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


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

(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 у нас есть объект.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 14

3 ответа:

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

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

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

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

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

Начиная с Chrome v13, Firefox v6 и IE 9, разработчики браузеров обратили внимание на опасность протокола "javascript:" и впоследствии запретили код ... В случае хрома и То есть, подстрока" 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.instance будет undefined.