Как javascript (или расширение браузера) может обнаружить использование функций с ограниченным доступом?

Я разрабатываю расширение для сценариев, похожее на Greasemonkey или движок сценариев содержимого Chrome. Это расширение позволит сценаристам делать очень опасные вещи, такие как доступ к локальным файлам.

Если я когда-нибудь выпущу это расширение для широкой публики, я бы хотел, чтобы оно могло предупреждать начинающих пользователей, если сценарий будет использовать «опасную» функцию. Я бы хотел, чтобы это предупреждение было как можно сложнее обойти.

Например, расширение может искать защищенную строку GM_openSQL_Connection и предупреждать пользователя — например, так:
Bad  предупреждение скрипта

Предположим, что базовая веб-страница никогда не сможет получить доступ к GM_openSQL_Connection благодаря механизмам песочницы. Точно так же ни один узел <script> не сможет этого сделать.

Но сценарист все еще может обойти простой поиск сверху примерно так:

eval (decodeURI ("GM_op%65nSQL_Connection (...);") )


Итак, вопрос заключается в том, какими способами злонамеренный скриптер может обмануть проверку на ограниченное использование функций и как я могу предотвратить такое зло?


Примечание: ложные предупреждения могут быть в порядке. Например, если автор скрипта использует текст "GM_openSQL_Connection" в статической строке, то ему просто придется смириться с (ложным) предупреждением.


person Brock Adams    schedule 06.03.2012    source источник
comment
Совершенно не связано, но мне нравится ваш пример предупреждения. :)   -  person seeming.amusing    schedule 06.03.2012
comment
Вы не можете сказать, что это опасно только потому, что имя функции. Это возможно только для действий, а не для внесения имен в черный список. Функции, которые используют прямой доступ к файлам cookie и удаленный доступ к сторонним хостам, чаще всего признаются опасными (это не значит, что они таковые, но это может быть предупреждением о том, что они таковыми являются). Некоторые другие паттерны также могут быть интерпретированы как нежелательные.   -  person YuS    schedule 06.03.2012
comment
Я бы предложил использовать тот же подход, что и JavaScript Deobfuscator (используйте интерфейс отладки, чтобы получить все вызовы функций, независимо от того, как они скомпилированы), но это не поможет. Рассмотрим var foo = window["GM_op" + "enSQL_Connection"];foo(...). Вы не можете идти по имени функции, потому что имя функции может измениться слишком легко.   -  person Wladimir Palant    schedule 06.03.2012
comment
@Yuri, я могу и скажу, что эти функции опасны. И они; есть причина, по которой они запрещены для обычного javascript во всех браузерах и большинстве расширений. ... Ожидается, что пользователь будет знать (и в предупреждении может быть указано), что то, что это опасно, не означает, что оно обязательно используется во зло. (Иначе зачем мне вообще создавать функцию?)   -  person Brock Adams    schedule 06.03.2012
comment
@WladimirPalant, это среда расширения/дополнения, а не javascript/DOM страницы браузера. Я не понимаю, как сценарист мог переименовать мои функции, но я не являюсь экспертом в написании расширений. Я буду использовать проверки времени компиляции или установки, но они не защищают от эксплойтов во время выполнения, таких как eval.   -  person Brock Adams    schedule 06.03.2012
comment
@BrockAdams: я не понимаю, какое значение здесь имеет окружающая среда. Сценарист по-прежнему может вызывать любую функцию косвенно, присваивая ее локальной переменной и не упоминая ее имя в открытом виде. Возможно, переменной window нет, но вместо нее можно использовать this. Честно говоря, я думаю, что единственный правильный способ контролировать использование опасных API-интерфейсов — это не раскрывать эти API-интерфейсы в первую очередь — возможно, вместо этого выставлять заполнители, которые будут отображать предупреждение.   -  person Wladimir Palant    schedule 06.03.2012


Ответы (2)


Какими способами злой скриптер может обмануть проверку ограниченной функции us[age]?

Есть тысячи комбинаций, например, с eval(), new Function(), комбинаций String.fromCharCode() и decodeURI() (как в вашем примере).

Как я могу предотвратить такое зло?

Не могли бы вы перегрузить/скрыть определенные плохие функции/объекты/переменные?

GM_openSQL_Connection = function() {
   warnUser();
};

Чтобы установить флаг, если расширение пытается получить доступ к запрещенной функции или переменной, просто установите var isDangerous = false, который установлен на true, если вызывается запрещенная функция, или get/set запрещенного свойства.

Если isDangerous равно true, то вы можете пометить это расширение как потенциально имеющее опасные вызовы/доступ к функциям/свойствам.

