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

Браузер — это механизм визуализации. Его задача — загрузить веб-страницу и отобразить ее в понятном для человека виде.

Несмотря на то, что это почти преступное упрощение, пока это все, что нам нужно знать.

  • Пользователь вводит адрес в строку браузера.
  • Браузер загружает «документ» по этому URL-адресу и отображает его.

Возможно, вы привыкли работать с одним из самых популярных браузеров, таких как Chrome, Firefox, Edge или Safari, но это не значит, что разных браузеров нет.

lynx, например, — это легкий текстовый браузер, работающий из командной строки. В основе lynx лежат те же принципы, что и в любом другом основном браузере. Пользователь вводит веб-адрес (URL), браузер извлекает документ и отображает его — единственная разница заключается в том, что lynx использует не визуальный движок рендеринга, а текстовый интерфейс, благодаря которому веб-сайты, подобные Google, выглядят вот так. :

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

Что делает браузер?

Короче говоря, работа браузера в основном состоит из:

  • разрешение DNS
  • HTTP-обмен
  • Рендеринг
  • Промыть и повторить

Разрешение DNS

Этот процесс гарантирует, что после того, как пользователь введет URL-адрес, браузер узнает, к какому серверу он должен подключиться. Браузер связывается с DNS-сервером, чтобы обнаружить, что google.com переводится в 216.58.207.110, IP-адрес, к которому браузер может подключиться.

HTTP-обмен

Как только браузер определит, какой сервер будет обслуживать наш запрос, он установит с ним TCP-соединение и начнет HTTP-обмен. Это не что иное, как способ для браузера сообщить серверу, что ему нужно, и серверу ответить.

HTTP — это просто название самого популярного протокола для общения в Интернете, и браузеры в основном общаются через HTTP при общении с серверами. При обмене HTTP клиент (наш браузер) отправляет запрос, а сервер отвечает ответом.

Например, после того, как браузер успешно подключится к серверу за google.com, он отправит запрос, который выглядит следующим образом:

GET / HTTP/1.1
Host: google.com
Accept: */*

Разберем запрос построчно:

  • GET / HTTP/1.1: этой первой строкой браузер запрашивает у сервера получение документа в местоположении /, добавляя, что остальная часть запроса будет следовать протоколу HTTP/1.1 (он также может использовать 1.0 или 2)
  • Host: google.com: это единственный обязательный HTTP-заголовок в HTTP/1.1. Поскольку сервер может обслуживать несколько доменов (google.com, google.co.uk и т. д.), клиент здесь упоминает, что запрос был для этого конкретного хоста.
  • Accept: */*: необязательный заголовок, в котором браузер сообщает серверу, что он примет любой ответ. У сервера может быть ресурс, доступный в форматах JSON, XML или HTML, поэтому он может выбрать любой формат, который он предпочитает.

После того как браузер, выступающий в роли клиента, обработает свой запрос, наступает очередь сервера отвечать. Вот как выглядит ответ:

HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=1234; expires=Fri, 18-Jan-2019 18:25:04 GMT; path=/; domain=.google.com; HttpOnly
<!doctype html><html">
...
...
</html>

Ух, сколько информации для переваривания. Сервер сообщает нам об успешном выполнении запроса (200 OK) и добавляет к ответу несколько заголовков, например, сообщает, какой сервер обработал наш запрос (Server: gws), какова политика X-XSS-Protection этого ответа. и так далее и тому подобное.

Прямо сейчас вам не нужно понимать каждую строчку в ответе. Мы рассмотрим протокол HTTP, его заголовки и т. д. позже в этой серии.

На данный момент все, что вам нужно понять, это то, что клиент и сервер обмениваются информацией и что они делают это через HTTP.

Рендеринг

И последнее, но не менее важное: процесс рендеринга. Насколько хорош был бы браузер, если бы он показывал пользователю только список забавных персонажей?

<!doctype html><html">
...
...
</html>

В тело ответа сервер включает представление ответа в соответствии с заголовком Content-Type. В нашем случае тип содержимого был установлен на text/html, поэтому мы ожидаем HTML-разметку в ответе — именно это мы и находим в теле.

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

Опять же, конечный результат — это то, что может понять средний Джо.

Для получения более подробной версии того, что на самом деле происходит, когда мы нажимаем Enter в адресной строке браузера, я бы посоветовал прочитать Что происходит, когда… — очень сложная попытка объяснить механизм, лежащий в основе этого процесса.

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

Продавцы

Четыре самых популярных браузера принадлежат разным производителям:

  • Хром от Google
  • Firefox от Mozilla
  • Сафари от Apple
  • Край от Майкрософт

Помимо борьбы друг с другом, чтобы расширить свое проникновение на рынок, поставщики также взаимодействуют друг с другом, чтобы улучшить веб-стандарты, которые являются своего рода «минимальными требованиями» для браузеров.

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

В Chrome 51, например, представлены файлы cookie SameSite, функция, которая позволит веб-приложениям избавиться от определенного типа уязвимости, известной как CSRF (подробнее об этом позже). Другие поставщики решили, что это хорошая идея, и последовали их примеру, что привело к тому, что SameSite стал веб-стандартом: на данный момент Safari — единственный крупный браузер без поддержки файлов cookie SameSite.

Это говорит нам о двух вещах:

  • Похоже, что Safari недостаточно заботится о безопасности своих пользователей (шутка: файлы cookie SameSite будут доступны в Safari 12, который, возможно, уже был выпущен к тому времени, когда вы читаете эту статью).
  • устранение уязвимости в одном браузере не означает, что все ваши пользователи в безопасности

