4

I need to be allow content from our site to be embeded in other users web sites. The conent will be chargeable so I need to keep it secure but one of the requirements is that the subscribing web site only needs to drop some javascript into their page.

It looks like the only way to secure our content is to check the url of the page hosting our javascript matches the subscribing site. Is there any other way to do this given that we don't know the client browsers who will be hitting the subscribing sites?

Is the best way to do this to supply a javascript include file that populates a known page element when the page loads? I'm thinking of using jquery so the include file would first call in jquery (checking if it's already loaded and using some sort of namespace protection), then on page load populate the given element.

I'd like to include a stylesheet as well if possible to style the element but I'm not sure if I can load this along with the javascript.

Does this sound like a reasonable approach? Is there anything else I should consider?

Thanks in advance,

Mike

Mike
  • 857
  • 1
  • 16
  • 29

2 Answers2

5

It looks like the only way to secure our content is to check the url of the page hosting our javascript matches the subscribing site.

Ah, but in client-side or server-side code?

They both have their disadvantages. Doing it with server-side code is unreliable because some browsers won't be passing a Referer header at all, and if you want to stop caches keeping a copy of the script, preventing the Referer-check from taking place, you have to serve with nocache or Vary: Referer headers, which would harm performance.

On the other hand, with client-side checks in the script you return, you can't be sure your environment you're running in hasn't been sabotaged. For example if your inclusion script tag was like:

<script src="http://include.example.com/includescript?myid=123"></script>

and your server-side script looked up 123 as being the ID for a customer using the domain customersite.foo, it might respond with the script:

if (location.host.slice(-16)==='customersite.foo') {
    // main body of script
} else {
    alert('Sorry, this site is not licensed to include content from example.com');
}

Which seems simple enough, except that the including site might have replaced String.prototype.slice with a function that always returned customersite.foo. Or various other functions used in the body of the script might be suspect.

Including a <script> from another security context cuts both ways: the including-site has to trust the source-site not to do anything bad in their security context like steal end-user passwords or replace the page with a big goatse; but equally, the source-site's code is only a guest in the including-site's potentially-maliciously-customised security context. So a measure of trust must exist between the two parties wherever one site includes script from another; the domain-checking will never be a 100% foolproof security mechanism.

I'd like to include a stylesheet as well if possible to style the element but I'm not sure if I can load this along with the javascript.

You can certainly add stylesheet elements to the document's head element, but you would need some strong namespacing to ensure it didn't interfere with other page styles. You might prefer to use inline styles for simplicity and to avoid specificity-interference from the page's main style sheet.

It depends really whether you want your generated content to be part of the host page (in which case you might prefer to let the including site deal with what styles they wanted for it themselves), or whether you want it to stand alone, unaffected by context (in which case you would probably be better off putting your content in an <iframe> with its own styles).

I'm thinking of using jquery so the include file would first call in jquery

I would try to avoid pulling jQuery into the host page. Even with noconflict there are ways it can conflict with other scripts that are not expecting it to be present, especially complex scripts like other frameworks. Running two frameworks on the same page is a recipe for weird errors.

(If you took the <iframe> route, on the other hand, you get your own scripting context to play with, so it wouldn't be a problem there.)

bobince
  • 528,062
  • 107
  • 651
  • 834
  • Thanks for the information, that's given me plenty to think about and clarified a few things. – Mike Feb 17 '10 at 11:10
  • @bobince Is it possible for the including-site to replace the "location.host" function as well as "String.slice"? – Murat Derya Özen Dec 24 '11 at 21:00
  • 1
    @Murat: yes, though there are browser quirks around what exactly you can do with `location`. In IE you can replace the whole `location` object. In Firefox you can `Object.defineProperty` a replacement property on the existing `location` object. – bobince Dec 24 '11 at 21:41
  • @bobince Then this means that there is no way to provide a 100% secure widget, since its possible that the Referer header might be missing/spoofed and/or the javascript functions might be overriden in a malicious way. What can a widget provider do in case the provider does not trust all sites benefiting from the widget? And following that, I just wonder if you would be interested in [this question](http://stackoverflow.com/questions/8615467/how-does-linkedin-know-or-keep-track-of-where-i-embedded-its-widget) of mine. :) – Murat Derya Özen Dec 24 '11 at 23:02
  • 1
    @Murat: correct, there is no 100%. However the simplest approach of just logging referrers (with no attempt to break cache) is often ‘good enough’: if you have a site using the script without authorisation, chances are that site's operator is going to have some users who don't have the file in cache and who don't block/spoof Referer. If you see a disproportionate number of accesses with bad Referer from a particular licensee, that would then be grounds for investigation and potential revocation of their API key. – bobince Dec 25 '11 at 12:49
  • @bobince - Thanks bobince, your comments helped. I'd like to mark your answer as the accepted one if you can just copy n paste the relevant parts of your answer (along with these comments) on [my question](http://stackoverflow.com/questions/8615467/how-does-linkedin-know-or-keep-track-of-where-i-embedded-its-widget) because your answer has given the deepest insight to me so far. – Murat Derya Özen Dec 25 '11 at 13:15
2

You can store the users domain, and a key within your local database. That, or the key can be an encrypted version of the domain to keep you from having to do a database lookup. Either one of these can determine whether you should respond to the request or not.

If the request is valid, you can send your data back out to the user. This data can indeed load in jQuery and and additional CSS reference.

Related:

  1. How to load up CSS files using Javascript?
  2. check if jquery has been loaded, then load it if false
Community
  • 1
  • 1
Sampson
  • 265,109
  • 74
  • 539
  • 565
  • 1
    +1. As a side note, I would always be cautious about loading a script into my page from a third party site, especially if it's not over `https`. Amongst not being keen on allowing a third party access to my page's DOM, it opens up for potential MITM attacks. Most widget provider should use iframes to offer security to all parties involved. Iframes can be transparent and you could even offer a `get` parameter that provides the location of the css file. – Andy E Feb 16 '10 at 16:56