Политика безопасности контента

Модель безопасности Интернета основана на политике единого происхождения . Код https://mybank.com должен иметь доступ только к данным https://mybank.com , а https://evil.example.com никогда не должен иметь доступа. Каждый источник изолирован от остальной сети, что дает разработчикам безопасную «песочницу», в которой можно создавать и играть. В теории это совершенно гениально. На практике злоумышленники нашли хитрые способы подорвать систему.

Например, атаки с использованием межсайтовых сценариев (XSS) обходят ту же политику происхождения, заставляя сайт доставлять вредоносный код вместе с предполагаемым контентом. Это огромная проблема, поскольку браузеры доверяют всему коду, который отображается на странице, как законной части источника безопасности этой страницы. Шпаргалка XSS — это старый, но репрезентативный набор методов, которые злоумышленник может использовать для нарушения этого доверия путем внедрения вредоносного кода. Если злоумышленник вообще успешно внедряет какой-либо код, игра практически окончена: данные сеанса пользователя скомпрометированы, а информация, которую следует хранить в секрете, попадает в руки The Bad Guys. Мы, очевидно, хотели бы предотвратить это, если это возможно.

В этом обзоре освещается защита, которая может значительно снизить риск и влияние XSS-атак в современных браузерах: политика безопасности контента (CSP).

ТЛ;ДР

  • Используйте списки разрешенных, чтобы сообщить клиенту, что разрешено, а что нет.
  • Узнайте, какие директивы доступны.
  • Изучите ключевые слова, которые они берут.
  • Встроенный код и eval() считаются вредными.
  • Сообщайте о нарушениях политики на свой сервер, прежде чем применять их.

Белые списки источников

Проблема, используемая XSS-атаками, заключается в неспособности браузера отличить скрипт, являющийся частью вашего приложения, от скрипта, злонамеренно внедренного третьей стороной. Например, кнопка Google +1 внизу этой страницы загружает и выполняет код из https://apis.google.com/js/plusone.js в контексте источника этой страницы. Мы доверяем этому коду, но не можем ожидать, что браузер сам определит, что код с apis.google.com хорош, а код с apis.evil.example.com скорее всего, нет. Браузер с радостью загружает и выполняет любой код, запрашиваемый страницей, независимо от источника.

Вместо того, чтобы слепо доверять всему , что доставляет сервер, CSP определяет HTTP-заголовок Content-Security-Policy , который позволяет вам создать список разрешенных источников доверенного контента, и дает браузеру указание выполнять или отображать ресурсы только из этих источников. Даже если злоумышленник сможет найти дыру, через которую можно внедрить сценарий, сценарий не будет соответствовать списку разрешений и, следовательно, не будет выполнен.

Поскольку мы доверяем apis.google.com в предоставлении допустимого кода и уверены, что сделаем то же самое, давайте определим политику, которая разрешает выполнение скриптов только в том случае, если они получены из одного из этих двух источников:

Content-Security-Policy: script-src 'self' https://apis.google.com

Просто, правда? Как вы, наверное, догадались, script-src — это директива, которая управляет набором привилегий, связанных со сценарием, для конкретной страницы. Мы указали 'self' в качестве одного допустимого источника скрипта, а https://apis.google.com в качестве другого. Браузер корректно загружает и выполняет JavaScript с apis.google.com через HTTPS, а также из источника текущей страницы.

Ошибка консоли: отказался загружать сценарий «http://evil.example.com/evil.js», поскольку он нарушает следующую директиву политики безопасности контента: script-src «self» https://apis.google.com

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

Политика применяется к широкому спектру ресурсов

Хотя ресурсы сценариев представляют собой наиболее очевидную угрозу безопасности, CSP предоставляет богатый набор директив политики, которые обеспечивают достаточно детальный контроль над ресурсами, которые странице разрешено загружать. Вы уже видели script-src , поэтому концепция должна быть ясна.