Первый пункт — это выстрел в Safari (как я уже говорил, шучу!), а второй пункт действительно важен. При разработке веб-приложений нам нужно не только убедиться, что они одинаково выглядят в разных браузерах, но и обеспечить одинаковую защиту наших пользователей на разных платформах.

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

В нашем случае, если мы решим, что будем смягчать CSRF-атаки только с помощью файлов cookie SameSite, мы должны осознавать, что подвергаем риску наших пользователей Safari. И наши пользователи тоже должны это знать.

И последнее, но не менее важное: вы должны помнить, что вы сами решаете, поддерживать версию браузера или нет: поддержка каждой версии браузера была бы непрактичной (вспомните Internet Explorer 6). Тем не менее, обеспечение поддержки нескольких последних версий основных браузеров, как правило, является хорошим решением. Однако, если вы не планируете предлагать защиту на определенной платформе, обычно рекомендуется сообщить об этом своим пользователям.

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

Вендорская или стандартная ошибка?

Тот факт, что средний пользователь получает доступ к нашему приложению через сторонний клиент (браузер), добавляет еще один уровень косвенности к четкому и безопасному просмотру: сам браузер может представлять уязвимость в системе безопасности.

Поставщики обычно предоставляют вознаграждение (также известное как bug bounty) исследователям безопасности, которые могут найти уязвимость в самом браузере. Эти ошибки не связаны с вашей реализацией, а скорее с тем, как браузер самостоятельно обрабатывает безопасность.

Например, Программа вознаграждений Chrome позволяет инженерам по безопасности обращаться к команде безопасности Chrome, чтобы сообщать о найденных ими уязвимостях. Если эти уязвимости подтверждаются, выпускается исправление, обычно публикуется уведомление о безопасности, а исследователь получает вознаграждение (обычно финансовое) от программы.

Такие компании, как Google, вкладывают относительно хорошие средства в свои программы Bug Bounty, поскольку это позволяет им привлекать исследователей, обещая финансовую выгоду, если они обнаружат какие-либо проблемы с приложением.

В программе Bug Bounty выигрывают все: поставщику удается повысить безопасность своего программного обеспечения, а исследователям платят за их находки. Мы обсудим эти программы позже, так как я считаю, что инициативы Bug Bounty заслуживают отдельного раздела в сфере безопасности.

Джейк Арчибальд (Jake Archibald) — специалист по защите прав разработчиков в Google, недавно обнаруживший уязвимость, затрагивающую несколько браузеров. Он задокументировал свои усилия, то, как он обращался к разным поставщикам, и их реакцию в интересном сообщении в блоге, которое я рекомендую вам прочитать.

Браузер для разработчиков

К настоящему времени мы должны были понять очень простую, но довольно важную концепцию: браузеры — это просто HTTP-клиенты, созданные для обычного интернет-пользователя.

Они определенно мощнее, чем голый HTTP-клиент платформы (вспомните, например, NodeJS require('http')), но, в конце концов, они являются «просто» естественным развитием более простых HTTP-клиентов.

Как разработчики, нашим предпочтительным HTTP-клиентом, вероятно, является cURL Дэниела Стенберга, одна из самых популярных программ, которые веб-разработчики используют ежедневно. Это позволяет нам выполнять HTTP-обмен на лету, отправляя HTTP-запрос из нашей командной строки:

$ curl -I localhost:8080
HTTP/1.1 200 OK
server: ecstatic-2.2.1
Content-Type: text/html
etag: "23724049-4096-"2018-07-20T11:20:35.526Z""
last-modified: Fri, 20 Jul 2018 11:20:35 GMT
cache-control: max-age=3600
Date: Fri, 20 Jul 2018 11:21:02 GMT
Connection: keep-alive

В приведенном выше примере мы запросили документ по адресу localhost:8080/, и локальный сервер успешно ответил.

Вместо того, чтобы сбрасывать тело ответа в командную строку, здесь мы использовали флаг -I, который сообщает cURL, что нас интересуют только заголовки ответа. Сделав еще один шаг вперед, мы можем поручить cURL вывести немного больше информации, включая фактический запрос, который он выполняет, чтобы мы могли лучше рассмотреть весь этот HTTP-обмен. Нам нужно использовать параметр -v (подробно):

$ curl -I -v localhost:8080
* Rebuilt URL to: localhost:8080/
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> HEAD / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< server: ecstatic-2.2.1
server: ecstatic-2.2.1
< Content-Type: text/html
Content-Type: text/html
< etag: "23724049-4096-"2018-07-20T11:20:35.526Z""
etag: "23724049-4096-"2018-07-20T11:20:35.526Z""
< last-modified: Fri, 20 Jul 2018 11:20:35 GMT
last-modified: Fri, 20 Jul 2018 11:20:35 GMT
< cache-control: max-age=3600
cache-control: max-age=3600
< Date: Fri, 20 Jul 2018 11:25:55 GMT
Date: Fri, 20 Jul 2018 11:25:55 GMT
< Connection: keep-alive
Connection: keep-alive
<
* Connection #0 to host localhost left intact

Примерно такая же информация доступна в основных браузерах через их DevTools.

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

И последнее, на что я хотел бы обратить внимание, это то, что все может быть браузером. Если у вас есть мобильное приложение, которое использует API-интерфейсы через протокол HTTP, то приложение — это ваш браузер — просто это очень индивидуальное приложение, которое вы создали сами, которое понимает только определенный тип HTTP-ответов (из вашего собственного API). .

В протокол HTTP

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

В следующей статье мы более подробно рассмотрим протокол HTTP и попытаемся понять, какие меры мы должны принять для обеспечения безопасности HTTP-обменов.