Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Sandboxing: Adding disclaimers about `postMessage` + cleanup. #263

Merged
merged 4 commits into from

3 participants

@mikewest
Collaborator
  1. postMessage can be dangerous if you're not careful; the demo code in
    this article didn't make that clear. This patch adds some comments to
    ensure that the important points are clearly highlighted, and adjusts
    the demo code itself to actually do rudimentary validation of sources
    rather than blindly executing code in response to a message event.

  2. Cleanup in the formatting of some code at the bottom of the article.
    One space too many, ah well.

@mikewest mikewest Sandboxing: Adding disclaimers about `postMessage` + cleanup.
1.  `postMessage` can be dangerous if you're not careful; the demo code in
    this article didn't make that clear. This patch adds some comments to
    ensure that the important points are clearly highlighted, and adjusts
    the demo code itself to actually do rudimentary validation of sources
    rather than blindly executing code in response to a message event.

2.  Cleanup in the formatting of some code at the bottom of the article.
    One space too many, ah well.
884a4c2
@mikewest
Collaborator

@abarth: Would you mind taking a look at this change as well? If there's more I can do to ensure that the demo code isn't leading folks down the wrong path, I'm happy to make more changes.

@abarth

The source is actually the DOMWindow of the frame, so you'll need to write something like:

if (e.origin === "null" && e.source === frame.contentWindow)

Collaborator

Ugh. facepalm. Yes. Thanks. :)

@abarth

Consider using window.location.origin

Similarly, you'll need unsandboxedFrame.contentWindow (assuming unsandboxedFrame points to the element rather than the frame's DOMWindow).

Collaborator

window.location.origin doesn't seem to work in Gecko. This is pretty ugly, but was the closest thing to cross-platform I could come up with.

Yes, I think it's only implemented in WebKit. What you have now probably works fine.

I wonder if we should write a patch for Firefox that implements location.origin. It's part of the URL spec: http://url.spec.whatwg.org/#dom-url-origin

Collaborator

I was looking for a bug yesterday, filed https://bugzilla.mozilla.org/show_bug.cgi?id=828261 today. Might be a nice way of getting my feet wet in Firefox. :)

@abarth

I added some comments to the patch.

@mikewest
Collaborator

Thanks Adam, much appreciated.

@cwilso
Owner

If this is ready, I'll pull and deploy it tomorrow.

@mikewest
Collaborator

I'd appreciate you pulling it, Chris. I think it's good to go, and it's certainly better than what's out there now. :)

@cwilso cwilso merged commit 7e0c266 into html5rocks:master
@cwilso
Owner

Deployed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 8, 2013
  1. @mikewest

    Sandboxing: Adding disclaimers about `postMessage` + cleanup.

    mikewest authored
    1.  `postMessage` can be dangerous if you're not careful; the demo code in
        this article didn't make that clear. This patch adds some comments to
        ensure that the important points are clearly highlighted, and adjusts
        the demo code itself to actually do rudimentary validation of sources
        rather than blindly executing code in response to a message event.
    
    2.  Cleanup in the formatting of some code at the bottom of the article.
        One space too many, ah well.
  2. @mikewest

    @abarth's feedback.

    mikewest authored
    * e.origin === sandboxedFrame.contentWindow
  3. @mikewest

    Update content/tutorials/security/sandboxed-iframes/en/index.html

    mikewest authored
    e.origin === frame.contentWindow.
  4. @mikewest

    Update content/tutorials/security/sandboxed-iframes/en/index.markdown

    mikewest authored
    e.source === frame.contentWindow
