понедельник, 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, которое позволяет сценариям передавать и читать произвольные полезные нагрузки; могут также автоматически отправлять запросы и считывать правильно отформатированные ответы на выдачу <script src ="..."> или <link rel ="stylesheet" href="..."> даже между доменами. Наконец, JavaScript может отправлять информацию на сторонние серверы, порождая такие объекты, как <img>, <iframe>, <object>, <applet>, или перенаправлять на другую страницу и одновременно автоматически кодировать информацию в URL, - но сценарий не может читать возвращаемые данные. Некоторые побочные каналы связанны с механизмами кэширования браузера и проверки безопасности DOM обеспечивают дополнительные побочные каналы между взаимодействующими сторонами.

Другими важнейшими характеристиками безопасности среды 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= соблюдается в <SCRIPT SRC="...">?
(Is charset= honored on <SCRIPT SRC="...">?)
ДА
ДА
ДА
ДА
НЕТ
ДА
ДА
Unicode-символы новой строки (U+2028, U+2029) разбивают строки в Javascript?
НЕТ
НЕТ
ДА
ДА
ДА
ДА
ДА

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

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

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

1. 8-разрядное восьмеричное числовое представление, содержащее три цифры, дополненное нулем, Си-стиль (C-style) ("test" → "t\145st"),
2. 8-разрядное шестнадцатеричное числовое представление, содержащее две цифры, дополненное нулем, C-style с префиксом \х ("test" → "t\x65st"),
3. 16-разрядное шестнадцатеричное числовое Unicode-представление, содержащее четыре цифры, дополненное нулем, с префиксом \u ("test" → "t\u0065st"),
4. префикс \  перед литералом ("test""t\est"),
5. Специальное сокращенное обозначение Cи-стиля \ для некоторых управляющих символов (таких как \n или \t).

   Четвертая схема является наиболее компактной, хотя и подвержена ошибкам; например, неспособность избежать \ как \\ может привести к строке \" + alert(1);" преобразованной из \\" + alert(1), и будет неправильно интерпретирована; это также частично пересекается с оставшимся \-префиксом выходом из метода, и не совместима с синтаксисом языка C.

   Анализ этих схем универсален для всех браузеров, когда введено меньшее количество цифр, чем требуется: значение интерпретируется правильно, и никакой последующий текст не используется ("\1test" принят, и становится "\001test").

    Кодирование HTML-объектов не имеют особого значения внутри блоков <SCRIPT>.

   Забавно, несмотря на то, что все четыре вышеупомянутых схемы поддерживаются в JavaScript, предлагаемый информационный стандарт для представления объектов JavaScript (JSON) и транспортно-ориентированная схема сериализации для объектов и массивов JavaScript (RFC 4627) технически допускают только \u запись и, по-видимому, произвольное подмножество \ сокращенных кодов управляющего символа (варианты 3 и 5 в списке схем кодирования символов). Поскольку формат JSON является подмножеством синтаксиса языка JavaScript, то он может быть быстро десериализован встроенной функцией eval(). Кроме того, возможна вставка вполне работоспособных JavaScript-функций. Однако, из-за рекомендаций, приведенных в документе RFC, некоторое несвойственное выполнение parseJSON может неправильно обрабатывать обычные \х управляющие символы. Также не определено, по какой схеме будут следовать браузеры. В настоящее время рассмотрены собственные, не исполняющие анализаторы предложенные для повышения производительности и безопасности. 

   В отличие от некоторых реализаций C, в JavaScript отдельные многострочные строковые литералы не разрешены, но отдельный \ в конце строки, может быть использован для разбиения длинных строк. 

Комментариев нет:

Отправка комментария