Есть ли способ предотвратить переопределение/перезапись функций/переменных в экземпляре singleton? - программирование

Есть ли способ предотвратить переопределение/перезапись функций/переменных в экземпляре singleton?

Рассмотрим этот псевдокод:

(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 со своим собственным, например, с помощью адресной строки (у него нет firebug, кто знает).

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

На самом деле, что BEST в этом смысле состоит в том, чтобы использовать Object.freeze(instance) или Object.seal(instance) вместо Object.defineProperty, так как позже можно снова вызвать с помощью writable: false (глупый huh?)

Есть ли какой-либо способ работать в старых браузерах (а именно IE6-8) без лишних хлопот? Если это невозможно, тогда я просто пожимаю плечами и двигаюсь дальше.

4b9b3361

Ответ 1

Если кто-либо когда-либо хотел манипулировать этим кодом (злоумышленник для пример), он будет переписывать функцию is_allowed с помощью своего собственного

Он мог переписать весь ваш код javascript или даже не использовать браузер, но имитировать запрос "без браузера" на ваш сервер.

Существует ли какой-либо способ работы в старых браузерах (а именно IE6-8) без слишком много хлопот?

Нет. Все, что вы раскрываете в глобальном масштабе, может быть изменено пользователем, это зависит от того, что браузер ограничивает поведение javascript:, чтобы пользователи не обманывались для доступа к предварительно созданным ссылкам. Недавно Firefox внес свое изменение в протокол URL-адреса javascript.

Как сказано в этой статье: http://survey-remover.com/blog/javascript-protocol-dangers/

Как и в случае с Chrome v13, Firefox v6 и IE 9, разработчики браузера обратили внимание на опасность протокола "javascript:" и впоследствии запретили код... В случае с Chrome и IE "javascript:" подстрока удаляется при вставке кода, тогда как Firefox больше не выполняет script в пределах области активной страницы.

Итак...

Если это невозможно, тогда я просто пожимаю плечами и двигаюсь дальше.

Вы должны.

Ответ 2

Предложение

Я не буду говорить, что я эксперт по этим вещам. Но, предполагая, что вы можете полностью завершить свой код и использовать события для запуска поведения, вы можете использовать такую ​​структуру:

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.

Для чего-то, что действительно должно быть безопасно, вам придется повторить проверку на стороне сервера. Никогда не доверяйте коду на стороне клиента, чтобы защитить вас, запрос может даже не появиться на странице, которую вы обслуживали...

Ответ 3

Что делать, если 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.instance будет undefined.