Есть ли способ предотвратить переопределение/перезапись функций/переменных в экземпляре 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
  }    
});

На самом деле, ЛУЧШЕ в этом смысле использовать Object.freeze(instance) или Object.seal(instance) вместо Object.defineProperty, так как последнее можно снова вызвать с помощью writable: false (глупо, да?)

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


person pocesar    schedule 03.02.2013    source источник
comment
Если ваше приложение зависит от целостности кода JavaScript, который выполняется на клиентской машине, то это ваша реальная проблема. Вам не нужно заботиться о том, что там происходит, просто убедитесь, что вы отправляете только то, что клиенту разрешено видеть, проверять и дезинфицировать все, что приходит.   -  person Niko    schedule 03.02.2013
comment
а как насчет AJAX, которым можно манипулировать (думая о другом сценарии, отличном от проверки). На самом деле это не МОЕ приложение, это библиотека, которая работает в проектах других людей, кстати.   -  person pocesar    schedule 03.02.2013
comment
Возможно, вы могли бы подумать об улучшении своего кода с помощью некоторой прокладки для поддержки возможностей кросс-браузерных объектов ES5. Взгляните на stackoverflow.com /вопросы/8221757/   -  person Ragnarokkr    schedule 03.02.2013
comment
ну, я думаю, я просто проверю Object.defineProperties и заморозю весь свой синглтон, когда API будет доступен...   -  person pocesar    schedule 03.02.2013
comment
Также доступно: Object.freeze.   -  person Felix Kling    schedule 03.02.2013
comment
да, Object.freeze — это то, что нужно. Я просто могу меньше заботиться о старом, т.е. во всяком случае, я думаю   -  person pocesar    schedule 03.02.2013
comment
печальная часть заключается в том, что объект МОЖЕТ быть «разморожен». это просто природа Javascript, я не могу заставить его быть чем-то, что не является mohsenweb. com/unfreeze-a-javascript-object (внизу)   -  person pocesar    schedule 03.02.2013
comment
@Нико прав. НЕ БЕСПОКОИТЕСЬ о том, что злонамеренный программист переопределит это. Если он хочет быть злонамеренным, ничто не остановит его от отправки некорректного запроса на сервер, независимо от того, какой Javascript вы используете.   -  person Paul Draper    schedule 04.02.2013
comment
Они могут просто написать совершенно другое приложение, которое начнет постить дерьмо на ваш сервер. Защита этого объекта (если бы вы могли) не защитит вас от этого. Защитите свой сервер.   -  person GolezTrol    schedule 04.02.2013


Ответы (3)


Если бы кто-то когда-либо захотел манипулировать этим кодом (например, злонамеренный пользователь), он бы переписал функцию 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 больше не выполняет скрипт в рамках активной страницы.

So...

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

Вам следует.

person Fagner Brack    schedule 05.02.2013

Предложение

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

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

Если ваш метод инициализации объявляет несколько привязок событий к приложению, вы можете таким образом сохранить свое состояние закрытым. События смогут запускать внутренние методы, поскольку они связаны внутри внутреннего замыкания, но внешний код их не увидит.

Бронирование

Хотя это может решить вашу проблему, я не уверен на 100%, что это так, в любом случае этому нельзя доверять. Любой пользователь, который хочет проникнуть в ваше приложение, может, если безопасность на стороне клиента. В любом случае ничто не мешает им создать свой собственный объект, чтобы заменить ваш постфактум, ES5 или не ES5.

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

person Jonas Schubert Erlandsson    schedule 03.02.2013
comment
это примерно то, что я делаю в данный момент ... Я просто хочу избежать со всем, что у меня есть в настоящее время, любого вмешательства в плагин jquery, автором которого я являюсь, просто потому, что я не буду знать, кто и как люди буду использовать его, поэтому я хочу сохранить его «защищенным от несанкционированного доступа», чтобы, по крайней мере, моя работа была выполнена - person pocesar; 04.02.2013

Что, если 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.

person KooiInc    schedule 03.02.2013