11

I'm building a website where users, among other things, can add embeds (YouTube, Google Forms, Airtable...) and show those embeds to other people. Embeds are snippets of HTML that can include <script> and <iframe>-tags.

It is important that the embedded content can't take over the parent page or make requests with the session cookie of the parent site.

One option that originally seemed fruitful would be to not have the allow-same-origin in the sandbox attribute of the <iframe>. But many embeds don't work if you remove that (YouTube for example).

As recommended by WhatWG, sites like Codepen and JSBin host such user-defined content on a different domain to ensure the iframe can't use the cookie from the top-level domain. However, they also include the allow-same-origin in the sandbox-attribute, which is a bit confusing to me.

  • What security measures do I need to implement to securely host and display these user-defined embeds?
  • Beyond just hosting the code on a different domain what other security measures are Codepen/JSBin implementing to safely host and display the user-defined HTML?
  • And can I use the srcdoc-attribute instead of hosting the embed HTML on a different domain? (accepting that IE would not be supported)

Note: OEmbed, Embedly and Iframely aren't options for me at this point, since I need more generic embeds than those allow.

1
  • 1
    You'll want to write those tags yourself. So parse whatever URL or input you get from the user, and extract only the bit you need. (For youtube it would be the specific part of the "ShareURL" that defines the UID of the video...) Output the entire embed code yourself adding the relevant bit. (and sanitize that bit) You'll only be storing the part you need.
    – pcalkins
    Aug 23 at 20:01
18

If the content you're embedding will contain untrusted scripts, it must either be loaded in an iframe from an untrusted domain, or be loaded from srcdoc in a sandboxed iframe with the allow-same-origin flag not set.

Content embedded in an iframe using the srcdoc attribute is normally considered same-origin with the parent page, so it is not safe to embed untrusted scripts that way unless you use the sandbox attribute without the allow-same-origin flag to ensure that the content is treated as if it were cross-origin.

In contrast, content embedded in an iframe via an untrusted domain is not treated as same-origin with your domain, even if you specify allow-same-origin in the sandbox attribute. This is because allow-same-origin only allows the embedded content to be treated as same-origin with it's own origin. It does not grant any extra permissions over and above what an iframe with no sandbox attribute would allow, so it is safe to use in this context. The WHATWG HTML spec explains:

The sandboxed origin browsing context flag

This flag forces content into a unique origin, thus preventing it from accessing other content from the same origin.

This flag also prevents script from reading from or writing to the document.cookie IDL attribute, and blocks access to localStorage.

This is also why most embeds won't work when sandboxed without allow-same-origin. Omitting that attribute causes the embedded content to treat its own domain as cross-origin (so for example, an embedded YouTube video wouldn't be able to communicate with YouTube except through cross-origin requests).

Note further that untrusted content should never be served directly from your primary domain, regardless of what sandbox attributes you use on your iframes, as users could be tricked into navigating to those pages directly, bypassing the sandbox attributes.

Beyond ensuring untrusted content is served from an untrusted domain entirely separate from your main domain (i.e. preferably not a subdomain of your primary domain), I would also advise the following:

  • Take measures to ensure user-embedded content is clearly identifiable as such to users of your site. Embedded content can be a vector for phishing if it can easily be mistaken for part of your site.
  • If feasible, consider using unique-per-user subdomains of the untrusted domain to ensure embedded content from one of your site's users cannot easily interfere with embedded content from another user.
    • You can further enhance this per-user isolation by requesting that your untrusted domain be added to the public suffix list.
6
  • 1
    Can you use nested iframes, the outer one with sandbox and no allow-same-origin and the inner one having no such restriction, to get around the problem with blocking (for example) youtube from making same-origin requests to itself? Aug 24 at 16:21
  • 1
    @R..GitHubSTOPHELPINGICE No, I checked. The sandbox applies recursively, which makes sense for most sandboxed permissions but is a bit unfortunate for this particular use case.
    – Ajedi32
    Aug 24 at 16:26
  • 1
    That's a shame. I was hoping it would reply "relative to the context it's in", which would be just as good from a standpoint of preventing access to the containing site context, without disrupting anything internal. Aug 24 at 16:35
  • 1
    Putting each user embedded content into a separate subdomain puts the code in different origins but I don't see what do we gain from this in practice. Since users have no server-side code, there is no cookie to steal. A user could do a GET to read another user's content but is this a security risk? Can you expand on point 2? Thank you. Aug 24 at 21:40
  • 1
    @MargaretBloom Cookies can be set by JavaScript. It all depends on what the users are doing in their embeds. If it's just static HTML it's probably fine, but what if they're storing important data in cookies or local storage, for example? Won't affect the main site obviously, but it's still a potential issue.
    – Ajedi32
    Aug 24 at 21:58
4

There might be many ways of achieving this, but I would most likely start with heavy handed input sanitization on server-side.

For example:

<iframe width="420" height="315"
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ">
</iframe>

I would most likely write code that extracts the dQw4w9WgXcQ portion of the input and injects it into a known-good template. I would also make sure that the video key is restricted to ONLY numbers and letters as YouTube UIDs do not contain special characters.

The same could most likely be applied to Google Forms and Airtables.

3
  • 1
    YouTube UIDs can have certain special characters. Based on personal recollection, verification with a page I control that includes many YouTube iframes and a quick search which verifies this (but only unofficially), it looks like the character set is A-Z, a-z, 0-9 plus - and _ Aug 23 at 22:14
  • 1
    That would make sense, @manassehkatz-Moving2Codidact, as YouTube uses Base64 for its IDs.
    – TRiG
    Aug 24 at 14:29
  • - and _ are certainly two of the "safest" characters: \ / & < > ' " % * ? : ; . = + ! $ ` all have issues with one or another operating system or with use in URLs, etc. Aug 24 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.