有没有办法防止在单例实例中覆盖/覆盖函数/变量?

时间:2013-02-03 10:02:35

标签: javascript singleton javascript-objects overwrite

考虑这个伪代码:

(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);

如果有人想操纵这个代码(例如恶意用户),他会用自己的代码重写is_allowed函数,例如,使用地址栏(他没有萤火虫,谁知道)。

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

这是一个天真的例子,但重点是,Javascript中的任何内容都可以被覆盖。

我知道在es5中我们有Object.defineProperty,所​​以你可以设置:

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

实际上,在这个意义上最好的是使用Object.freeze(instance)Object.seal(instance)代替Object.defineProperty,因为后者可以使用writable: false再次调用(傻呀? )

有没有什么方法可以在旧浏览器(即IE6-8)中运行而不会有太多麻烦?如果这是不可能的,那么我只会耸耸肩继续前进。

3 个答案:

答案 0 :(得分:2)

  

如果有人想要操纵此代码(恶意用户)   例如,他会用自己的

重写is_allowed函数

他可以重写您的整个javascript代码,甚至不使用浏览器,但可以模拟对服务器的“无浏览器”请求。

  

是否有任何方式可以在旧浏览器(即IE6-8)中使用它   麻烦太多了?

没有。您全局公开的任何内容都可以由用户更改,由浏览器限制javascript:行为以避免用户被愚弄以访问预先制作的链接。 Firefox最近对javascript URL协议进行了一些更改。

如本文所述:http://survey-remover.com/blog/javascript-protocol-dangers/

  

从Chrome v13,Firefox v6和IE 9开始,浏览器开发人员已经注意到“javascript:”协议的危险,并随后禁止使用代码......在Chrome和IE的情况下,“javascript: “粘贴代码时会删除子字符串,而Firefox不再在活动页面的范围内执行脚本。

因此...

  

如果不可能,那我就耸耸肩继续前进。

你应该。

答案 1 :(得分:1)

提案

我不会说我是这方面的专家。但假设您可以完全包装代码并使用事件来触发行为,您可以使用如下结构:

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 };

}())};

使用obj = Closed("Anything");进行设置,您仍然可以让恶意用户覆盖use_secret()方法,因为它已公开,但get_secret()方法和任何其他内部方法都受到保护。< / p>

如果你的init方法声明了一些对应用程序的事件绑定,你可以用这种方式保持你的状态私有。事件将能够触发内部方法,因为它们从内部闭包内部绑定,但外部代码将看不到它们。

预订

虽然这可能会解决您的问题,但我并不是百分之百确定它,不管怎么说都不值得信任。只要安全性在客户端,任何想要渗透您的应用程序的用户都可以。无论如何,ES5或没有ES5,没有什么可以阻止他们制作自己的对象来替换你的。

对于任何实际需要安全的内容,您必须在服务器端重新验证。永远不要相信客户端代码来保护您,请求可能甚至不会来自您提供的页面......

答案 2 :(得分:0)

如果is_allowed完全是本地的,该怎么办?

(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模型

BTW:在您的代码中,window.instance将是undefined