Давайте быстро пройдемся по остальным директивам ресурсов. Список ниже представляет состояние директив на уровне 2. Спецификация уровня 3 была опубликована, но в основном не реализована в основных браузерах.

  • base-uri ограничивает URL-адреса, которые могут отображаться в элементе <base> страницы.
  • child-src перечисляет URL-адреса рабочих процессов и встроенное содержимое фрейма. Например: child-src https://youtube.com позволит встраивать видео с YouTube, но не из других источников.
  • connect-src ограничивает источники, к которым вы можете подключиться (через XHR, WebSockets и EventSource).
  • font-src указывает источники, которые могут обслуживать веб-шрифты. Веб-шрифты Google можно включить через font-src https://themes.googleusercontent.com .
  • form-action перечисляет допустимые конечные точки для отправки из тегов <form> .
  • frame-ancestors указывает источники, в которые можно встроить текущую страницу. Эта директива применяется к тегам <frame> , <iframe> , <embed> и <applet> . Эту директиву нельзя использовать в тегах <meta> , она применяется только к ресурсам, отличным от HTML.
  • frame-src устарел на уровне 2, но восстанавливается на уровне 3. Если он отсутствует, он все равно возвращается к child-src как и раньше.
  • img-src определяет источники, из которых можно загружать изображения.
  • media-src ограничивает источники, которым разрешено доставлять видео и аудио.
  • object-src позволяет управлять Flash и другими плагинами.
  • plugin-types ограничивают типы плагинов, которые может вызывать страница.
  • report-uri указывает URL-адрес, по которому браузер будет отправлять отчеты при нарушении политики безопасности контента. Эту директиву нельзя использовать в тегах <meta> .
  • style-src это аналог script-src для таблиц стилей.
  • upgrade-insecure-requests предписывает пользовательским агентам переписать схемы URL-адресов, заменив HTTP на HTTPS. Эта директива предназначена для веб-сайтов с большим количеством старых URL-адресов, которые необходимо переписать.
  • worker-src — это директива CSP уровня 3, которая ограничивает URL-адреса, которые могут быть загружены как рабочий, общий или сервисный работник. По состоянию на июль 2017 года эта директива имеет ограниченное применение .

По умолчанию директивы широко открыты. Если вы не установили конкретную политику для директивы, скажем, font-src , то эта директива по умолчанию ведет себя так, как если бы вы указали * в качестве допустимого источника (например, вы можете загружать шрифты откуда угодно, без ограничений). .

Вы можете переопределить это поведение по умолчанию, указав директиву default-src . Эта директива определяет значения по умолчанию для большинства директив, которые вы оставляете неуказанными. Как правило, это относится к любой директиве, оканчивающейся на -src . Если для default-src установлено значение https://example.com и вы не указали директиву font-src , вы можете загружать шрифты с https://example.com и нигде больше. В наших предыдущих примерах мы указали только script-src , что означает, что изображения, шрифты и т. д. могут быть загружены из любого источника.

Следующие директивы не используют default-src в качестве запасного варианта. Помните, что не установить их — это то же самое, что разрешить что-либо.

  • base-uri
  • form-action
  • frame-ancestors
  • plugin-types
  • report-uri
  • sandbox

Вы можете использовать столько или меньше этих директив, сколько имеет смысл для вашего конкретного приложения, просто перечисляя каждую из них в заголовке HTTP, разделяя директивы точкой с запятой. Убедитесь, что вы перечислили все необходимые ресурсы определенного типа в одной директиве. Если вы написали что-то вроде script-src https://host1.com; script-src https://host2.com вторая директива будет просто проигнорирована. Что-то вроде следующего правильно укажет оба источника как действительные:

script-src https://host1.com https://host2.com

