Web App Model
Suppose I have a sensitive JS object by which I can do critical stuff. My requirement is that I would like to wrap this object entirely such that no one can access it. Here is my pattern to wrap this object.
var proxy = (function (window){
// A private reference to my critical object (i.e. big apple)
var bigApple = window.bigApple;
// Delete this property so that no one else can access it
delete window.bigApple;
// Oooah, It's mine! I'm now eating it :)
// Public APIs exposed globally
return {
doStuffWithBigApple: function (){
// The Script element being executed now
var who = document.currentScript;
// Access control
if(isLegitimate(who)){
return bigApple.doStuff();
}
}
};
}) (window);
By this code I export a public literal object named proxy so that every one can access it.
What is that isLegitimate? It is an abstract function to be implemented which decides which script elements access to which methods of my big apple. The decision is made with regard to src attribute of the script element. (i.e. their domain)
Others use this public API like this:
proxy.doStuffWithBigApple();
Attack Model
In my web app there are placeholders for advertising such that external contents including JavaScript codes could be loaded and get executed. All of these external resources eagerly would want to access my big apple.
Note: Those are added after my scripts resulting in there is no access to the original window.bigApple.
My Question
Is there any circumventing way for my security model?
Critical edges:
Changing src attribute at parse-time. --- Not possible, because src can only be set once.
Adding script element at run-time --- No problem is raised
Your idea of creating a proxy is good imo, however, if you have access to ES6, why not looking into Proxy? I think it does what you want out-of-the-box.
The MDN provides good examples on how do traps for value validation in a setter, etc.
EDIT :
Possible trap I have imagined :
document.currentScript is not supported in IE. So if you care about it and decide to polyfill it/use a pre-exisiting polyfill, make sure it is secure. Or it could be used to modify on the fly the external script url returned by document.currentScript and skew the proxy. I don't know if this could happen in real life tho.
This way for protecting JavaScript objects has a very significant issue which should be addressed, otherwise this way will not work properly.
MDN noted on this API that:
It's important to note that this will not reference the <script> element if the code in the script is being called as a callback or event handler; it will only reference the element while it's initially being processed.
Thus, any call to proxy.doStuffWithBigApple(); inside callbacks and event handlers might lead to misbehaving of your framework.
Related
I'm wondering which of the following would be the best way to pass server data and use it in a function, especially if the function is to be used by a component
Method 1
function doSomething(elm, serverTime) {
// Do something
}
<script>
doSomething('foo', '<% php server time %>');
</script>
vs
Method 2
<div id="foo" data-server-time="<% php server time %>"></div>
function doSomething(foo) {
var serverTime = getElementById("server-time").dataset.servertime;
// Do something
}
<script>
doSomething('foo');
</script>
Method 3
Other suggestions?
Would like to do something like the following but not sure how?
document.getElementById("foo").doSomething() ?
For me, case 1 would be better.
code would have less coupling
code would not use global vars (document.getElementById)
you could reuse your function in other places that do not have DOM, like in the server.
I would argue in this case the 1st is better in this simple example because sever time isn't really attached to any specific div element.
Just make sure no matter what you do that there are no XSS security holes.
You are at a crossroads looking for common practice, to which one isn't more prevalent over another. Any great sage may tell you, which you choose isn't as important as making the same choice again; that is, be consistent.
Depending on the type of information, I would either pass it in the:
HTTP header (e.g., via HTTP Cookie)
Querystring (if redirection is used)
External JSON file (e.g., server.json), loaded via JS
Embedded JSON object (e.g., window.SERVER = {'server_time': <%php ...%>};)
In your case, keeping it closer to the JavaScript makes more sense and is easier to maintain, if the JS is the main place you're working. Therefore, Method 1 is both cleaner and easier to make changes in the future. Method 2, would require sifting through the HTML and making sure you are modifying the correct line.
Though, I'm somewhat partial to keeping server data as an external JSON, or embedded JSON object. So if you needed to track other server data/metadata, it's easy to add to it.
I would argue that all of them are the same and depending on your coding manner, they woulh have the same performance performand.
Let's not forget that nowadays, the most common way is to attach event listeners to elements (jQuery, Angular and .., use heavily event listeners).
I want to create a class called NMLDocument which inherits from Document but has some additional properties.
I've tried this code:
NMLDocument.prototype = Object.create(Document.prototype);
But the browser throws the following error:
Ignoring get or set of property that has [LenientThis] because the "this" object is incorrect.
Is there any way around? (I don't want to include all the properties separately)
What you try to achieve probably isn't possible since internal types like Document don't have to behave like normal JS objects (usually, Document won't because of security reasons).
If you want to simulate a browser, you can try envjs which is a pretty complete implementation of a browser in pure JavaScript.
If you need a real browser, try phantomjs. That's a WebKit-based browser which is controlled by JavaScript or CoffeeScript. It offers many nice APIs on the controlling side (like listeners for resource loading).
If you want to use XULRunner, try to write a wrapper or overwrite specific parts of Document.
I am trying to mock a very simple browser environment that mimics how browsers react to user's change in location variable. As far as I know, users can alter
self.location
location
document.location
window.location
one of those to navigate the current window by either
assigning a string of url directly onto the variable (e.g. self.location = 'http://www.google.com')
or assigning a string onto href inside the location object (e.g. self.location.href = 'http://www.google.com')
or maybe explicitly instantiating a location object.
So my real question is how can I instantiate the browser environment to allow users to assign location variable is anyway they wish and let me retrieve the location variable later on? Sorry if this sounds stupid, (I've never coded in javascript before) but in real world circumstances, do browsers convert string data into location objects through macro or does Javascript have some sort of "implicit constructor" mechanism that can automatically invoke the constructor of a class just by assigning a value?
(I am aware that there are dom libraries available, but I find them quite an overkill as I am only interested in the navigating mechanism.)
Well, there are actually several different answers, here.
First, don't anticipate being on the same page, when retrieving the location.
If a user changed it's value, then your page will change (and your in-memory application with it), so you'd need to do state management using some form of storage (online/offline) there.
In terms of how the object actually works, that isn't exactly JS (in all cases).
Long story short, there's JavaScript the language, and then there's the DOM/BOM.
Document-Object Model and Browser-Object Model.
The DOM is a set of functions/objects that let you interface with the HTML/CSS(as it applies to an element) of the page.
The BOM contains things that relate, not directly to the HTML, but to other parts of web functionality.
console.log( ); is a good example.
JS has no native console object or Console constructor. That's a part of the BOM that's added to a browser's environment, by the browser vendor (or third-party plugin), and is implementation a specific, with no real standard.
Same thing is true for URLs.
JS has a global object (in the BOM, it's called window), but it doesn't have a location natively.
So the implementation -- the "how", is hard to answer.
Some browsers might do it in legitimate JS, while others do it in C++ or C, and old IE even had ActiveX components.
That said, new JS engines do have magic get / set methods which can perform actions, while you set data.
Cutting-edge JS even has Proxies, which are sort of like that, but on steroids (these won't be widely supported everywhere for a few years)...
But older JS engines didn't have those features in place in the native language, so they went off into some other language and wired things up to behave in ways that wouldn't have been supported in JS itself, but were needed to fill out the BOM/DOM.
these days, using a .set might be all you need to grab an instance of a constructor.
So in terms of setting up your own object with similar functionality, you could RegEx parse (or iterate pieces of) the value handed to you.
On your object, you could have magic get/set methods assigned to a property name, where you could then, on a set, either modify all aspects of your current instance (based on value), or save a new instance to the var currently occupied by the old one, passing the new value to the constructor.
...but "where's the Location" constructor is a question that's not going to be answered in any simple way, without going browser by browser, version by version.
In a browser, window is effectively an alias for the global object so self === window.self and:
self.location
location
window.location
are all equivalent.
The location object is documented at MDN: window.location and at MSDN: The Window’s Location Object.
Users can set a location by entering it in the browser's address bar. You might also provide say an input element that they can type into, then a button that assigns the value to window.location (or uses any of the methods in the references provided).
do browsers convert string data into location objects through macro or does Javascript have some sort of "implicit constructor" mechanism that can automatically invoke the constructor of a class just by assigning a value?
The window and location objects are host objects that are not required to have any constructor, they just "are". Even if they are implemented as instances with prototype inheritance, there's no specification requiring users to have access to the constructor.
A new window can be created using:
var newWindow = window.open(...);
which I suppose is like calling a constructor.
When a location object is assigned a new URL, it behaves per the documentation referenced. How that happens is an implementation detail that is not specified, so you can implement it any way you like as long as it behaves like it should. That is the general philosophy behind javascript.
What you're looking for here is a getter/setter pair.
var window = {
get location() {
return {
get href() { return "foo"; },
set href() { /* change stored location data */; },
get port() { return 80; },
set port() { /* change stored location data */; },
/* etc ... */
};
}
set location() {
// change stored location data
}
};
Does anyone know if its possible to prevent a JavaScript function from accessing the DOM?
More info:
I am trying to create a "Threading" object for JavaScript, e.g. use the Worker object, fall back on setTimeOut when not available. Obviously the worker can't access the DOM, I would like to keep this standard.
Even more info:
One possible, but ugly possible solution (that I figured out just now):
function test(document, window)
{
}
But Nothing prevents the dev to access the dom from another function he calls within this function though - and you'll have to list the world of arguments.
No, that's not really possible in a normal browser environment.
You might be able to replace stuff like document.getElementById before calling the function and restoring it afterwards though... But I'm sure there are ways to get around this.
You could execute the function in a Web Worker. There is no access to DOM from a Web Worker.
But really, what are you trying to achieve?
Since your goal is to enforce conventions rather than to completely sandbox the JavaScript, you could indeed use a function with window, document and other DOM interfaces shadowed locally and then eval the third-party script:
(function test(window, self, top, document) {
'use strict';
eval(untrustedCode);
}());
Of course they still could access the real global object, but at least not directly.
I am looking for ways to build a system where I do not need to load all source files in order to play the application. My past project had over 200 .js files (I am not kidding!) and it was really slow to do a page reload to test features you develop.
I looked into Dojo and I see how they have built a dynamic loader. Basically you just load a single core component, then everything else will be loaded when needed.
I am thinking about implementing a factory method in my application that allows me to construct new instances of objects in JavaScript:
var user = MyApp.create('MyApp.model.User');
instead of:
var user = new MyApp.model.User();
The reasoning why I'd like to ditch the new keyword is because the former approach allows me to dynamically load the component in a lazy-loaded fashion if it does not exist already. The factory method can just look if the target object is defined, and if it is not, it would load it.
The only problem I am facing with that is the fact IDEs no longer understand user is type of MyApp.model.User which is certainly not a good thing.
Is there a way to solve this dilemma? Can I somehow JsDoc that factory method?
If your factory method returns various types of objects, based on the argument, then you can't document the return value for the factory method itself (using #returns) in a way that IDEs can make sense of. At least I'm not aware of any way to do it.
But you can solve your problem, easily, by annotating the variable which holds the object, like this:
/**
* #type {MyApp.model.User}
*/
var user = MyApp.create('MyApp.model.User');
Of course, I don't know if your particular IDE can interpret this. Mine can (using Komodo).