Памятка по безопасности HTML5¶
Введение¶
Следующая памятка служит руководством по безопасной реализации HTML5.
API коммуникации¶
Web Messaging¶
Web Messaging (также известный как Cross Domain Messaging) предоставляет средства обмена сообщениями между документами из разных источников способом, который в целом безопаснее, чем многочисленные хаки, ранее использовавшиеся для выполнения этой задачи. Однако есть ряд рекомендаций, о которых следует помнить:
- При отправке сообщения явно указывайте ожидаемый источник в качестве второго аргумента
postMessageвместо*, чтобы предотвратить отправку сообщения неизвестному источнику после перенаправления или другого способа изменения источника целевого окна. - Принимающая страница должна всегда:
- Проверять атрибут
originотправителя для верификации того, что данные исходят из ожидаемого места. - Выполнять валидацию ввода атрибута
dataсобытия, чтобы убедиться, что он соответствует желаемому формату.
- Проверять атрибут
- Не думайте, что вы контролируете атрибут
data. Единственная уязвимость Cross Site Scripting на отправляющей странице позволяет злоумышленнику отправлять сообщения в любом формате. - Обе страницы должны интерпретировать передаваемые сообщения только как данные. Никогда не выполняйте переданные сообщения как код (например, через
eval()) и не вставляйте их в DOM страницы (например, черезinnerHTML), так как это создаст уязвимость XSS на основе DOM. Подробнее см. Памятку по предотвращению DOM-based XSS. - Для присвоения значения данных элементу вместо небезопасного метода
element.innerHTML=data;используйте более безопасный вариант:element.textContent=data; - Проверяйте источник точно, чтобы он соответствовал ожидаемым FQDN. Обратите внимание, что следующий код:
if(message.origin.indexOf(".owasp.org")!=-1) { /* ... */ }очень небезопасен и не будет работать должным образом, так какowasp.org.attacker.comбудет соответствовать шаблону. - Если вам нужно встроить внешний контент/ненадёжные виджеты и разрешить скрипты, контролируемые пользователем (что крайне не рекомендуется), обратитесь к информации о изолированных фреймах.
Cross Origin Resource Sharing¶
- Валидируйте URL, переданные в
XMLHttpRequest.open. Современные браузеры позволяют этим URL быть межсайтовыми; это поведение может привести к инъекции кода удалённым злоумышленником. Уделяйте особое внимание абсолютным URL. - Убедитесь, что URL, отвечающие с
Access-Control-Allow-Origin: *, не содержат никакого чувствительного содержимого или информации, которая может помочь злоумышленнику в дальнейших атаках. Используйте заголовокAccess-Control-Allow-Originтолько для выбранных URL, которым необходим межсайтовый доступ. Не используйте заголовок для всего домена. - Разрешайте только выбранные доверенные домены в заголовке
Access-Control-Allow-Origin. Предпочитайте указывать конкретные домены, а не блокировать или разрешать все домены (не используйте подстановочный символ*и не возвращайте содержимое заголовкаOriginвслепую без каких-либо проверок). - Имейте в виду, что CORS не предотвращает попадание запрошенных данных в несанкционированное место. По-прежнему важно, чтобы сервер выполнял обычную защиту от CSRF.
- Хотя стандарт Fetch рекомендует предварительный запрос с методом
OPTIONS, текущие реализации могут не выполнять этот запрос, поэтому важно, чтобы «обычные» запросы (GETиPOST) выполняли необходимый контроль доступа. - Отклоняйте запросы, полученные по обычному HTTP от источников с HTTPS, для предотвращения ошибок смешанного содержимого.
- Не полагайтесь только на заголовок Origin для проверок контроля доступа. Браузер всегда отправляет этот заголовок в CORS-запросах, но он может быть подделан вне браузера. Для защиты чувствительных данных следует использовать протоколы уровня приложений.
WebSockets¶
- Ознакомьтесь с Памяткой по безопасности WebSocket для изучения специфичных для WebSocket мер защиты.
Server-Sent Events¶
- Валидируйте URL, переданные в конструктор
EventSource, даже если разрешены только URL того же источника. - Как упоминалось ранее, обрабатывайте сообщения (
event.data) как данные и никогда не оценивайте содержимое как HTML или код скрипта. - Всегда проверяйте атрибут origin сообщения (
event.origin), чтобы убедиться, что сообщение поступает от доверенного домена. Используйте подход на основе белого списка.
Storage API¶
Local Storage¶
- Также известен как Offline Storage, Web Storage. Базовый механизм хранения может варьироваться от одного пользовательского агента к другому. Иными словами, любая аутентификация, которую требует ваше приложение, может быть обойдена пользователем с локальными привилегиями на машине, где хранятся данные. Поэтому рекомендуется избегать хранения любой конфиденциальной информации в локальном хранилище, где предполагалась бы аутентификация.
- Ввиду гарантий безопасности браузера уместно использовать локальное хранилище там, где доступ к данным не предполагает аутентификацию или авторизацию.
- Используйте объект sessionStorage вместо localStorage, если постоянное хранение не требуется. Объект sessionStorage доступен только для данного окна/вкладки до закрытия окна.
- Единственная уязвимость Cross Site Scripting может быть использована для кражи всех данных в этих объектах, поэтому снова рекомендуется не хранить конфиденциальную информацию в локальном хранилище.
- Единственная уязвимость Cross Site Scripting также может быть использована для загрузки вредоносных данных в эти объекты, поэтому не считайте объекты в них доверенными.
- Уделяйте особое внимание вызовам
localStorage.getItemиsetItem, реализованным на HTML5-странице. Это помогает обнаруживать случаи, когда разработчики создают решения, хранящие конфиденциальную информацию в локальном хранилище, что может быть серьёзным риском, если неправильно предполагается аутентификация или авторизация для этих данных. - Не храните идентификаторы сессии в локальном хранилище, так как данные всегда доступны через JavaScript. Cookie могут снизить этот риск с помощью флага
httpOnly. - Не существует способа ограничить видимость объекта определённым путём, как это делает атрибут path у HTTP cookie; каждый объект разделяется в пределах источника и защищён политикой одного источника (Same Origin Policy). Избегайте размещения нескольких приложений на одном источнике, так как все они будут использовать один объект localStorage; вместо этого используйте разные поддомены.
Клиентские базы данных¶
- В ноябре 2010 года W3C объявил Web SQL Database (реляционная SQL-база данных) устаревшей спецификацией. Активно разрабатывается новый стандарт Indexed Database API или IndexedDB (ранее WebSimpleDB), который обеспечивает хранилище ключ-значение и методы для выполнения сложных запросов.
- Базовые механизмы хранения могут варьироваться от одного пользовательского агента к другому. Иными словами, любая аутентификация, которую требует ваше приложение, может быть обойдена пользователем с локальными привилегиями на машине, где хранятся данные. Поэтому рекомендуется не хранить конфиденциальную информацию в локальном хранилище.
- При использовании содержимое WebDatabase на стороне клиента может быть уязвимо для SQL injection и требует надлежащей валидации и параметризации.
- Как и в случае с Local Storage, единственная уязвимость Cross Site Scripting может быть использована для загрузки вредоносных данных в веб-базу данных. Не считайте данные в ней доверенными.
Геолокация¶
- Geolocation API требует, чтобы пользовательские агенты запрашивали разрешение у пользователя перед определением местоположения. Способ запоминания и хранения этого решения варьируется от браузера к браузеру. Некоторые пользовательские агенты требуют, чтобы пользователь снова посетил страницу для отключения возможности получения геолокации без запроса, поэтому из соображений конфиденциальности рекомендуется требовать ввода пользователя перед вызовом
getCurrentPositionилиwatchPosition.
Web Workers¶
- Web Workers разрешено использовать объект
XMLHttpRequestдля выполнения внутридоменных и Cross Origin Resource Sharing запросов. Обратитесь к соответствующему разделу этой памятки для обеспечения безопасности CORS. - Хотя Web Workers не имеют доступа к DOM вызывающей страницы, вредоносные Web Workers могут использовать чрезмерный объём CPU для вычислений, что приводит к условию отказа в обслуживании, или злоупотреблять Cross Origin Resource Sharing для дальнейшей эксплуатации. Убедитесь, что код во всех скриптах Web Workers не является вредоносным. Не разрешайте создание скриптов Web Worker из данных, предоставленных пользователем.
- Валидируйте сообщения, обмениваемые с Web Worker. Не пытайтесь передавать фрагменты JavaScript для выполнения, например через
eval(), так как это может создать уязвимость DOM Based XSS.
Tabnabbing¶
Атака подробно описана в этой статье.
Кратко, это возможность воздействовать на содержимое или местоположение родительской страницы из вновь открытой страницы через обратную ссылку, предоставляемую экземпляром объекта JavaScript opener.
Это применимо к HTML-ссылке или функции JavaScript window.open, использующей атрибут/инструкцию target для указания целевого места загрузки, которое не заменяет текущее место и делает текущее окно/вкладку доступными.
Для предотвращения этой проблемы доступны следующие действия:
Разрыв обратной ссылки между родительской и дочерней страницами:
- Для HTML-ссылок:
- Для разрыва этой обратной ссылки добавьте атрибут
rel="noopener"на тег, используемый для создания ссылки с родительской страницы на дочернюю. Это значение атрибута разрывает ссылку, но в зависимости от браузера позволяет присутствовать информации о реферере в запросе к дочерней странице. - Для также удаления информации о реферере используйте это значение атрибута:
rel="noopener noreferrer".
- Для разрыва этой обратной ссылки добавьте атрибут
- Для функции JavaScript
window.openдобавьте значенияnoopener,noreferrerв параметр windowFeatures функцииwindow.open.
Поскольку поведение при использовании указанных элементов различается в разных браузерах, для открытия окна (или вкладки) используйте HTML-ссылку или JavaScript, а затем применяйте следующую конфигурацию для максимальной кросс-браузерной поддержки:
- Для HTML-ссылок добавляйте атрибут
rel="noopener noreferrer"ко всем ссылкам. - Для JavaScript используйте эту функцию для открытия окна (или вкладки):
function openPopup(url, name, windowFeatures){
//Открываем всплывающее окно и устанавливаем инструкции политики opener и referrer
var newWindow = window.open(url, name, 'noopener,noreferrer,' + windowFeatures);
//Сбрасываем ссылку на opener
newWindow.opener = null;
}
- Добавьте HTTP-заголовок ответа
Referrer-Policy: no-referrerк каждому HTTP-ответу, отправляемому приложением (Информация о заголовке Referrer-Policy). Эта конфигурация гарантирует, что информация о реферере не будет отправляться вместе с запросами со страницы.
Матрица совместимости:
Изолированные фреймы (Sandboxed frames)¶
- Используйте атрибут
sandboxуiframeдля ненадёжного содержимого. - Атрибут
sandboxуiframeвключает ограничения на содержимое внутриiframe. Следующие ограничения активны при установке атрибутаsandbox:- Всё содержимое обрабатывается как исходящее из уникального источника.
- Все формы и скрипты отключены.
- Все ссылки блокируются от нацеливания на другие контексты просмотра.
- Все функции, запускающиеся автоматически, блокируются.
- Все плагины отключены.
Возможен тонкий контроль над возможностями iframe с использованием значения атрибута sandbox.
- В старых версиях пользовательских агентов, где эта функция не поддерживается, атрибут будет проигнорирован. Используйте эту функцию в качестве дополнительного уровня защиты или проверяйте, поддерживает ли браузер изолированные фреймы, и показывайте ненадёжное содержимое только при наличии поддержки.
- Помимо этого атрибута, для предотвращения атак Clickjacking и нежелательного встраивания во фреймы рекомендуется использовать заголовок
X-Frame-Options, который поддерживает значенияdenyиsame-origin. Другие решения, такие как framebustingif(window!==window.top) { window.top.location=location;}, не рекомендуются.
Подсказки для ввода учётных данных и персональных данных (PII)¶
- Защитите вводимые значения от кэширования браузером.
При обращении к финансовому аккаунту с общедоступного компьютера следующий пользователь, даже после выхода из системы, может войти в аккаунт благодаря функции автозаполнения браузера. Для снижения этого риска мы указываем полям ввода не оказывать никакой помощи.
<input type="text" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></input>
Текстовые области и поля ввода для PII (имя, электронная почта, адрес, номер телефона) и учётных данных (имя пользователя, пароль) должны быть защищены от хранения браузером. Используйте эти HTML5-атрибуты для предотвращения хранения PII из формы браузером:
spellcheck="false"autocomplete="off"autocorrect="off"autocapitalize="off"
Офлайн-приложения¶
- Запрашивает ли пользовательский агент разрешение у пользователя на хранение данных для офлайн-просмотра и когда этот кэш удаляется — зависит от браузера. Отравление кэша является проблемой, если пользователь подключается через незащищённые сети, поэтому из соображений конфиденциальности рекомендуется требовать ввода пользователя перед отправкой каких-либо файлов
manifest. - Пользователи должны кэшировать только доверенные сайты и очищать кэш после работы через открытые или незащищённые сети.
Риски прогрессивного улучшения и постепенного ухудшения¶
- Лучшей практикой сейчас является определение возможностей, которые поддерживает браузер, и дополнение заменой для возможностей, которые не поддерживаются напрямую. Это может означать многоуровневый элемент, например переход к Flash Player, если тег
<video>не поддерживается, или дополнительный скриптовый код из различных источников, который следует проверять в ходе код-ревью.
HTTP-заголовки для повышения безопасности¶
Обратитесь к проекту OWASP Secure Headers для получения списка HTTP-заголовков безопасности, которые приложение должно использовать для включения защиты на уровне браузера.