Если, например, у вас есть приложение, которое загружает все свои ресурсы из сети доставки контента (скажем, https://cdn.example.net ), и вы знаете, что вам не нужен какой-либо контент или плагины в рамках, то ваш политика может выглядеть примерно так:

Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'

Детали реализации

Вы увидите заголовки X-WebKit-CSP и X-Content-Security-Policy в различных руководствах в Интернете. В дальнейшем вам следует игнорировать эти заголовки с префиксами. Современные браузеры (за исключением IE) поддерживают заголовок Content-Security-Policy без префикса. Это заголовок, который вы должны использовать.

Независимо от используемого вами заголовка, политика определяется для каждой страницы: вам нужно будет отправлять HTTP-заголовок вместе с каждым ответом, защиту которого вы хотите обеспечить. Это обеспечивает большую гибкость, поскольку вы можете точно настроить политику для конкретных страниц в соответствии с их конкретными потребностями. Возможно, на одном наборе страниц вашего сайта есть кнопка +1, а на других нет: вы можете разрешить загрузку кода кнопки только при необходимости.

Список источников в каждой директиве является гибким. Вы можете указать источники по схеме ( data: , https: ) или по специфичности от имени хоста ( example.com , что соответствует любому источнику на этом хосте: любая схема, любой порт) до полного URI ( https://example.com:443 , что соответствует только HTTPS, только example.com и только порту 443). Подстановочные знаки принимаются, но только в виде схемы, порта или в крайнем левом положении имени хоста: *://*.example.com:* будет соответствовать всем поддоменам example.com (но не самому example.com ), по любой схеме, на любом порту.

Список источников также принимает четыре ключевых слова:

  • 'none' , как и следовало ожидать, не соответствует ничему.
  • 'self' соответствует текущему источнику, но не его поддоменам.
  • 'unsafe-inline' позволяет использовать встроенный JavaScript и CSS. (Чуть позже мы коснемся этого более подробно.)
  • 'unsafe-eval' поддерживает механизмы преобразования текста в JavaScript, такие как eval . (К этому мы тоже доберемся.)

Эти ключевые слова требуют одинарных кавычек. Например, script-src 'self' (с кавычками) разрешает выполнение JavaScript с текущего хоста; script-src self (без кавычек) разрешает JavaScript с сервера с именем « self » (а не с текущего хоста), что, вероятно, не то, что вы имели в виду.

Песочница

Есть еще одна директива, о которой стоит поговорить: sandbox . Он немного отличается от других, которые мы рассматривали, поскольку накладывает ограничения на действия, которые может выполнять страница, а не на ресурсы, которые страница может загружать. Если директива sandbox присутствует, страница обрабатывается так, как если бы она была загружена внутри <iframe> с атрибутом sandbox . Это может иметь широкий спектр последствий для страницы: принудительное присвоение странице уникального источника и предотвращение отправки формы, среди прочего. Это немного выходит за рамки данной статьи, но вы можете найти полную информацию о допустимых атрибутах песочницы в разделе «Песочница» спецификации HTML5 .

Мета-тег

Предпочтительным механизмом доставки CSP является заголовок HTTP. Однако может быть полезно установить политику на странице непосредственно в разметке. Сделайте это, используя тег <meta> с атрибутом http-equiv :

<meta
  http-equiv="Content-Security-Policy"
  content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>

Это нельзя использовать для frame-ancestors , report-uri или sandbox .

Встроенный код считается вредным

Должно быть ясно, что CSP основан на происхождении списков разрешений, поскольку это недвусмысленный способ указать браузеру рассматривать определенные наборы ресурсов как приемлемые и отклонять остальные. Однако белые списки на основе источника не устраняют самую большую угрозу, которую представляют XSS-атаки: внедрение встроенных скриптов. Если злоумышленник может внедрить тег сценария, который непосредственно содержит вредоносную полезную нагрузку ( <script>sendMyDataToEvilDotCom();</script> ), у браузера не будет механизма, с помощью которого можно было бы отличить его от законного встроенного тега сценария. CSP решает эту проблему, полностью запрещая встроенные сценарии: это единственный способ быть уверенным.

Этот запрет распространяется не только на скрипты, встроенные непосредственно в теги script , но также на встроенные обработчики событий и URL-адреса javascript: Вам потребуется переместить содержимое тегов script во внешний файл и заменить URL-адреса javascript: и <a ... onclick="[JAVASCRIPT]"> соответствующими вызовами addEventListener() . Например, вы можете переписать следующее:

<script>
  function doAmazingThings() {
    alert('YOU AM AMAZING!');
  }
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>

что-то вроде:

<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>

<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
  alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
  document.getElementById('amazing').addEventListener('click', doAmazingThings);
});

