From b292e4233e4da33f6fd3ac2a4a7d0b4dd6725ce4 Mon Sep 17 00:00:00 2001 From: Karl Burtram Date: Fri, 18 Feb 2022 15:39:44 -0800 Subject: [PATCH] Port - Restrict which sites out webview iframe can frame (#18495) (#18497) * protocol handler - normalize paths * use `extUri` for normalizing paths * :lipstick; * Add content security policy to top level webview This change hardens our webviews by adding a fairly restrictive csp to them. This CSP should only apply to the outer webview iframe, not to the inner iframe which is controlled by extensions Co-authored-by: Benjamin Pasero Co-authored-by: Matt Bierner Co-authored-by: Benjamin Pasero Co-authored-by: Matt Bierner --- .../electron-main/protocolMainService.ts | 34 ++++++++++++------- .../contrib/webview/browser/pre/index.html | 2 ++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/protocol/electron-main/protocolMainService.ts b/src/vs/platform/protocol/electron-main/protocolMainService.ts index e752ac1c36..96d9de9843 100644 --- a/src/vs/platform/protocol/electron-main/protocolMainService.ts +++ b/src/vs/platform/protocol/electron-main/protocolMainService.ts @@ -8,7 +8,7 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle' import { TernarySearchTree } from 'vs/base/common/map'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { isLinux } from 'vs/base/common/platform'; -import { extname } from 'vs/base/common/resources'; +import { extname, normalizePath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -84,33 +84,43 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ //#region vscode-file:// private handleResourceRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback): void { - const uri = URI.parse(request.url); - - // Restore the `vscode-file` URI to a `file` URI so that we can - // ensure the root is valid and properly tell Chrome where the - // resource is at. - const fileUri = FileAccess.asFileUri(uri); + const uri = this.requestToFileUri(request); // first check by validRoots - if (this.validRoots.findSubstr(fileUri)) { + if (this.validRoots.findSubstr(uri)) { return callback({ - path: fileUri.fsPath + path: uri.fsPath }); } // then check by validExtensions - if (this.validExtensions.has(extname(fileUri))) { + if (this.validExtensions.has(extname(uri))) { return callback({ - path: fileUri.fsPath + path: uri.fsPath }); } // finally block to load the resource - this.logService.error(`${Schemas.vscodeFileResource}: Refused to load resource ${fileUri.fsPath} from ${Schemas.vscodeFileResource}: protocol (original URL: ${request.url})`); + this.logService.error(`${Schemas.vscodeFileResource}: Refused to load resource ${uri.fsPath} from ${Schemas.vscodeFileResource}: protocol (original URL: ${request.url})`); return callback({ error: -3 /* ABORTED */ }); } + private requestToFileUri(request: Electron.ProtocolRequest): URI { + + // 1.) Use `URI.parse()` util from us to convert the raw + // URL into our URI. + const requestUri = URI.parse(request.url); + + // 2.) Use `FileAccess.asFileUri` to convert back from a + // `vscode-file:` URI to a `file:` URI. + const unnormalizedFileUri = FileAccess.asFileUri(requestUri); + + // 3.) Strip anything from the URI that could result in + // relative paths (such as "..") by using `normalize` + return normalizePath(unnormalizedFileUri); + } + //#endregion //#region IPC Object URLs diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index a5d2361c1c..58e58502dc 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -4,6 +4,8 @@ + +