This page is out of date. Refresh to see the latest.
View
14 content/tutorials/security/sandboxed-iframes/en/index.html
@@ -278,7 +278,13 @@ <h3 id="safely-sandboxing-eval">Safely sandboxing <code>eval()</code></h3>
<pre class="prettyprint"><code>window.addEventListener('message',
function (e) {
- alert('Result: ' + e.data);
+ // Sandboxed iframes which lack the 'allow-same-origin'
+ // header have "null" rather than a valid origin. This means you still
+ // have to be careful about accepting data via the messaging API you
+ // create. Check that source, and validate those inputs!
+ var frame = document.getElementById('sandboxed');
+ if (e.origin === "null" &amp;&amp; e.source === frame.contentWindow)
+ alert('Result: ' + e.data);
});
</code></pre>
@@ -289,6 +295,10 @@ <h3 id="safely-sandboxing-eval">Safely sandboxing <code>eval()</code></h3>
<pre class="prettyprint"><code>function evaluate() {
var frame = document.getElementById('sandboxed');
var code = document.getElementById('code').value;
+ // Note that we're sending the message to "*", rather than some specific
+ // origin. Sandboxed iframes which lack the 'allow-same-origin' header
+ // don't have an origin which you can target: you'll have to send to any
+ // origin, which might alow some esoteric attacks. Validate your output!
frame.contentWindow.postMessage(code, '*');
}
@@ -318,7 +328,7 @@ <h3 id="safely-sandboxing-eval">Safely sandboxing <code>eval()</code></h3>
<p>Note, however, that you need to be very careful when dealing with framed content
that comes from the same origin as the parent. If a page on
<code>https://example.com/</code> frames another page on the same origin with a sandbox
-that includes both the <strong>allow-same-origin **and **allow-scripts</strong> flags, then
+that includes both the <strong><code>allow-same-origin</code></strong> and <strong><code>allow-scripts</code></strong> flags, then
the framed page can reach up into the parent, and remove the sandbox attribute
entirely.</p>
View
14 content/tutorials/security/sandboxed-iframes/en/index.markdown
@@ -254,7 +254,13 @@ would do something less annoying:
window.addEventListener('message',
function (e) {
- alert('Result: ' + e.data);
+ // Sandboxed iframes which lack the 'allow-same-origin'
+ // header have "null" rather than a valid origin. This means you still
+ // have to be careful about accepting data via the messaging API you
+ // create. Check that source, and validate those inputs!
+ var frame = document.getElementById('sandboxed');
+ if (e.origin === "null" &amp;&amp; e.source === frame.contentWindow)
+ alert('Result: ' + e.data);
});
Next, we'll hook up an event handler to clicks on the `button`. When the user
@@ -264,6 +270,10 @@ frame for execution:
function evaluate() {
var frame = document.getElementById('sandboxed');
var code = document.getElementById('code').value;
+ // Note that we're sending the message to "*", rather than some specific
+ // origin. Sandboxed iframes which lack the 'allow-same-origin' header
+ // don't have an origin which you can target: you'll have to send to any
+ // origin, which might alow some esoteric attacks. Validate your output!
frame.contentWindow.postMessage(code, '*');
}
@@ -290,7 +300,7 @@ ensuring that each module is well-fed with only the information it requires.
Note, however, that you need to be very careful when dealing with framed content
that comes from the same origin as the parent. If a page on
`https://example.com/` frames another page on the same origin with a sandbox
-that includes both the **allow-same-origin **and **allow-scripts** flags, then
+that includes both the **allow-same-origin** and **allow-scripts** flags, then
the framed page can reach up into the parent, and remove the sandbox attribute
entirely.
View
2  static/demos/evalbox/frame.html
@@ -11,7 +11,7 @@
} catch (e) {
result = 'eval() threw an exception.';
}
- mainWindow.postMessage(result, event.origin);
+ mainWindow.postMessage(result, e.origin);
});
</script>
</head>
View
17 static/demos/evalbox/index.html
@@ -61,6 +61,10 @@
function evaluate(frame) {
var code = document.getElementById('code').value;
+ // Note that we're sending the message to "*", rather than some specific
+ // origin. Sandboxed iframes which lack the 'allow-same-origin' header
+ // don't have an origin which you can target: you'll have to send to any
+ // origin, which might alow some esoteric attacks. Validate your output!
frame.contentWindow.postMessage(code, '*');
}
@@ -73,7 +77,18 @@
// Listen for response messages from the frames.
window.addEventListener('message', function (e) {
- alert('Result: ' + e.data);
+ // Normally, you should verify that the origin of the message's sender
+ // was the origin and source you expected. This is easily done for the
+ // unsandboxed frame. The sandboxed frame, on the other hand is more
+ // difficult. Sandboxed iframes which lack the 'allow-same-origin'
+ // header have "null" rather than a valid origin. This means you still
+ // have to be careful about accepting data via the messaging API you
+ // create. Check that source, and validate those inputs!
+ if ((e.origin === "null" && e.source === sandboxedFrame.contentWindow)
+ || (e.origin === (window.location.protocol + "//" + window.location.host)
+ && e.source === unsandboxedFrame.contentWindow)) {
+ alert('Result: ' + e.data);
+ }
});
</script>
</body>
Something went wrong with that request. Please try again.