Переписанный код имеет ряд преимуществ помимо хорошей работы с CSP; это уже лучшая практика, независимо от того, используете ли вы CSP. Встроенный JavaScript смешивает структуру и поведение именно так, как не следует. Внешние ресурсы легче кэшировать браузерам, они более понятны разработчикам и удобны для компиляции и минимизации. Вы напишете лучший код, если проделаете работу по перемещению кода во внешние ресурсы.

Встроенный стиль обрабатывается таким же образом: как атрибут style , так и теги style должны быть объединены во внешние таблицы стилей, чтобы защититься от множества удивительно умных методов кражи данных, которые допускает CSS.

Если вам необходим встроенный скрипт и стиль, вы можете включить его, добавив 'unsafe-inline' в качестве разрешенного источника в директиве script-src или style-src . Вы также можете использовать одноразовый номер или хэш (см. ниже), но на самом деле не следует этого делать. Запрет встроенного сценария — это самый большой выигрыш в безопасности, который обеспечивает CSP, а запрет встроенного стиля также повышает безопасность вашего приложения. Требуется немного усилий, чтобы гарантировать, что все работает правильно после перемещения всего кода за пределы строки, но это компромисс, на который стоит пойти.

Если вам абсолютно необходимо использовать его

Уровень 2 CSP обеспечивает обратную совместимость для встроенных сценариев, позволяя добавлять определенные встроенные сценарии в список разрешений, используя либо криптографический одноразовый номер (число, используемое один раз), либо хэш. Хотя это может быть обременительно, в крайнем случае это полезно.

Чтобы использовать nonce, присвойте тегу скрипта атрибут nonce. Его значение должно совпадать с одним в списке доверенных источников. Например:

<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  // Some inline code I can't remove yet, but need to asap.
</script>

Теперь добавьте nonce в директиву script-src добавленную к ключевому слову nonce- .

Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'

Помните, что одноразовые номера должны генерироваться повторно для каждого запроса страницы, и они не должны быть угадываемыми.

Хэши работают примерно так же. Вместо добавления кода в тег скрипта создайте SHA-хеш самого скрипта и добавьте его в директиву script-src . Например, предположим, что ваша страница содержит следующее:

<script>
  alert('Hello, world.');
</script>

Ваша политика будет содержать это:

Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

Здесь следует отметить несколько вещей. Префикс sha*- указывает алгоритм, генерирующий хэш. В приведенном выше примере используется sha256- . CSP также поддерживает sha384- и sha512- . При создании хеша не включайте теги <script> . Также имеют значение капитализация и пробелы, включая начальные или конечные пробелы.

Поиск в Google по созданию хешей SHA приведет вас к решениям на любом количестве языков. Используя Chrome 40 или более позднюю версию, вы можете открыть DevTools, а затем перезагрузить страницу. Вкладка «Консоль» будет содержать сообщения об ошибках с правильным хешем sha256 для каждого встроенного скрипта.

Ивал тоже

Даже если злоумышленник не может внедрить скрипт напрямую, он может обманом заставить ваше приложение преобразовать в противном случае инертный текст в исполняемый код JavaScript и выполнить его от его имени. eval() , new Function() , setTimeout([string], ...) и setInterval([string], ...) — все это векторы, через которые внедренный текст может в конечном итоге выполнить что-то неожиданно вредоносное. Реакция CSP по умолчанию на этот риск — полная блокировка всех этих векторов.

