avoid Javascript variable modification from browser console - javascript

I have a problem. I have defined some global variables and namespaced it into an object called "app".
Example:
window.app : {
foo : null,
bar : null,
}
Well, the idea is that I want to be able to modify those variables from any module by calling app.foo = "baz" or app.bar = "baz", but I don't want the user to be able to modify those variables from the browser console (element inspector).
Is it possible?
PD: Well, I have a Backbone.js collection which is sinchronized with the server. I don't want the user to be able to modify that collection with the console

No. The browser is the user's domain. They have the possibility to modify your scripts and inject their own functionality in various ways (through the console or browser plug-ins). That's one of the reasons why you should never blindly trust user input on the server side.
They could even manually forge a complete request, tricking your server into thinking that your JavaScript code made that request.
If you want these values to be secure, you need to keep them on the server. You can send them to the client, of course, as long as you keep a possibility to validate the values against those on the server.

The only way to make the variables not (easily) modifiable by a user is to remove them from global scope - something like
!function() {
foo = null;
bar = null;
}()
You'll need to redesign the way your modules interact with each other to accomplish this. An MVC Framework like Angular.js will help.
You should never rely on this as a security mechanism, though - the browser is fully in the user's control.

Still for them who are searching solution to this problem, use const modifier while assigning variable instead of var. Now try to change value of variable from browser console. It will throw error Uncaught TypeError: Assignment to constant variable that will prevent your data from being modified.