person alex    schedule 06.03.2012
comment
Хм. У этой слежки есть потенциал. Я мог бы потребовать от разработчиков самостоятельно сообщать, какие опасные функции они используют в коде. Пользователь получит предупреждения во время установки, как указано, и предупреждения во время выполнения будут деактивированы для этого скрипта. Любые функции, которые не были объявлены, все равно будут вызывать предупреждения во время выполнения, и это будет еще более убедительным свидетельством уловки или небрежного кодирования. - person Brock Adams; 06.03.2012
comment
Ну, затенение конкретных плохих функций — это черный список, что немного беспокоит. Скорее всего, ваш черный список будет неполным. Черные списки имеют тенденцию быть хрупкими. - person D.W.; 07.03.2012
comment
@D.W., я тебя не понимаю. Я создаю эти функции и полностью контролирую их поведение во время выполнения (за исключением эксплойтов безопасности, о которых я не знаю). Как сценарист мог обойти это? - person Brock Adams; 07.03.2012
comment
@BrockAdams, если вы предоставляете только заведомо хорошие функции, вы в порядке (внесение в белый список). Если вы раскрываете все, но затем затеняете известные плохие, это хрупкое (черный список). Обычно в Javascript все доступно по умолчанию, и вы не можете запретить ненадежному коду получать доступ ко всему (через глобальный объект). Расширениям Firefox разрешено использовать evalInSandbox, что позволяет вызывающей стороне указать другой глобальный объект. Если вы используете evalInSandbox для указания глобального объекта, который предоставляет только заведомо исправные функции, вы в хорошей форме, но тогда вам не нужно затенение. - person D.W.; 09.03.2012
comment
Возможно, затенение - неправильный термин для этого, но этот ответ вдохновил на то, что на данный момент это лучший подход... То есть сама функция предупреждает пользователя (и, возможно, прерывает сценарий), если это не указано заранее в манифесте. (В этом случае пользователь получит только более мягкое предупреждение во время установки). - person Brock Adams; 09.03.2012
comment
@BrockAdams Я называю это слежкой, когда это делается намеренно, и затиранием, когда это непреднамеренно :) - person alex; 09.03.2012

Попытка просканировать сценарий, чтобы определить, использует ли он какой-либо из этих интерфейсов, является неправильным подходом. Слишком легко уклониться от запутывания, как вы, кажется, обнаруживаете. Это принципиально небезопасно: нет никакого способа заставить его работать.

Вот лучший подход. Требовать от сценариста включения манифеста, в котором объявляется, к каким специальным API ему нужен доступ. Затем запустите сценарий в защищенной песочнице Javascript, которая предоставляет доступ только к разрешенным API и запрошенным API, но не более того. Если скрипт не запрашивает GM_openSQL_Connection в своем манифесте, не предоставляйте этот API скрипту.

Поскольку Javascript — это динамический язык, допускающий внесение исправлений и неограниченный доступ к глобальному объекту, необходимо приложить некоторые усилия для создания безопасной изолированной программной среды, которая ограничивает доступ к API-интерфейсам сценария. Поэтому я рекомендую вам использовать существующее решение для песочницы. Один из подходов состоит в том, чтобы запустить пользовательский сценарий в песочнице и предоставить изолированному коду библиотеку, полную заглушек для конфиденциальных API, где заглушки просто используют postMessage для отправки запроса RPC в ваш код расширения. Это позволяет избежать ссылок, пересекающих границу песочницы, что хорошо, поскольку (в зависимости от технологии песочницы) такие ссылки обычно несут значительный потенциал для уязвимостей безопасности.

Затем вы можете управлять предупреждениями пользователей на основе содержимого манифеста. Важно: пожалуйста, внимательно подумайте об этом с точки зрения пользователя. Смогут ли простые пользователи понять предупреждения? Смогут ли они принимать разумные решения? Будут ли пользователи в лучшем положении для принятия правильных решений, чем вы? Будут ли пользователи ошеломлены постоянными предупреждениями и просто начнут игнорировать их и нажимать «ОК» (эффект волчьего крика)?

Информацию о технологии изолированной программной среды Javascript см. в следующем вопросе по ИТ-безопасности: Как сканировать Javascript на наличие вредоносного кода?. В будущем вы можете получить ответы на этот вопрос на сайте ИТ-безопасности.

person D.W.    schedule 07.03.2012
comment
Это бросает вызов всему, что я испытал или прочитал до сих пор. Предоставьте ссылку или пример того, как код скрипта может получить доступ к коду расширения (не коду скрипта содержимого) за пределами API, который может предоставлять расширение. - person Brock Adams; 08.03.2012
comment
Это не совсем архитектура и не совсем то, как работает Greasemonkey. Пользовательский скрипт устанавливается один раз, никогда не загружается на лету (во всяком случае, с отключенными обновлениями). И это не совсем просто evaled. Он запускается с использованием evalInSandbox после применения некоторых ограничений безопасности. Chrome использует аналогичный механизм, если я правильно понимаю. Ваши комментарии могут по-прежнему применяться, но я еще не видел документации или примера. - person Brock Adams; 08.03.2012
comment
@BrockAdams, хорошая мысль! Моя ошибка. Я отказываюсь от своих заявлений о необходимости специальной технологии песочницы (например, Caja). Я совсем забыл про evalInSandbox, так что я явно не так хорошо информирован, как думал. Мои извинения за мои ошибки. - person D.W.; 08.03.2012