Это оказывает немалое влияние на способ создания приложений:

  • Вы должны анализировать JSON с помощью встроенного JSON.parse , а не полагаться на eval . Собственные операции JSON доступны в каждом браузере, начиная с IE8 , и они полностью безопасны.
  • Перепишите все вызовы setTimeout или setInterval , которые вы сейчас выполняете, используя встроенные функции, а не строки. Например:
setTimeout("document.querySelector('a').style.display = 'none';", 10);

лучше было бы написать так:

setTimeout(function () {
  document.querySelector('a').style.display = 'none';
}, 10);
  • Избегайте встроенных шаблонов во время выполнения: многие библиотеки шаблонов широко используют new Function() для ускорения создания шаблонов во время выполнения. Это отличное применение динамического программирования, но оно сопряжено с риском оценки вредоносного текста. Некоторые платформы поддерживают CSP «из коробки», возвращаясь к надежному синтаксическому анализатору при отсутствии eval . Директива ng-csp AngularJS является хорошим примером этого.

Однако лучшим выбором будет язык шаблонов, который предлагает предварительную компиляцию (например, Handlebars ). Предварительная компиляция шаблонов может сделать работу пользователя даже быстрее, чем самая быстрая реализация во время выполнения, а также безопаснее. Если eval и его собратья по преобразованию текста в JavaScript необходимы для вашего приложения, вы можете включить их, добавив 'unsafe-eval' в качестве разрешенного источника в директиве script-src , но мы настоятельно не рекомендуем это делать. Запрет на выполнение строк значительно усложняет злоумышленнику выполнение неавторизованного кода на вашем сайте.

Составление отчетов

Способность CSP блокировать ненадежные ресурсы на стороне клиента — огромная победа для ваших пользователей, но было бы весьма полезно отправить какое-то уведомление обратно на сервер, чтобы вы могли выявить и устранить любые ошибки, которые допускают вредоносное внедрение в первую очередь. место. С этой целью вы можете указать браузеру POST отчеты о нарушениях в формате JSON в папку, указанную в директиве report-uri .

Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

Эти отчеты будут выглядеть примерно следующим образом:

{
  "csp-report": {
    "document-uri": "http://example.org/page.html",
    "referrer": "http://evil.example.com/",
    "blocked-uri": "http://evil.example.com/evil.js",
    "violated-directive": "script-src 'self' https://apis.google.com",
    "original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
  }
}

Он содержит большой объем информации, которая поможет вам отследить конкретную причину нарушения, включая страницу, на которой произошло нарушение ( document-uri ), реферер этой страницы (обратите внимание, что в отличие от поля заголовка HTTP, ключ не является с ошибкой), ресурс, нарушивший политику страницы ( blocked-uri ), конкретную директиву, которую он нарушил ( violated-directive ), и полную политику страницы ( original-policy ).

Только отчет

Если вы только начинаете работать с CSP, имеет смысл оценить текущее состояние вашего приложения, прежде чем внедрять драконовскую политику для своих пользователей. В качестве шага к полному развертыванию вы можете попросить браузер отслеживать политику, сообщая о нарушениях, но не обеспечивая соблюдение ограничений. Вместо отправки заголовка Content-Security-Policy отправьте заголовок Content-Security-Policy-Report-Only .

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;

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

Использование в реальном мире

CSP 1 вполне пригоден для использования в Chrome, Safari и Firefox, но имеет очень ограниченную поддержку в IE 10. Подробности можно просмотреть на сайте caniuse.com . CSP Level 2 доступен в Chrome начиная с версии 40. Массовые сайты, такие как Twitter и Facebook, развернули заголовок ( пример использования Twitter стоит прочитать), и стандарт вполне готов к тому, что вы можете начать его развертывание на своих собственных сайтах.

