Browse files

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.
  • Loading branch information...
1 parent 8bcb567 commit 884a4c24c0d84258e208c8c88f68e8ac227b99a4 @mikewest committed Jan 8, 2013
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)
@abarth
abarth added a note Jan 8, 2013

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)

@mikewest
Owner
mikewest added a note Jan 8, 2013

Ugh. facepalm. Yes. Thanks. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ 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)
@abarth
abarth added a note Jan 8, 2013

ditto

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ 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
16 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,17 @@
// 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)
+ || (e.origin === (window.location.protocol + "//" + window.location.host) && e.source === unsandboxedFrame) {
@abarth
abarth added a note Jan 8, 2013

Consider using window.location.origin

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

@mikewest
Owner
mikewest added a note Jan 8, 2013

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.

@abarth
abarth added a note Jan 8, 2013

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

@mikewest
Owner
mikewest added a note Jan 9, 2013

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. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ alert('Result: ' + e.data);
+ }
});
</script>
</body>

0 comments on commit 884a4c2

Please sign in to comment.