3 Июня, 2013

Browser Security Handbook. Глава 1, пункт 8

Сергей Сторчак
Руководство по безопасности браузеров (Browser Security Handbook). Глава 1

8.  Браузерный Javascript  

   JavaScript - относительно простой, но богатый прототипно-ориентированный сценарный язык программирования, тесно интегрированный с HTML и поддерживаемый всеми современными браузерами. Название «JavaScript» - это просто маркетинговый ход, придуманный Netscape и Sun в 90-е годы. Авторы утверждают, что JavaScript берет свое начало от языков программирования Scheme и Self , хотя его часто характеризуют как скрещенный C/C++ и Visual Basic . Помимо схожести с Cи, он перенял некоторые функции языка Java .

   Язык является детищем компании Netscape. Первоначально на рынке он был известен под именем «Mocha», затем «Livescript», и, наконец, «JavaScript»; Microsoft выпустила аналог языка JavaScript, названный JScript. По инициативе компании Netscape была проведена стандартизация языка ассоциацией ECMA. Стандартизированная версия имеет название ECMAScript и описывается стандартом ECMA-262 .

   Браузерный JavaScript может быть вызван из HTML-документов четырьмя основными способами:
1. Автономным тегом <script>, расположенным в блоке кода.
2. Обработчиком событий, привязанным к тегам (например, onmouseover="...").
3. Блоком таблицы стилей expression(...) в некоторых браузерах, которые пропускают JavaScript-синтаксис.
4. Специальными URL-протоколами, указанными в качестве цели для определенных ресурсов или действия (javascript:...) - в HTML и таблицах стилей.

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

Независимо от их источника (<script src ="...">), удаленные скрипты всегда выполняются в контексте безопасности документа, к которому они прикреплены. JavaScript имеет полный доступ к текущему DOM, а также ограниченный доступ к DOM других окон; это может вызвать новые JavaScript путем вызова eval(), настройки таймера (setTimeout(...)и setInterval(...)), или путем создания JavaScript, используя HTML. JavaScript может также запуститься при взаимодействии его объектов со сторонним JavaScript-кодом сценария, настраивая часы, сеттеры (мутаторы) или геттеры (получатели) , или пересекающийся контекст, вызывая функции того же источника, принадлежащие другим документам. 

JavaScriptимеет очень ограниченные возможности загрузки и вывода. Существует не так много доступных средств ввода-вывода для взаимодействия с данными документа и графикой CANVASec , отображения всплывающих диалоговых окон и записи консольных ошибок сценария. Операции с файлами и доступ к другому постоянному хранению, как правило, не возможны, несмотря на то, что некоторые экспериментальные функции вводятся и быстро отбраковываются. Сценарии могут отправлять и получать данные с исходного сервера, используя расширение XMLHttpRequest

Другими важнейшими характеристиками безопасности среды JavaScript в современных браузерах являются:

- Динамическая интерпретация исполняемого кода без строгих правил кэширования.Любые фрагменты кода, содержащиеся в тегах, будут интерпретированы и исполнены, и JavaScript имеет возможность оценить строки как JavaScript-код (eval (...)), или создать новый HTML, который, в свою очередь, может содержать другие сценарии (свойства .innerHTML и .outerHTML, document.write(), обработчики событий). Поведение кода, которое пытается изменить собственный контейнер во время выполнения (через DOM), определено нечетко и в разных браузерах отличается.

- Несколько противоречивая поддержка исключений. Несмотря на то, что в самом языке, условия для исключений хорошо определены, при взаимодействии с DOM-структурой это не работает. В зависимости от обстоятельств, некоторые операции с DOM могут не выполняться (игнорируется команда редактирования или чтения), возвращаться необычные ответы (undefined, null, object inaccessible), выдаваться нестандартизированные исключения, или даже безоговорочно прерываться выполнение.

- Несколько противоречивые, но модифицируемые встроенные команды и прототипы. Поведение многих языковых конструкций может быть переопределено программами в текущем контексте путем изменения объектов (сеттеров, геттеров) или перезаписью прототипов. Из-за этого рискованно полагаться на какой-либо конкретный код (например, проверку безопасности), выполняющийся предсказуемым способом в непосредственной близости от потенциально вредоносной полезной нагрузки. Однако не все встроенные объекты могут быть легко подделаны, например, Array - прототип сеттеров - может изменяться, но не так как XML. В JavaScript 1.x есть все необходимые для жизни операторы, хотя нет их перегрузки .

