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

Is there any way to prevent override/overwrite of functions/variables in singleton instance?

本文关键字:覆盖 函数 变量 实例 单例 有没有      更新时间:2023-09-26

考虑这个伪代码:

(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)中工作而不会有太多麻烦?如果不可能,那么我会耸耸肩继续前进。

如果有人想要操纵此代码(恶意用户 示例),他会用自己的函数重写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不再在活动页面范围内执行脚本。

所以。。。

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

你应该。

提案

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

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() 方法和任何其他内部都受到保护。

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

保留

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

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

如果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 样机

顺便说一句:在您的代码中,window.instanceundefined.