最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Is there any way to prevent overrideoverwrite of functionsvariables in singleton instance? - Stack Overflow

programmeradmin2浏览0评论

Consider this pseudo code:

(function(window){
   var options = { /*where everything goes */ };

   var instance = (function(options){
       for (var i in options){
       if (options.hasOwnProperty(i)){
         this[i] = options[i];
       }
     }
   })(options);

   instance.callbacks = function(cb){
     //...
   }

   instance.is_allowed = function()
    //... checks, return boolean
   }

   window.instance = instance;
})(this);

If anyone ever wanted to manipulate this code (a malicious user for example), he would rewrite the is_allowed function with his own, for example, using the address bar (he doesn't have firebug, who knows).

javascript:(function(){ window.instance.is_allowed = function(){ return true; } })();

This is a naive example, but that's the point, anything in Javascript can be overwritten.

I know in es5 we have the Object.defineProperty so you can set:

// being explicit
Object.defineProperty(instance, "is_allowed", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: function(){
    // do checks
  }    
});

Actually, what is BEST in this sense is to use Object.freeze(instance) or Object.seal(instance) instead of Object.defineProperty, since the later can be called again with writable: false (silly huh?)

Is there ANY way that it work in old browsers (namely IE6-8) without too much hassle? If it's impossible, then I'll just shrug and move on.

Consider this pseudo code:

(function(window){
   var options = { /*where everything goes */ };

   var instance = (function(options){
       for (var i in options){
       if (options.hasOwnProperty(i)){
         this[i] = options[i];
       }
     }
   })(options);

   instance.callbacks = function(cb){
     //...
   }

   instance.is_allowed = function()
    //... checks, return boolean
   }

   window.instance = instance;
})(this);

If anyone ever wanted to manipulate this code (a malicious user for example), he would rewrite the is_allowed function with his own, for example, using the address bar (he doesn't have firebug, who knows).

javascript:(function(){ window.instance.is_allowed = function(){ return true; } })();

This is a naive example, but that's the point, anything in Javascript can be overwritten.

I know in es5 we have the Object.defineProperty so you can set:

// being explicit
Object.defineProperty(instance, "is_allowed", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: function(){
    // do checks
  }    
});

Actually, what is BEST in this sense is to use Object.freeze(instance) or Object.seal(instance) instead of Object.defineProperty, since the later can be called again with writable: false (silly huh?)

Is there ANY way that it work in old browsers (namely IE6-8) without too much hassle? If it's impossible, then I'll just shrug and move on.

Share Improve this question edited Feb 3, 2013 at 10:34 pocesar asked Feb 3, 2013 at 10:02 pocesarpocesar 7,0507 gold badges57 silver badges91 bronze badges 9
  • 12 If your application relies on the integrity of JavaScript code that runs on the client's machine, then that's your actual problem. You shouldn't care about what happens there, just make sure that you sent out only what the client is allowed to see and validate and sanitize everything that es in. – Niko Commented Feb 3, 2013 at 10:10
  • and what about AJAX that can be manipulated (thinking another scenario other than validation). It's not actually MY application, it's a library that runs on other peoples projects btw – pocesar Commented Feb 3, 2013 at 10:14
  • Maybe you could think to improve your code with some shim to support cross-browser ES5 Object capabilities. Take a look at stackoverflow./questions/8221757/… – Ragnarokkr Commented Feb 3, 2013 at 10:15
  • 1 Also available: Object.freeze. – Felix Kling Commented Feb 3, 2013 at 10:34
  • 2 @Niko is correct. DO NOT WORRY about a "malicious" programmer overriding that. If he wants to be malicious, nothing will stop him from sending an improper request to the server, no matter what Javascript you use. – Paul Draper Commented Feb 3, 2013 at 21:20
 |  Show 4 more ments

3 Answers 3

Reset to default 2

If anyone ever wanted to manipulate this code (a malicious user for example), he would rewrite the is_allowed function with his own

He could rewrite your whole javascript code or not even use a browser but simulate a "browser-less" request to your server.

Is there ANY way that it work in old browsers (namely IE6-8) without too much hassle?

No. Anything you globally expose can be altered by the user, it is up to the browsers restrict the javascript: behavior to avoid users from being fooled to access pre-crafted links. Firefox recently have made some kind of change to the javascript URL protocol.

As said on this article: http://survey-remover./blog/javascript-protocol-dangers/

As of Chrome v13, Firefox v6 and IE 9, the browser developers have taken notice to the dangers of the "javascript:" protocol and have subsequently disallowed code ... In the case of Chrome and IE, the "javascript:" substring is stripped when the code is pasted, whereas Firefox no longer executes the script within the scope of the active page.

So...

If it's impossible, then I'll just shrug and move on.

You should.

Proposal

I won't say I'm an expert on these things. But assuming you can wrap your code pletely and use events to trigger behavior you can use a structure like this:

Closed = function(args) { return (function() {
  "use strict";

  var secret, init, get_secret, use_secret;

  init = function(something){
    secret = something;
  };

  get_secret = function() {
    return secret;
  };

  use_secret = function () {
    console.log(secret);
  };

  /* Run constructor */
  init(args);

  /* Publish API */
  return { use_secret:use_secret };

}())};

Setting it up with obj = Closed("Anything"); you can still have a malicious user overwrite the use_secret() method, since it's exposed, but the get_secret() method, and any other internals, are protected.

If your init method declares a number of event bindings to the application you can keep your state private in this way. The events will be able to trigger internal methods since they where bound from inside the inner closure but external code won't see them.

Reservations

While this might solve your problem, I'm not 100% sure it does, it's not to be trusted anyway. Any user that want to penetrate your application can as long as the security is on the client side. There is nothing to stop them from crafting their own object to replace yours after the fact anyway, ES5 or no ES5.

For anything that actually needs to be secure you will have to revalidate on the server side. Never trust client side code to protect you, the request might not even e from the page you served ...

What if is_allowed would be pletely local?

(function(window){
   var options = {}, is_allowed;

   var instance = (function(options){
     for (var i in options) {
     if (options.hasOwnProperty(i)) {
        this[i] = options[i];
       }
     }
     return this;
   })(options);

   instance.callbacks = function(cb){
       /* ... */
   };

   function check_allowed(){
     /* check and let this function set [is_allowed] */
   };

  window.instance = check_allowed()
                     ? instance
                     : { callbacks: function(){(alert('not allowed'));}  };

} (this) );

jsBin mockup

BTW: in your code, window.instance would be undefined.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论