Первым шагом на пути к разработке политики для вашего приложения является оценка ресурсов, которые вы фактически загружаете. Как только вы решите, что разбираетесь в том, как все собирается в вашем приложении, настройте политику, основанную на этих требованиях. Давайте рассмотрим несколько распространенных случаев использования и определим, как лучше всего обеспечить их поддержку в рамках защиты CSP.

Вариант использования №1: виджеты социальных сетей

  • Кнопка Google +1 включает скрипт из https://apis.google.com и встраивает <iframe> из https://plusone.google.com . Чтобы встроить кнопку, вам нужна политика, включающая оба этих источника. Минимальная политика: script-src https://apis.google.com; child-src https://plusone.google.com . Вам также необходимо убедиться, что фрагмент JavaScript, предоставляемый Google, вынесен во внешний файл JavaScript. Если у вас была политика уровня 1 с использованием frame-src уровень 2 требовал, чтобы вы изменили ее на child-src . На уровне CSP 3 в этом больше нет необходимости.

  • Кнопка «Мне нравится» в Facebook имеет несколько вариантов реализации. Мы рекомендуем придерживаться версии <iframe> , поскольку она надежно изолирована от остальной части вашего сайта. Для правильной работы требуется директива child-src https://facebook.com . Обратите внимание, что по умолчанию код <iframe> , предоставляемый Facebook, загружает относительный URL-адрес //facebook.com . Измените это, чтобы явно указать HTTPS: https://facebook.com . Нет смысла использовать HTTP, если в этом нет необходимости.

  • Кнопка «Твитнуть» в Твиттере опирается на доступ к сценарию и фрейму, оба размещены на https://platform.twitter.com . (Twitter также по умолчанию предоставляет относительный URL-адрес; отредактируйте код, указав HTTPS при локальном копировании/вставке.) Все будет готово с помощью script-src https://platform.twitter.com; child-src https://platform.twitter.com , если вы переместите фрагмент JavaScript, предоставляемый Twitter, во внешний файл JavaScript.

  • Другие платформы имеют аналогичные требования и могут решаться аналогичным образом. Мы предлагаем просто установить для параметра default-src значение 'none' и наблюдать за консолью, чтобы определить, какие ресурсы вам необходимо включить, чтобы виджеты работали.

Включить несколько виджетов очень просто: просто объедините директивы политики, не забывая объединить все ресурсы одного типа в одну директиву. Если вам нужны все три виджета социальных сетей, политика будет выглядеть так:

script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com

Вариант использования 2: блокировка

Предположим на минуту, что вы управляете банковским сайтом и хотите быть уверены, что могут быть загружены только те ресурсы, которые вы написали сами. В этом сценарии начните с политики по умолчанию, которая блокирует абсолютно все ( default-src 'none' ), и наращивайте ее.

Допустим, банк загружает все изображения, стиль и скрипт из CDN по адресу https://cdn.mybank.net и подключается через XHR к https://api.mybank.com/ , чтобы извлечь различные биты данных. Фреймы используются, но только для страниц, локальных для сайта (никаких сторонних источников). На сайте нет Flash, нет шрифтов, нет дополнений. Самый ограничительный заголовок CSP, который мы можем отправить, таков:

Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'

Вариант использования 3: только SSL

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

Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'

Несмотря на то, что https: указан в default-src , директивы сценария и стиля не наследуют этот источник автоматически. Каждая директива полностью перезаписывает значение по умолчанию для этого конкретного типа ресурса.

Будущее

Политика безопасности контента уровня 2 является кандидатом на рекомендацию . Рабочая группа W3C по безопасности веб-приложений уже начала работу над следующей версией спецификации — Content Security Policy Level 3 .

Если вы заинтересованы в обсуждении этих будущих функций, просмотрите архивы списков рассылки public-webappsec@ или присоединитесь сами.

Обратная связь