Why? That's the first question you might be asking. If a context is "compromised" then it's already too late, so no point in worrying. Weeell, I'm in a situation where I'm passing sensitive information on foreign domains, and I simply can't let the yocals interfere/intercept/counterfeit.
"And what's the point anyways? You have to assume, that on the client browser, everything is PUBLIC information." NO! That's the whole point of this project. I WANT security. I want to break that paradigm everyone seems quite happy with. The only question I start with, is "is that possible?"
Some Background
"And what's the point anyways? You have to assume, that on the client browser, everything is PUBLIC information." NO! That's the whole point of this project. I WANT security. I want to break that paradigm everyone seems quite happy with. The only question I start with, is "is that possible?"
Some Background
Imports and Modules are going to be a part of the ECMAScript 6 specification, aka JavaScript 2.0. Maybe you've noticed that in a <script> element you can specify what type of javascript you have - that's because JavaScript really has evolved over the years and pre-1.5 JS is just like pre-1.5 Java. Well, eventually we'll think the same thing about pre-2.0 Javascript. But till then, we have to make due with 1.5, and just implement the 2.0 functionality we want ourselves.
Likely the most important thing that 2.0 allows for, are classes, imports, and modules. Imports and Modules have been implemented by Firefox for some time now - likely because the founder/caretaker of Javascript works at Mozilla. If you've created a Firefox plugin, you've seen the concept of modules and exports/imports. Basically, you specify which variables you'll be importing from a module that you're loading. The module is designed to run in it's own context - it's own "window" - and only sends to the loader's window the "var"s specified by the load (in FF, the module specifies the vars, but in JS2.0, the loader AND the module specify).
These features are what I set out to duplicate. On deciding what path to take, I examines the features of the different JS loader's I could find in the wild. In particular, an API called AMD seemed popular, as were the loader's which implemented it. This website was helpful : http://addyosmani.com/writing-modular-js/ . A more extensive list of options and features can be seen here : https://spreadsheets.google.com/ccc?key=0Aqln2akPWiMIdERkY3J2OXdOUVJDTkNSQ2ZsV3hoWVE&hl=en#gid=2
I wasn't immediately impressed with the idea of AMD, but after two days of reading about it, I understood why it was designed how it is. As flexible and robust as JS can be, it's hard to make a general case loader, but I think AMD is 'pretty good' as a standard. But I've no idea why one would want to use a 'standard' API call in this case (since no external callers), except just for the sake of it being a 'standard'. I have a specific use case, with three total goals in mind: security, small fingerprint, and non-blocking cross-domain loading, so no reason to use a standard for standard's sake. So I looked into some of the alternatives on the Google Spreadsheet linked above - all the ones less than 2kb minimized. After looking at the source code of each, I found that all of them 'did too much', and didn't really address all my (aforementioned) main concerns. Specifically, none that I found cared too much about security - - they focused on speed, convenience, features, and footprint. Which is great, but I could hack any of them into loading malicious code instead of the intended modules **. Which is bad.
** Note that I don't mean what you probably think I mean. "Of course they can be used to load in malicious code, they are LOADERS!", right?? What I mean is that when my script makes a call to load a script, anyone can "fake" that load and make my script (in my private, secure scope) run their own code, breaking that "security".
** Note that I don't mean what you probably think I mean. "Of course they can be used to load in malicious code, they are LOADERS!", right?? What I mean is that when my script makes a call to load a script, anyone can "fake" that load and make my script (in my private, secure scope) run their own code, breaking that "security".
So with that in mind, I set out to make my own importer which fit all my other needs (simply: small, non-blocking, asynchronous) but also was as tight as it got as far as security. I'm not really sure how "secure" I can make this, at this point. I'd love for it to be "impossible" for other scripts to access my information, but I suppose I could accept "very very difficult". Protecting functions and variables in your own JS file is easy, but how do you protect a second loaded JS file when the browser makes the load, the element, and the status, all public knowledge?
So lets think about this a bit.
Naive load: just a regular document.body.appendChild(myScriptElement). Your new JS loads and runs. But the problem is that it can't tell the difference between the loader JS and a stranger - there's no way to block access to functions and variables selectively. Anything can be overwritten or used by someone else. And you can't scope things internally either, because you'd be locking out the original script (loader) too.
So you have to leave things in the open, but you don't want anyone changing your functions. Idea: using an entry way (one function), attach all that is in the loaded JS's scope to the internal scope of the loader JS, then delete reference to yourself. This would give all the 2nd JS's assets to the protected scope of the 1st JS - which no external scope one can reference. Problem - this only works if you trust the that the first person through the "entry way" is the loader. If the first person through the gate is a stranger - then you've just given away everything to that stranger instead of the loader. How can we guarantee that the first person to call the gateway function is the loader?
The only guarantee the browser provide is that the element's "onload" (or "onreadystatechange") functions will be called before the ones that were attached using attachEvent/addEventListener. "Ok, great, so just make your callback the element's attribute function"? Well no, because if we assume malicious code is on the page, then it could just replace you as the attribute callback function. All malicious code needs is a reference to the element. In fact, even if you placed some checks, malicious code could store your callback, replace it, then when the event has occurred, it would replace the loaded module with a malicious module, reattach your function, then dispatch your callback. A whole list of nasty things could happen if malicious code got reference to your callback function. The summary being - you can't allow anyone else reference to either your element OR your callback function. But HOW??
That's part 2...
No comments:
Post a Comment