- Обычное синхронное выполнение. В пределах одного документа, на стороне браузера JavaScript обычно выполняется синхронно и в едином потоке, и асинхронным событиям таймера не разрешается запускаться до тех пор, пока механизм выполнения сценариев не введет состояние ожидания. Не существует никаких гарантий синхронного выполнения, однако, многопроцессорный рендеринг Chrome и MSIE8 позволяет осуществлять междоменный доступ более асинхронно.

- Глобальные функциональные поиски не зависят от упорядочивания или потока выполнения.Функции могут быть вызваны в блоке кода прежде, чем они будут определены и проиндексированы. Поэтому доверять операторам, таким, как while (1);для предотвращения последующего интерпретированного кода, может быть рискованно.

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

- Быстро развивающийся синтаксис. Например, в Firefoxрасширение языка программирование « ECMAScript for XML (E4X) » добавляет встроенную поддержку XML в JavaScript . Трудно представить, что какой-то формат данных будет не допустим JavaScript-синтаксисом в будущем.


Встроенные в HTML блоки сценария, сложнее удалить, если разрешено содержать управляемые пользователями строки, потому что, такие теги как <TEXTAREA>, <STYLE>и некоторые другие теги, идут за нелогичным анализом CDATA-style: последовательность литерала </SCRIPT> заканчивает блоком сценария независимо от своего расположения в синтаксисе JavaScript. Например, следующий блок кода завершится преждевременно и приведет к несанкционированному, дополнительному выполнению JavaScript-блока:

<SCRIPT>
var user_string ='Hello world</SCRIPT><SCRIPT>alert(1)</SCRIPT>';
</SCRIPT>

Грубо говоря, стандарт HTML4 определяет, что любая</...последовательность, (такая, как <SCRIPT>) может быть использована для высвобождения из блока . На практике, браузеры этому примеру не следуют и взамен требуют строку с литералом </SCRIPT>. Однако, на эту способность полагаться не безопасно. 


Некоторые отличительные особенности браузеров приведены в таблице№10:
Таблица№10
Описание теста
MSIE7
MSIE8
FF3
Safari
Opera
Chrome
Android
Поддерживаются ли в настоящее время сеттеры и геттеры?
НЕТ
НЕТ
ДА
ДА
ДА
ДА
ДА
Возможен ли доступ к прототипам через __proto__?
НЕТ
НЕТ
ДА
ДА
НЕТ
ДА
ДА
Возможен ли псевдоним функции eval()?
ДА
ДА
ЧАСТИЧНО
ДА
ЧАСТИЧНО
ДА
ДА
Поддерживается ли объектами метод watch?
НЕТ
НЕТ
ДА
НЕТ
НЕТ
НЕТ
НЕТ
Могут ли в настоящем времени исполняемые блоки кода самостоятельно измениться?
только для чтения
только для чтения
НЕТ
НЕТ
ДА
НЕТ
НЕТ
Поддерживается ли E4X-расширение?
НЕТ
НЕТ
ДА
НЕТ
НЕТ
НЕТ
НЕТ
charset=соблюдается в <SCRIPTSRC="...">?
(Ischarset=honoredon<SCRIPTSRC="...">?)
ДА
ДА
ДА
ДА
НЕТ
ДА
ДА
Unicode-символы новой строки (U+2028, U+2029) разбивают строки в Javascript?
НЕТ
НЕТ
ДА
ДА
ДА
ДА
ДА

Общая информация: программы на Javascriptмогут инициировать или перехватывать различные элементы (такие как мышь и клавиатуру) в пределах окна. Это может нарушить работу других механизмов защиты, таких как "защищенное" поле <INPUT TYPE=FILE ...>или HTML-фреймы с другого источника. Во время проектирования этим взаимодействиям было уделено недостаточно внимания, что привело к проблемам реализации в современных браузерах. 

Кодировка символов в Javascript

Для обработки строк, содержащих строковые литералы, такие как </SCRIPT>, ", ', CLили LF идругие непечатаемые символы, JavaScript предлагает пять схем кодирования символов:

1. 8-разрядное восьмеричное числовое представление, содержащее три цифры, дополненное нулем, Си-стиль (C-style) ("test"