Pull to refresh

UserJS. Часть 3: Безопасность

Reading time2 min
Views1.3K
В этой статье описывается, чем опасны некоторые userjs трюки и как с этой опасностью справиться.

Другие статьи серии:

LiveConnect


Опасность этой технологии очевидна. Как только Вы разрешаете доступ с некоторого адреса к расширенным возможностям (например, работать с буфером обмена), как все скрипты с этого адреса могут использовать расширенные возможности в своих целях (например, отсылать содержимое буфера на сайт — вдруг там пароль).

Решение состоит в том, чтобы разрешить доступ только одному адресу — «http://0.0.0.0/», открыть фрейм с этим адресом и все действия производить через XDM. Неудобство состоит в том, что все вызовы становятся асинхронными. Но чего не сделаешь ради безопасности. Да и есть в этом некоторый плюс — скрипты на странице не повиснут в ожидании какого-нибудь долгого синхронного вызова.

Теперь нужно обезопасить XDM.

XDM


Любой скрипт на странице может найти iframe и отправить ему сообщение. Достаточно лишь знать формат сообщений. Узнать — не проблема, если userjs выложен в сети. Да даже если userjs написан Вами и для себя, часто формат угадать несложно.

Итак, задача — сделать формат неугадываемым. Для этого нужно:
  • для каждого пользователя сгенерировать пароль;
  • добавлять в начало каждого сообщения;
  • использовать событие «BeforeEvent.message», чтобы мы первым узнавали о сообщении;
  • обрабатывать только сообщения с подходящим паролем;
  • использовать функцию «Event.preventDefault» для предотвращения получения сообщений скриптом на странице.


Консервируем функции


Но и этого ещё недостаточно для обеспечения безопасности.

К сожалению, userjs выполняются в контексте страницы. А значит все модификации объектов скриптами со страницы отражаются и на userjs.

Предположим, что проверка пароля в userjs производится следующим образом:
if (ev.data.substring(0, password.length) == password) { ... }


Тогда скрипт на странице может выполнить:
String.prototype.substring = function(start, len) { alert(this); }

и получить пароль!

Необходимо сохранить функции, используемые в критических местах userjs:
// В самом начале скрипта.
var functionCall = Function.prototype.call;
var stringSubstring = String.prototype.substring;

// В обработчике события.
stringSubstring.call = functionCall;
if (stringSubstring.call(ev.data, 0, password.length) == password) { ... }
Tags:
Hubs:
Total votes 16: ↑14 and ↓2+12
Comments0

Articles