Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
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...
commit 884a4c24c0d84258e208c8c88f68e8ac227b99a4 1 parent 8bcb567
@mikewest authored
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

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

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

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

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

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

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

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.
Something went wrong with that request. Please try again.