Переглянути джерело

Audit innerHTML usage and sanitize inputs.

Jason Grout 6 роки тому
батько
коміт
6283e6b97b

+ 1 - 1
packages/apputils/src/clientsession.tsx

@@ -985,7 +985,7 @@ namespace Private {
     // Create the dialog body.
     let body = document.createElement('div');
     let text = document.createElement('label');
-    text.innerHTML = `Select kernel for: "${session.name}"`;
+    text.textContent = `Select kernel for: "${session.name}"`;
     body.appendChild(text);
 
     let options = getKernelSearch(session);

+ 11 - 4
packages/javascript-extension/src/index.ts

@@ -30,10 +30,17 @@ export class ExperimentalRenderedJavascript extends RenderedJavaScript {
     };
     if (!model.trusted) {
       // If output is not trusted or if arbitrary Javascript execution is not enabled, render an informative error message
-      this.node.innerHTML = `<pre>Are you sure that you want to run arbitrary Javascript within your JupyterLab session?</pre>
-      <button>Run</button>`;
-      this.node.querySelector('button').onclick = event => {
-        this.node.innerHTML = '';
+      const pre = document.createElement('pre');
+      pre.textContent =
+        'Are you sure that you want to run arbitrary Javascript within your JupyterLab session?';
+      const button = document.createElement('button');
+      button.textContent = 'Run';
+
+      this.node.appendChild(pre);
+      this.node.appendChild(button);
+
+      button.onclick = event => {
+        this.node.textContent = '';
         void renderJavascript();
       };
       return Promise.resolve();

+ 10 - 3
packages/mainmenu-extension/src/index.ts

@@ -358,9 +358,16 @@ export function createFileMenu(
             .then(result => {
               if (result.ok) {
                 // Close this window if the shutdown request has been successful
-                let body = document.createElement('div');
-                body.innerHTML = `<p>You have shut down the Jupyter server. You can now close this tab.</p>
-                  <p>To use JupyterLab again, you will need to relaunch it.</p>`;
+                const body = document.createElement('div');
+                const p1 = document.createElement('p');
+                p1.textContent =
+                  'You have shut down the Jupyter server. You can now close this tab.';
+                const p2 = document.createElement('p');
+                p2.textContent =
+                  'To use JupyterLab again, you will need to relaunch it.';
+
+                body.appendChild(p1);
+                body.appendChild(p2);
                 void showDialog({
                   title: 'Server stopped',
                   body: new Widget({ node: body }),

+ 4 - 1
packages/outputarea/src/widget.ts

@@ -386,7 +386,10 @@ export class OutputArea extends Widget {
       }
       output.renderModel(model).catch(error => {
         // Manually append error message to output
-        output.node.innerHTML = `<pre>Javascript Error: ${error.message}</pre>`;
+        const pre = document.createElement('p');
+        pre.textContent = `Javascript Error: ${error.message}`;
+        output.node.appendChild(pre);
+
         // Remove mime-type-specific CSS classes
         output.node.className = 'p-Widget jp-RenderedText';
         output.node.setAttribute(

+ 13 - 4
packages/rendermime/src/renderers.ts

@@ -468,13 +468,17 @@ export namespace renderSVG {
  */
 export function renderText(options: renderText.IRenderOptions): Promise<void> {
   // Unpack the options.
-  let { host, source } = options;
+  const { host, sanitizer, source } = options;
 
   // Create the HTML content.
-  let content = Private.ansiSpan(source);
+  const content = sanitizer.sanitize(Private.ansiSpan(source), {
+    allowedTags: ['span']
+  });
 
-  // Set the inner HTML for the host node.
-  host.innerHTML = `<pre>${content}</pre>`;
+  // Set the sanitized content for the host node.
+  const pre = document.createElement('pre');
+  pre.innerHTML = content;
+  host.appendChild(pre);
 
   // Return the rendered promise.
   return Promise.resolve(undefined);
@@ -493,6 +497,11 @@ export namespace renderText {
      */
     host: HTMLElement;
 
+    /**
+     * The html sanitizer for untrusted source.
+     */
+    sanitizer: ISanitizer;
+
     /**
      * The source text to render.
      */

+ 2 - 0
packages/rendermime/src/widgets.ts

@@ -354,6 +354,7 @@ export class RenderedText extends RenderedCommon {
   render(model: IRenderMime.IMimeModel): Promise<void> {
     return renderers.renderText({
       host: this.node,
+      sanitizer: this.sanitizer,
       source: String(model.data[this.mimeType])
     });
   }
@@ -383,6 +384,7 @@ export class RenderedJavaScript extends RenderedCommon {
   render(model: IRenderMime.IMimeModel): Promise<void> {
     return renderers.renderText({
       host: this.node,
+      sanitizer: this.sanitizer,
       source: 'JavaScript output is disabled in JupyterLab'
     });
   }

+ 1 - 1
packages/vega5-extension/src/index.ts

@@ -84,7 +84,7 @@ export class RenderedVega extends Widget implements IRenderMime.IRenderer {
     const el = document.createElement('div');
 
     // clear the output before attaching a chart
-    this.node.innerHTML = '';
+    this.node.textContent = '';
     this.node.appendChild(el);
 
     this._result = await vega.default(el, spec, {