A possible way to avoid to (easily) modify javascript variables from the browser console is to either use the get operator (ECMAScript 5) or a getter-function.
To make it possible to define "private" variables, an anonymous function defines the variables in the local scope, so that it is not globally available. (as mentioned in joews' answer)
As mentioned before, this does not make it impossible to manipulate the variables.
Via get operator:
window.app = (function () {
var _foo = 123; // private variable
return {
get foo () { return _foo; }
};
}());
// --- accessing app from the console ---
// app.foo is readable from console, but not modifiable
console.log(app.foo);
app.foo = 234;
console.log(app.foo); // 123
// However, app.foo can still be modified via Object.defineProperty or
// removed with the delete operator
Via getter-function (older browsers, e.g IE < 9):
window.app = (function () {
var _foo = 123; // private variable
return {
foo: function() { return _foo; }
};
}());
// --- accessing app from the console ---
console.log(app.foo()); // 123
// However, the foo function can still be overwritten.
// But at least, the internal _foo variable is unaffected.
app.foo = function () { return 234; }

Related

interacting with javascript through the chrome console [duplicate]

This question already has answers here:
Console access to Javascript variables local to the $(document).ready function
(8 answers)
Closed 6 years ago.
I'm using a shopping cart api to build an ecommerce website. The creators made an sdk and then you have to make your own .js file for some other functions.
While debugging I would insert a console.log(etc..) anywhere in my .js file so that I could debug object options and etc..
But I would like to be able to use the sdk as a live tool, so instead of having to edit my .js file with new console.log() lines, I'd rather just be able to type object.color_code and have the console output that string for the object color code. At the moment though it just gives me uncaught reference error, object is not defined.
I think this is because my custom .js file has all of it's script inside a $(function() { EVERYTHING }); SO, when I try to call anything in EVERYTHING from the console it says it's undefined, but if I just used console.log inside EVERYTHING it would work. So is there a way I can get around this?
Feel free to explain why it isn't working but I'd like a way to enable this, don't tell me there isn't a way, even if I have to prefix what I want with the .js file it's coming from each time, I don't mind
You were correct in that all of your variables inside the function are only being defined locally, and thus can't be accessed via the console. However, in Javascript there are at least two options for setting global variables from inside functions; If you use these to declare a variable you want to access from outside the function, it will work:
Assign a value to an undeclared variable: varname=value;
Assign the variable to the window object: window.varname=value; or window['varname']=value;
A possible workaround is to expose the object(s) that you want to debug in the global scope:
(function() {
var privateStuff = { foo: 'bar' };
// make privateStuff public for debugging purposes
window['debugObject'] = privateStuff;
})();
document.write(debugObject.foo);
If you want to expose several objects with rather common names that are likely to collide with existing ones, make sure to expose them within an object with an uncommon name rather than directly:
(function() {
var x = { str: 'this is' },
y = { str: 'a test' };
window['debugObject'] = {
x: x,
y: y
};
})();
document.write(debugObject.x.str + ' ' + debugObject.y.str);
If you're happy to change the source file then you could export whatever you want to access from EVERYTHING as a global.
$(function() {
//EVERYTHING
...
window.Ireply = window.Ireply || {};
window.Ireply.object = object;
...
});
console.log(Ireply.object); // some object
You can change a declaration like
$(function(){
var cart = {};
})
To
var cart;
$(function(){
cart = {}
})
Or
$(function(){
var cart = {};
window.cart = cart;
})
But you will want to avoid polluting global namespace. You will also want to be careful about using globals inside callbacks or loops where you can run into unexpected behaviors since local variables scope is often important to be kept local

Firefox add-on: function not available after juggling scopes

As of Firefox 36, Function.__exposedProps__ was made unavailable. Instead if one wanted to expose a chrome JS object to be used in content scripts, they have to use Components.utils.cloneInto with the target scope as browser.contentWindow.wrappedJSObject.
If one does not turn on the cloneFunctions flag, only those attributes are cloned that are not functions. Turning the flag does clone functions too, but not those functions that are defined via the Function.prototype path. For those functions one has to export them via Components.utils.exportTo with the target scope as your exposed object.
Coming to the issue I'm facing. (As I am unable to put it in words, I am adding a MWE).
Chrome end JS:
function Foo(){
this._nFunc = "something";
this._func = function(){/*do something*/};
}
Foo.prototype.Bar = function(){
this._func();
}
Foo.prototype.FooBar = function(){
this._nFunc = "somthing else";
}
var myFoo = new Foo();
var targetScope = browser.contentWindow.wrappedJSObject;
targetScope.myExposedObject = Components.utils.cloneInto(myFoo, targetScope, {cloneFunctions:true});
Components.utils.exportFunction(myFoo.Bar, targetScope.myExposedObject , {defineAs:"Bar"});
Components.utils.exportFunction(myFoo.FooBar, targetScope.myExposedObject , {defineAs:"FooBar"});
Content end JS:
window.myExposedObject.FooBar(); // works
window.myExposedObject._func(); // works
window.myExposedObject.Bar() // error this._func is undefined
Upon logging the this scope received by the function Bar(), we get _func:(void 0), while _nFunc is logged correctly.
Questions:
Is there something I'm missing, or is this a limitation in Firefox? If it is a limitation, please suggest possible ways to workaround the limitation.
Initially I thought that Bar() was somehow unable to access the scope of the calling object, and I tried to supply it the scope as parameters, i.e., Foo.prototype.Bar = function(scope){ scope._func();} and window.myExposedObject.Bar(window.myExposedObject);. Interestingly upon logging, the scope object also turned out to be (void 0). Why is that? I am sure that I am missing something here. What I expected was that the exposed object would map to the original object and upon sending the exposed object as parameters the chrome end JS would be able to get the original object.
While what you're trying to do might be possible with the right combination of cloneInto/exportFunction and waiving of xrays i would suggest you simply load the unprivileged part of your class hierarchy directly into the target context with the subscript loader and only hook the minimal amount of privileged functions into the prototype once it has been created.
This should reduce the attack surface and also avoid headaches with inheritance.
Additionally, these may prove useful:
https://developer.mozilla.org/en-US/docs/Components.utils.createObjectIn
https://developer.mozilla.org/en-US/docs/Components.utils.makeObjectPropsNormal

How to fix scope issue between my jquery+flash plugin and require.js

I got a pull request on GitHub today for a small jquery plugin proposing a little hack in it's master branch because the Flash element of the plugin doesn't work with require.js closures. It comes down to Flash needing a global variable, so the scope changes after loading through require.js and the variable is no longer seen.
The proposed fix in the pull request is to omit declaration, so basically:
foo = { "bar": 1 };
instead of:
var foo = { "bar": 1 };
but that prohibits jslint passing forever, so I don't really want to do that.
Should i fix this in my main script with something like:
var foo = { "bar": 1 };
if ( typeof(window) === 'object' ) { window['foo'] = foo; }
or should I encourage this to be fixed in the implementation rather than in my script?
Does the third party need direct control over the variable? You can add the line window.foo = foo at the end.
However, it would be safer be to have a getFoo() method that returns the value, that way you keep control over the variable.
If you require a global variable for Flash, then I suggest creating a proper namespace for your application so the Flash can access it through a single point of entry.
// create your objects for your app
var foo = {
bar: 1
};
// add your object to the global namespace eg. 'myApp'
window.myApp = foo;
This article might help: http://www.2ality.com/2011/04/modules-and-namespaces-in-javascript.html
You could provide an initialization parameter allowing the consumer of your library to choose where to stick it to.
require(['theflashlibrary'], function(theFlashLibrary){
theFlashLibrary.init({ globalProperty: 'foo' }); //Otherwise this could default to something else...
});
I don't have a good way of doing this, but, I feel that it would be nice to at least provide a way for the user to choose where will your library be referenced.

Protecting a Global Javascript "API" Object

I currently have a Web Application that runs off a global Javascript-based API, and it is initialized like this:
var Api = {
someVar: "test",
someFunction: function() {
return "foo";
}
}
This API is shared across many "Widgets" that live in the Web Application, and they should all run off this single Api instance so they can pass data to each other.
AJAX is currently used to load these Widgets, for example in widgets/mywidget.html, and it's placed in, say, <div id='widget_<random number>'>...</div>
Certain other parts of the code may choose to add more functionality to Api, and it's currently done like this:
Api.myExtension = {
myNewFunction: function() {
return "bar";
}
}
However, some issues arise from this kind of usage:
Problem One: What if one Widget (these may be provided by third-parties) decides to hide some code within, and does something similar to Api = {}, destroying the global Api var everything lives on, and breaking the whole Application? Is it possible to protect this Api variable from being overwritten from outside? Only "extending" is allowed (adding new things), but "removing/changing" is not allowed. i.e.:
Api.foo = { test: "bar" } // allowed
Api.someVar = "changing the existing someVar"; // not allowed
The following code is located "inside" Api, for example:
var Api = {
Debug: {
Messages = new Array,
Write: function() {
Api.Debug.Messages.push("test"); // allowed
}
}
}
Api.Debug.Messages.push("test 2"); // not allowed
Probable Solutions I've Thought Of:
Suppose we simply use frames to resolve this issue. The Apis provided are now separate from each other. However, there's additional overhead when loading Api again and again if I have many Widgets running, and they can no longer communicate with the "Host" of the widgets (the page where frames reside in), for example, I may want to tell the host to show a notification: Api.Notify.Show("Test"), but it cannot do so because this Api is completely independent from other instances, and it cannot communicate with the "Host"
Using something like a "getter" and "setter" function for the Api to be read and written. I'm unsure on how to implement this, so any help on directions on how to implement this is welcome!
A mixture of 1/2?
There's no good way to prevent having a "third party" widget overwrite the a global variable. Generally it is the responsibility of whoever is putting together the final application to ensure that whatever JavaScripts they are using aren't littering the global namespace and conflicting. The best thing you can do in that direction is give your "Api" a nice, unique name.
What I think can help you a lot is something like the "revealing pattern", which would be a way of doing the "getters and setters" you mentioned, plus more if you needed it.
A simple, useless example would be like the following:
var Api = (function () {
// private variable
var myArray = [];
return {
addItem: function (newItem) {
myArray.push(newItem);
},
printItems: function () {
console.log("lots if items");
}
};
})();
Api.addItem("Hello, world");
Api.extensionValue = 5;
I think you should make a clear delineation of what is shared, or "singleton" data, and keep those items private, as with myArray in my example.
Make it a constant:
const Api = "hi";
Api = 0;
alert(Api); //"hi"
Take a look at
Object.freeze
More info here
Here is a code example from Mozilla's page:
var obj = {
prop: function (){},
foo: "bar"
};
// New properties may be added, existing properties may be changed or removed
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;
var o = Object.freeze(obj);
assert(Object.isFrozen(obj) === true);
// Now any changes will fail
obj.foo = "quux"; // silently does nothing
obj.quaxxor = "the friendly duck"; // silently doesn't add the property
// ...and in strict mode such attempts will throw TypeErrors
function fail(){
"use strict";
obj.foo = "sparky"; // throws a TypeError
delete obj.quaxxor; // throws a TypeError
obj.sparky = "arf"; // throws a TypeError
}
fail();
// Attempted changes through Object.defineProperty will also throw
Object.defineProperty(obj, "ohai", { value: 17 }); // throws a TypeError
Object.defineProperty(obj, "foo", { value: "eit" }); // throws a TypeError
However browser support is still partial
EDIT: see Kernel James's answer, it's more relevant to your question (freeze will protect the object, but not protect reassigning it. however const will) same issue with limited browser support though.
The only way (at least that I can think of) to protect your global variable is to prevent the Widgets from having a direct access to it. This can be achieved by using frames functions, as you suggested. You should create an object that contains all the functions that the Widgets should be able to use, and pass such to each Widget. For example:
var Api = {
widgetApi = {
someFunction: function(){
// ...
}
},
addWidget:function(){
var temp = this.widgetApi.constructor();
for(var key in this.widgetApi)
temp[key] = clone(this.widgetApi[key]);
return temp;
}
// Include other variables that Widgets can't use
}
This way, the Widgets could execute functions and communicate with the host or global variable Api. To set variables, the Widget would be editing its private object, rather than the global one. For every frame (that represents a Widget), you must initialize or create a copy of the widgetApi object, and probably store it inside an array, in such a way that an instance of a Widget is stored in the main Api object.
For example, given <iframe id="widget"></iframe>
You would do the following:
var widget = document.getElementById("widget");
widget.contentWindow.Api = Api.addWidget();
widget.contentWindow.parent = null;
widget.contentWindow.top = null;
Additionally, in every frame you would need to set the parent and top variables to null so that the Widgets wouldn't be able to access the data of the main frame. I haven't tested this method in a while, so there might be ways to get around setting those variables to null.

Strange Closure Compiler issue

I'm using Google's Closure Compiler in advanced mode, and I'm having a strange issue. Here is the uncompiled code, with returned log statement from the compiled version running:
goog.provide('frame.store');
goog.require('frame.storeBack.LocalStore');
goog.require('frame.storeBack.Mem');
frame.store = (function() {
/** prioritised list of backends **/
var backends = [
frame.storeBack.LocalStore,
frame.storeBack.Mem
];
frame.log(backends);
// [function rc(){}, function tc(){this.q={}}]
frame.log(frame.storeBack.LocalStore === backends[0]);
// true
frame.log(frame.storeBack.LocalStore.isAvailable === backends[0].isAvailable);
// false
frame.log(frame.storeBack.LocalStore.isAvailable);
// function sc(){try{return"localStorage"in window&&window.localStorage!==k}catch(a){return l}}
frame.log(backends[0].isAvailable);
// undefined
for (var i=0, len=backends.length; i<len; i++)
if (backends[i].isAvailable())
return new backends[i]();
// Uncaught TypeError: Object function rc(){} has no method 'Ga'
throw('no suitable storage backend');
})();
For some reason the static method isAvailable is not present when LocalStore is accessed via the backends array, and is present when it's accessed via it's global namespace.
Can anyone see why?
EDIT: for reference, here is the method declaration:
frame.storeBack.LocalStore.isAvailable = function() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
}catch (e) {
return false;
}
};
Turn on --debug true to check your output and what frame.storeBack.LocalStore.isAvailable is renamed to.
Dump a variables name map to check whether frame.storeBack.LocalStore.isAvailable has been flattened.
For example, the Closure Compiler may flatten frame.storeBack.LocalStore.isAvailable first to frame$storeBack$LocalStore$isAvailable, then rename the whole thing to the global function "a" or something. This is called flattening of namespaces. Check the debug output to see whether your function declaration has been renamed to:
$frame$storeBack$LocalStore$isAvailable$$ = function() {
In such case, calling frame.storeBack.LocalStore.isAvailable() directly will still call the flattened global version, no prob here! However, you can't expact that isAvailable() exists in frame.storeBack.LocalStore (another object) any more. In the compiled output, frame.storeBack.LocalStore.isAvailable and frame.storeBack.LocalStore are now separated. This is the behavior of the compiler's namespace flattening, if it happens.
You're asking for trouble putting properties into a constructor function itself -- the compiler does a lot of optimizations on classes that you may not expect.
Check the debug output and variable names map to confirm. You may have to remove the closure wrapper function in order to see the actual names in the map file.
Not sure what your back ends are exactly...
But shouldn't you instantiate them?
var backends = { localStore : new frame.storeBack.LocalStore(),
mem: new frame.storeBack.Mem() };

Categories