In JavaScript when i say window.SomeData = 'whatever', where does it get saved in the browser? I thought it gets saved in the viewstate but it doesnt. Also how much security concern is it to save some data in window.someKey. I am not talking about username or password storage but some general data like PK values of some records.
--Edit--
The reason i am asking this is because i have a page with 5 tabs and each tabs gets loaded by an AJAX call. I need to save the data that comes back from AJAX request and currently i am using window.somekey to save it.
It gets saved in the global object window. That object is not very secure and its lifetime is for that page.
It doesn't get saved anywhere, it is exactly the same as using a global variable:
var SomeData = "whatever"; //done in global scope obviously
window.SomeData === "whatever" //true
Nowhere, effectively. Data stored in random fields of the window object is not saved.
The annoying answer is its saved in memory! Its no different than having
var j = {}
j.SomeData = 'Whatever'
window is just a global variable containing all the information about window (such as the documents DOM)
window can have data saved like the j variable above. Its no less safe than saving any piece of information ANYWHERE else in js. The only risk you have is that the items namespace may be used by another library.
So if i were you i would do this. (use this as a guide to writing good JS http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/)
(function(MyLibrary, $, undefined) {
var stuff;
MyLibrary.SomeData = 5;
}(window.MyLibrary = window.MyLibrary || {}, jQuery)); // or moo tools
alert(window.MyLibrary.SomeData); // 5!
It's generally good practice to use an object as namespace for functions and variables specific for web application. For example:
var site = {};
site.someData = 'whatever';
site.initGallery = function() {
//
};
Declaration of variables in global namespace (in client-side JS, window is global namespace) is called global-namespace pollution and is generally undesirable and unrecommended since it can lead to naming conflicts either with other libraries that also pollute global namespace or, even worse, with browser's native global objects.
Related
I have my HTML setup like this:
<script type="module" src="main.js"></script>
and all the ES6 modules work fine. The only problem is I now can't refer to anything from within DevTools (like using the Console and typing in a variable to see it's value or using a function manually).
How do I import modules whilst being able to use the DevTools? Thanks!
One way to make a variable accessable within DevTools is to create it on the window object:
// Variable in your module
var importantNumber = 1;
window.importantNumber = importantNumber;
This method works fine if you just have a couple of variables, but if you need to have access to a lot more variables within DevTools, I would recommend you go to the sources-tab in DevTools, search for your module and adding a breakpoint. When the execution pauses, you have access to all the variables within that module on the DevTools console.
If you want to be able to refer to variables created within the module from the console's global scope, you'll have to deliberately expose each such variable that you want to be visible from the console. Either assign each variable to window (probably not a good idea - the whole point of modules is to make things more modular, without global pollution), or perhaps assign a single object to window, to which you assign module variables. For example:
// in the console:
setTimeout(() => {
window.myModule.foo();
console.log(window.myModule.bar);
});
<script type="module">
function foo() {
console.log('doing foo');
}
const bar = 'a string bar';
const thisModule = { foo, bar };
window.myModule = thisModule;
// If you ever reassign variables, you'll have to reassign them on thisModule too
// or, only reference and reassign properties of thisModule, rather than create independent variables
</script>
For anyone else interested, if you're comfortable with it, use a bundler like Webpack. I don't believe (at least at this point) that the browser will by itself be able to use the DevTools on modules (the other solutions are quite janky, and aren't fantastic to work with).
Hopefully in the future, when all major browsers will be able to support ES6 modules without a bundler, we'll be able to use DevTools.
Using a Helper
I personally use a little helper function in development that allows me to expose a bunch a variables in a single expression. For example, it makes the following two blocks equivalent:
window.playerOne = playerOne;
window.someClass = someClass;
window.localData = localData;
globalize({playerOne, someClass, localData});
The helper looks like this:
const globalize = function(variables) {
Object.entries(variables).forEach(([name, value]) => window[name] = value);
};
I'm trying to refactor code that uses let to declare a module scoped Auth instance which is later reassigned (in the same module) due to a configuration change. The original implementation looks like this.
let client = new Auth({ config });
// ...later in the same module
export const updateConfig = (_config) => { client = new Auth(_config) };
My first question, is the original Client released after updateConfig(). How would you prove that?
Are there any drawbacks to this approach?
My proposed refactor aims to make this a little less magical, by wrapping the Auth module in a singleton with an implicit constructor. However, it requires a getter for the instance. But, in essence it does the same thing by re-assigning a reference when a new configuration is applied.
function Client(options) {
if (Client._instance) {
return Client._instance;
}
if (!(this instanceof Client)) {
return new Client(options);
}
this._instance = new Auth(options);
}
Client.prototype.getInstance = function() { return this._instance };
Client.prototype.updateConfig = function(opts) {
this._instance = new Client(opts).getInstance();
}
// usage
const client = new Client({ foo: 'bar'});
client.updateConfig({bar: 'baz'});
console.log(client.getInstance()); // eg. { bar: 'baz' } works!
Same questions apply, from a code safety and memory management perspective, which solution is more appropriate? These are Authentication classes, so I want to make sure they are collected properly and not potentially abused.
My first question, is the original Client released after updateConfig()?
Maybe, if client is the only variable that references it.
How would you prove that?
Make a memory dump in the console and search for those client objects.
Are there any drawbacks to this approach?
No, as long as no one is referencing the client which you expect to update:
const referenced = client;
updateConfig();
console.log(referenced === client); // false
My proposed refactor aims to make this a little less magical ... but, in essence it does the same thing
Why is it "less magical" if you hide that change behind 20 lines of code? If I would be the reviewer, I would reject this change, because it introduces some unexpected behaviour, and provides no benefit whatsoever:
console.log(new Client === new Client); // true, wtf
How I would refactor that (good comments are underestimated):
// Note: client gets re-set in updateConfig(), do not reference this!
let client = new Auth({ config });
From a code safety and memory management perspective, which solution is more appropriate?
"but, in essence it does the same thing ". Wise words.
When we call new on a constructor function, it will always return a new object which means that when client was mutated later, it now definitely holds the new value. That is one thing.
The other thing is that javascript runtime environment garbage collector and looks for the objects which are in memory but are not reference from any variable and if found remove them.
So basically when I do this
let obj = {name: 'Hello'}
obj referes to some object with 2ABCS memory address and when I mutate it
let obj = {name: 'World'}
It now refers to object with address 1ABCS which makes 2ABCS orphan which means it will be removed by garbage collector
For more read https://javascript.info/garbage-collection
In Javascript, GC is not a big concern for potentially abusing the information available in objects. It is the objects themselves. With modern day developer tools, one can easily get into any part of front end code and make sense out of it unless it is obfuscated. IMO, Obfuscation is pretty much necessary these days. One it reduces the file size and second makes it bit difficult to nerds using the code in production.
Now coming to the actual question. Once a new instance new Auth is assigned to client, the old instance is no more hard referenced by client so it is eligible to garbage collection provided no other references are held. There is no guarantee on how quickly the memory is reclaimed.
And advantage of using let is it's scope. It is restricted to its block. However, it is not uncommon to have huge blocks. Compared to global vars, let offers you a small scope and hence may get released soon after the block ends. It may also be the case that Javascript runtime may utilize method stack for let variables and as soon as block ends (method), it will drop the stack and hence the references are also dropped.
Finally, it is absolutely fine to have the way it is and your implementation does not offer any advantage over the previous one.
Background
I just learned that calling keys(window) (or Object.keys(window)) in the DevTools console reveals variables in the global scope (source). I called that code on the StackOverflow page and got this result:
Variable i got my attention as it seems to be in the global scope by a mistake. I tried locating code that is responsible for declaring i, but it turned out to be cumbersome (there is a lot of code and a lot of is).
Question
Getting console warnings that say
Global variable "i" created (main.js:342)
could be useful. How can I implement that feature?
Research
I figured that I need some kind of an event whenever new variable is created.
We do have setters in JavaScript. However, creating a setter requires that you provide a property name. Since I want to monitor all properties I can't really use that.
__noSuchMethod__ (MDN) would be perfect but it only covers methods (and there is no __noSuchProperty__ method).
Object.observe (HTML5 Rocks) doesn't reveal anything about the code that created the property (console.trace() gives me only the name of the observer function).
Object.prototype.watch (MDN) - same as the setter, you have to specify a property name.
Calling Object.preventExtensions(window) (MDN) causes errors with a nice stack trace whenever new global variable is created. The problem with this solution is that it interferes with the script execution and may change its behaviour. It also doesn't allow me to catch the error and format it properly.
Notes
I know about jshint/jslint and I still think that catching these declarations in the runtime could be useful.
I don't care about i variable on the SO page that much, you can probably find the declaration using setters. My question concerns the general solution for this problem.
IMO you have two decent options:
JSHint.
Strict mode.
Both will yell at you when you leak a global. Strict mode will probably be better for your usecases.
You've definitely done your homework, and you thought of all the things I would have thought of and, as you discovered, none of them fit.
The only way I can think of doing is to just monitor the global object (this example is using window as the global object: modify accordingly for Node or another JavaScript container). Here's an example that monitors new globals and deleted globals (if you don't need to monitor deletions, you can remove that functionality):
var globals = Object.keys(window);
var monitorGlobalInterval = 50;
setInterval(function(){
var globalsNow = Object.keys(window);
var newGlobals = globalsNow.filter(function(key){
return globals.indexOf(key)===-1;
});
var deletedGlobals = globals.filter(function(key){
return globalsNow.indexOf(key)===-1;
});
newGlobals.forEach(function(key){
console.log('new global: ' + key);
});
deletedGlobals.forEach(function(key){
console.log('global deleted: ' + key);
});
globals = globalsNow;
}, monitorGlobalInterval);
See it in action here: http://jsfiddle.net/dRjP9/2/
You can try this method to get a list of global variables that you've created:
(function(){
var differences = {},
ignoreList = (prompt('Ignore filter (comma sep)?', 'jQuery, Backbone, _, $').split(/,\s?/) || []),
iframe = document.createElement('iframe'),
count = 0; ignoreList.push('prop');
for (prop in window) {
differences[prop] = {
type: typeof window[prop],
val: window[prop]
}; count++;
}
iframe.src = 'about:blank';
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe = iframe.contentWindow || iframe.contentDocument;
for (prop in differences) {
if (prop in iframe || ignoreList.indexOf(prop) >= 0) {
delete differences[prop];
count--;
}
}
console.info('Total globals: %d', count);
return differences;
})();
So, I just noticed today that you can apparently run javascript in the chrome console. I had no idea you could do this. It's actually really cool.
In my rails app, I have an external javascript page. Some of the variables on that page I would like to be global so that all the functions in the JS file can access them. for example I have a map, and I would like the map object to be global in the javascript file because that way all my functions access the one map variable instead of creating their own, and I can break complex operations down into smaller functions.
This is all well and good I know how to do that and it's working perfectly. My problem now, can I protect the variables from outside? For example you can change the values of all the javascript class variables from the chrome console.. as well methods from for example the map are accessible and excecutable.. I have locked the map settings on one of the pages so it is not zoomable or movable, however from the console I can simply say map.setZoom(11) and the map will zoom to 11.. I can type map.dragable = true and bam u can drag the map.. I don't like this really..
It's not too terribly bad yet like the user enabling map drag and zoom isnt the worst thing in the world.. but still I'd like to disable this. Any ideas?
EDIT
Thanks all for the answers and comments. I guess I will just resort to not putting anything that can be turned malicious into my javascript, and do thing like pass my map variable to functions where necessary to slow people down.
You can use an immediately-invoked function (IIFE) expression to prevent your variables and functions from being exposed in the global scope:
var a = 10;
(function() {
var b = 20;
})();
window.a lets you view and modify a, but you cannot do that with b:
Try it out here
I'm more than sure that there's a way to edit b with Inspector, but I haven't taken the time to figure it out. Don't waste your time trying to prevent your users from modifying code that they can view.
You can't. Even if you wrap them into anonymous functions, user can get to them through debugger. As last resort he can simply intercept your traffic to his own machine and replace your JavaScript with something else.
Bottom line: JavaScript in browser is client-side. Client can do whatever he pleases with it.
Try doing something like this:
(function(){
//All of your current code
})();
One thing to still be aware of - Chrome developer tools also lets you edit the javascript (not the javascript file on the server, just currently running copy.) Go to Chrome Dev Tools->Sources and you can edit the javascript files.
You can't. Your saying you need to define your map globally, this means it's accessible for everyone.
You could define your map in a different scope and then only define the "public" things:
(function() {
var map = new Map();
window.myMap = {
goTo: function(lat, lng) {
map.goTo(lat, lng);
}
};
})();
Depending on your architecture, there are a few ways to accomplish this. Use this method to create a reusable component that has public and private properties:
var protectedScope = function () {
var protected_var = 'protected';
this.showProtected = function () {
return protected_var;
}
this.public = 'public';
};
var myObject = new protectedScope();
console.log('Public var: '+myObject.public); // outputs "public"
console.log('Protected via accessor: '+myObject.showProtected ()); // outputs "private"
console.log('Protected var: '+myObject.protected); // outputs undefined
Any variable or function declared with a var keyword will be, in effect, private. Any variable or function that uses the this.name mechanism will be "public".
Understand that this structure is not truly public or private, such concepts are not a part of the language. There are still ways to get at those variables, and one can always view source. Just be clear; this is a code organization concept rather than a security concept. Chrome has had this developer console for a while, and other major user agents are moving to include similar tools (or already have done so). There are also tools like Firebug which allow a user full access to your javascript runtime environment. This isn't a realm that the developer can control at all.
Try it here: http://jsfiddle.net/cf2kS/
More Reading
"Private Members in JavaScript" by Douglas Crockford* - http://www.crockford.com/javascript/private.html
"OOP in JS, Part 1 : Public/Private Variables and Methods" on http://phrogz.net - http://phrogz.net/JS/classes/OOPinJS.html
Javascript Object Management on MDN - https://developer.mozilla.org/en-US/docs/XUL_School/JavaScript_Object_Management
Closures on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures
Object.defineProperty(map, 'zoom', {value:1});
or
Object.defineProperty(map, 'zoom',{
set: function(){console.warn('Access denied!');},
get: function(){return 1;}
});
demo
or
Object.defineProperty(Object.prototype, 'protect', {
value: function(ignore){
var childObjects = [], ignore = ignore || [];
ignore.push(this);
if(this instanceof MimeType)return; //Chrome Fix //window.clientInformation.mimeTypes[0].enabledPlugin[0] !== window.clientInformation.mimeTypes[0]
for(var prop in this){
if(typeof this[prop] === "unknown")continue; //IE fix
if(this[prop] instanceof Object){
var skip = false;
for(var i in ignore)
if(ignore[i]===this[prop]){
skip = true;
break;
}
if(!skip)childObjects.push(prop);
}
var d = Object.getOwnPropertyDescriptor(this, prop);
if(!d || !d.configurable || !d.writable)continue;
var that = this;
(function(){
var temp = that[prop];
delete that[prop];
Object.defineProperty(that, prop,{
set: function(){console.warn('Access denied!');},
get: function(){return temp;}
});
})();
}
for(var i = 0;i<childObjects.length;i++)
this[childObjects[i]].protect(ignore);
}
});
this.onload=function(){this.protect();} //example
demo
How can I set an environment variable in WSH jscript file that calls another program? Here's the reduced test case:
envtest.js
----------
var oShell = WScript.CreateObject("WScript.Shell");
var oSysEnv = oShell.Environment("SYSTEM");
oSysEnv("TEST_ENV_VAR") = "TEST_VALUE";
oExec = oShell.Run("envtest.bat", 1, true);
envtest.bat
-----------
set
pause
I expect to see TEST_ ENV _VAR in the list of variables, but it's not there. What's wrong?
edit:
If someone can produce a working code sample, I'll mark that as the correct answer. :)
The problem is not in your code, but it is in execution of the process. The complete system variables are assigned to the process which is executed. so, your child process also had the same set of variables.
Your code-sample works good. It adds the variable to the SYSTEM environment.
So, you need to set the variable not only for your system but also for your process.
Here's the code.
var oShell = WScript.CreateObject("WScript.Shell");
var oSysEnv = oShell.Environment("SYSTEM");
oSysEnv("TEST1") = "TEST_VALUE";
var oSysEnv = oShell.Environment("PROCESS");
oSysEnv("TEST1") = "TEST_VALUE";
oExec = oShell.Run("envtest.bat", 1, true);
Once you created the system variable.
It will assign the newly created variable for the current process. So, your child process can get that variable while the "SET" command executed.
Sorry for my bad-english.
There are 4 "collections" (System, User, Volatile, and Process) you probably want Process if you just need a child process to see the variable
You are getting the system environment variables. I suspect you simply don't have permission to modify them; you could try changing this to the user environment variables.
Also I don't know whether the argument to Environment() is case-sensitive or not. MS's documentation uses "System" instead of "SYSTEM". Might make a difference but I don't know for sure.