Введение
Умение реализовать грамотное REST API — полезный навык в наше время, т.к. все больше сервисов предоставляют свои возможности с помощью API. Но разработка REST API не ограничивается реализацией HTTP запросов в определенном стиле и формированием ответов в соответствии со спецификацией. Задача обеспечения безопасности REST API не так очевидна, как, например, обеспечение безопасности баз данных, но ее необходимость не менее важна.
В настоящее время многие онлайн системы с помощью API передают приватные данные пользователей, такие как медицинские или финансовые. Текущая же ситуация с безопасностью в веб-приложениях весьма печальна: по данным Comnews порядка 70% содержат критические уязвимости. Поэтому всем, кто участвует в проектировании, реализации и тестировании онлайн систем, важно иметь общую картину по существующим угрозам и способам обеспечения безопасности как всей системы, так и используемого REST API.
В статье я попытался обобщить информацию о существующих уязвимостях REST API, чтобы у читателей сложилась общая картина. На схемах представлена современная архитектура клиент-сервер и обобщенный REST API запрос с потенциальными угрозами безопасности. Далее я подробнее расскажу об этих угрозах, и как технически реализовать защиту от них.
Стандарты безопасности
Начнем со стандартов. Существует несколько стандартов, которые помогут нам сформулировать список требований к безопасности API:
OWASP (Open Web Application Security Project) известна своими списками рисков в разных программных технологиях. Нам интересен список «10 наиболее опасных уязвимостей при разработке API»:
- API1:2019 Broken Object Level Authorization (Недостатки контроля доступа к объектам). Другое название этого риска: Insecure Direct Object References (Небезопасные прямые ссылки на объекты)
- API2:2019 Broken User Authentication (Недостатки аутентификации пользователей)
- API3:2019 Excessive Data Exposure (Разглашение конфиденциальных данных)
- API4:2019 Lack of Resources & Rate Limiting (Отсутствие проверок и ограничений)
- API5:2019 Broken Function Level Authorization (Недостатки контроля доступа на функциональном уровне)
- API6:2019 Mass Assignment (Небезопасная десериализация)
- API7:2019 Security Misconfiguration (Некорректная настройка параметров безопасности)
- API8:2019 Injection (Внедрение)
- API9:2019 Improper Assets Management (Недостатки управления API)
- API10:2019 Insufficient Logging & Monitoring (Недостатки журналирования и мониторинга)
Добавлю пункты, которые не вошли в Top10, но относятся к нашей теме:
- Insecure Transport (Небезопасный транспортный уровень)
- Insecure Passwords (Небезопасные пароли)
- Using Components with Known Vulnerabilities (Использование компонент с известными уязвимостями)
А также уязвимости из списка другой организации Common Weakness Enumeration (CWE): CWE Top 25 Most Dangerous Software Errors:
- CWE-79 Cross-site Scripting (XSS) (Межсайтовое выполнение сценариев)
- CWE-352 Cross-Site Request Forgery (CSRF) (Межсайтовая подмена запросов)
И несколько пунктов из других найденных списков:
- Insecure Cookies and Local Storage (Небезопасные Cookies и Local Storage)
- Insecure HTTP Headers (Небезопасные HTTP заголовки)
- Improper Cross-origin resource sharing (Неправильное использование CORS)
- Clickjacking (Подмена кликов)
В результате получился список, который, на мой взгляд, достаточно полно отражает современные проблемы безопасности API. Для проверки того, что список получился общим и применимым для всех технологий я использовал рекомендации по безопасности API, найденные на просторах Интернета (ссылки приведены в конце статьи). Далее рассмотрим все перечисленные пункты.
API2:2019 — Broken User Authentication (Недостатки аутентификации пользователей)
Тема аутентификации пользователей идет на втором месте в списке OWASP, но я ее поставил на первое, т.к. с этого все начинается. Современные стандарты аутентификации и авторизации я уже рассматривал в своей статье про OAuth 2.0, OpenID Connect, WebAuthn. Здесь кратко опишу основные схемы безопасности и рассмотрим более подробно наиболее надежную на данный момент схему, основанную на токенах.
API key
API Key — это строка символов, которую передает клиент в запросах к серверу. Для успешной аутентификации строка должна совпадать у клиента и у сервера. Данная схема обеспечивает защиту от несанкционированного использования API и позволяет осуществлять, например, проверку лимитов использования API.
Basic Authentication
В Basic Authentication используется аутентификация по двум строкам, например логину/паролю.
Для передачи информации используется HTTP заголовок 'Authorization' с ключевым словом Basic далее пробел и base64 закодированная строка username:password. Например:
Authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
Cookie-Based Authentication
Cookie-Based Authentication использует механизм передачи Cookies в HTTP запросах. В ответ на запрос клиента сервер посылает заголовок Set-Cookie, который содержит имя и значение cookie, а также дополнительные атрибуты: expires, domain, path, secure, httponly. Пример отправки cookie:
Authorization: Set-Cookie: JSESSIONID=123456789; Path=/; HttpOnly
После этого клиент автоматически будет посылать заголовок Cookie при каждом запросе:
Cookie: JSESSIONID=123456789
Для реализации этого механизма необходимо на сервере организовать хранение и проверку сессий пользователей. Подробнее использование Cookies рассмотрено в разделе «Insecure Cookies and Local Storage»
Token-Based Authentication
Также называют Bearer Authentication.
Token-Based Authentication использует подписанный сервером токен (bearer token), который клиент передает на сервер в заголовке Authorization HTTP с ключевым словом Bearer или в теле запроса. Например:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjI4Y
При получении токена сервер должен проверять его на валидность — что пользователь существует, время использования не прошло и т.д. Token-Based Authentication может использоваться как часть OAuth 2.0 или OpenID Connect протоколов, так и сервер сам может сформировать токен.
При любом способе аутентификации для безопасного использования должен использоваться протокол, который обеспечивает шифрование данных, HTTP заголовков и URL, например HTTPS.
Алгоритм Token-Based Authentication
Разберем подробнее последнюю из описанных схем. На схеме представлен упрощенный алгоритм Token-Based Authentication на примере реализации возможности «Зайти с помощью Google аккаунта»
- Пользователь заходит на сайт и нажимает кнопку «Зайти с помощью Google аккаунта»
- Сервер посылает запрос на Google.
- Google показывает пользователю свою форму логина.
- Пользователь вводит логин/пароль.
- Google проверяет логин/пароль и отправляет на наш сервер приложений access token и refresh token.
- Для аутентификации сервер расшифровывает token или получает информацию о пользователе по Google API.
- Далее сервер находит пользователя в своей базе, сообщает об успешной аутентификации и сохраняет токены в локальном хранилище пользователя для реализации возможности «Запомнить меня на этом устройстве». В каком конкретно: Local Storage, Session Storage или Cookies, решается в зависимости от требований бизнеса и безопасности. OWASP склоняется к Cookies с реализацией дополнительных механизмов безопасности: JSON Web Token Cheat Sheet. Нужно ли генерировать дополнительный «session token», где его хранить и как использовать — также должно определяться бизнесом, для которого реализуется система.
- После этого при каждом запросе к серверу клиент будет передавать access token в запросе, а наш сервер проверять его на валидность в Google и только после этого передавать запрошенные данные.
- При окончании срока действия access токена сервер использует refresh токен для получения нового.
Какие плюсы Token-Based Authentication для сервера приложений:
- Не надо хранить пароли в базе данных на сервере, таким образом сразу избавляемся от уязвимости Insecure Passwords.
- В некоторых случаях можно вообще избавиться от базы данных на сервере и получать всю необходимую информацию из Google или других систем.
- Нет проблем с безопасностью, характерных для остальных методов:
- При компрометации логина/пароля доступ к данным получается сразу и длится пока пользователь сам не заметит факт взлома, у токенов же есть время жизни, которое может быть небольшим.
- Токен автоматически не уйдет на сторонний сайт, как Cookie.
- Cookie-Based Authentication подвержена атаке Cross-Site Request Forgeries (CSRF) и, соответственно, необходимо использовать дополнительные механизмы защиты.
- Можно не хранить сессию пользователя на сервере, а токен проверять каждый раз в Google.
Минус видится один:
В случае перехвата токена, злоумышленник может какое-то время выдавать себя за владельца токена. Поэтому для передачи токена надо обязательно использовать HTTPS.
API1:2019 Broken Object Level Authorization (Недостатки контроля доступа к объектам)
Другое название этого риска: Insecure Direct Object References (Небезопасные прямые ссылки на объекты). Это самая распространенная проблема с API в настоящее время. Для иллюстрации приведу API, которое в дальнейшем использую еще для нескольких примеров уязвимостей.
Получить одного пользователя с userID:
GET /users/{userID}
Получить всех пользователей (может только администратор):
GET /users
Удалить пользователя c userID: DELETE /users/{userID}
DELETE /users/1
Итак, если вызывается команда удаления пользователя:
DELETE /users/1
То необходима проверка, что эту команду может вызвать только сам пользователь 1 или администратор, а не, например, пользователь 2 от своего имени, просто изменив значение ID в вызове команды. Чтобы избежать подобных проблем нужно:
- Проверять права доступа к объектам при каждом запросе.
- Проверять, что залогиненный пользователь имеет доступ только к разрешенным объектам.
- ID объектов должны быть сложными для подбора, например в виде UUID, а не простая последовательность 1, 2, 3.
OWASP рекомендует (Access Control Cheat Sheet) следующие модели обеспечения контроля доступа:
- Role-Based Access Control (RBAC)
- Discretionary Access Control (DAC)
- Mandatory Access Control (MAC)
- Permission Based Access Control
API5:2019 Broken Function Level Authorization (Недостатки контроля доступа на функциональном уровне)
Должна быть разработана четкая система разграничения доступа между ролями пользователей API. Например, есть роль: обычные пользователи и роль: администраторы. Команду по просмотру всех пользователей может вызвать только администратор:
GET /users/all
При каждом вызове команды необходима проверка прав доступа, чтобы обычный пользователь не мог вызвать команду, только изменив формат.
API3:2019 Excessive Data Exposure (Разглашение конфиденциальных данных)
На самом деле пункт называется — предоставление излишних данных, но при этом как раз и может происходить разглашение конфиденциальных или персональных данных. Как такое получается? На запрос клиента сервер, как правило, формирует запрос к базе данных, которая возвращает запись или список записей. Эти данные зачастую сериализируются в JSON без проверок и отправляется клиенту с предположением, что клиент сам отфильтрует нужные данные. Но проблема в том, что запрос может отправить не только клиент, а может сформировать злоумышленник напрямую к серверу и получить конфиденциальные данные. Например, безобидный запрос данных по пользователю с ID 1:
GET /users/1
может вернуть не только имя / возраст, но и ответ на секретный вопрос, который пользователь задал во время регистрации:
{"userName":"Alex","age":25,"secretAnswer":"HelloWorld"}
Это и называется излишняя передача данных. Проблема усугубляется тем, что лишних данных может быть еще и просто много по объёму. При больших нагрузках это приведет к сетевым проблемам. Соответственно, при разработке API нельзя полагаться на фильтрацию данных в клиенте — все данные должны фильтроваться на сервере.
API6:2019 Mass Assignment (Небезопасная десериализация)
В данном случае ситуация обратная предыдущему пункту Excessive Data Exposure — лишние данные передаются на сервер с целью несанкционированной замены значений. Как это понимать? Предположим у нас есть пользователь-хакер с ID 1 со следующими данными:
{"userName":"Alex","age":25,"balance":"150"}
Некоторые поля записей пользователь может легитимно менять сам, например, свой возраст. А поля, такие как balance должны устанавливать внешние системы.
Но наш сервер подвержен атаке Mass Assignment и без проверок источника записывает все пришедшие данные. Наш пользователь-хакер может отправить на сервер запрос на изменение возраста, в который добавляет дополнительный атрибут balance:
POST /users/1
{"userName":"Alex","age":26,"balance":"1000000"}
После этого баланс увеличится без внесения реальных денег. Чтобы предотвратить данную атаку необходимо:
- Не допускать автоматическую десериализацию пришедших данных.
- Ограничить список атрибутов, которые может менять пользователь.
API4:2019 Lack of Resources & Rate Limiting (Отсутствие проверок и ограничений)
Необходимо защитить сервер от атак по подбору пароля (brute force attack). Для этого нужно реализовать следующие ограничения:
- Ограничить число неудачных попыток авторизации одного пользователя. Как вариант использовать reCapture или аналогичный механизм.
- Блокировать IP, если число неудачных попыток с него превысило определенное значение по всем пользователям.
Для JS существуют средства, позволяющие делать такие проверки автоматически (например, Rate limiter) и сразу посылать ответ «429 Too Many Requests», не нагружая сервер.
Необходимо защитить сервер и от отказа в обслуживании (DoS-атаки)
- Ограничить число запросов от одного пользователя или по одному ресурсу в течении определенного времени.
- Также атаки по отказу в обслуживании могут основываться на передаче заведомо больших значений.
/api/users?page=1&size=100
Если на сервере отсутствует проверка size на максимальное значение, то передача в параметре злоумышленником, например, 1 000 000 может привести к исчерпанию памяти на сервере и отказу в обслуживании. Поэтому нужно проверять на сервере все значения параметров на допустимые, даже если на нашем клиенте есть такие проверки. Ведь никто не помешает вызвать API напрямую.
API7:2019 Security Misconfiguration (Некорректная настройка параметров безопасности)
Следующие действия могут привести к проблемам с безопасностью, соответственно, их надо избегать:
- Используются дефолтные настройки приложений, которые могут быть небезопасны.
- Используются открытые хранилища данных.
- В OpenSourсe попала закрытая информация, например, конфигурация системы или параметры доступа.
- Неправильно используются регулярные выражения, что позволяет провести атаку ReDoS (Regular expression Denial of Service)
- Неправильно сконфигурированы HTTP заголовки (данная тема рассмотрена далее в разделе «Insecure HTTP Headers»).
- Аутентификационные данные (логин/пароль, токен, apiKey) посылаются в URL. Это небезопасно, т.к. параметры из URL могут оставаться в логах веб серверов.
- Отсутствует или неправильно используется политика Cross-Origin Resource Sharing (CORS) (данная политика рассмотрена далее в одноимённом разделе).
- Не используется HTTPS (использование HTTPS рассмотрено в разделе «Insecure Transport»).
- При эксплуатации промышленной системы используются настройки, предназначенные для разработки и отладки.
- Сообщения об ошибках содержат чувствительную информацию, например, трейсы стека.
Также необходимо уделять внимание конфигурации облачных сервисов:
- Для пользователей устанавливать только необходимые права доступа.
- Открывать только необходимые сетевые порты.
- Устанавливать безопасные версии патчей OS и приложений (подробно рекомендации рассмотрены в разделе «Using Components with Known Vulnerabilities»).
API8:2019 Injection (Внедрение)
Внедрение — это выполнение программного кода, не предусмотренного системой. Разделяют внедрения:
- SQL команд
- Команд OS
Атака будет успешна, если сервер выполняет полученные команды без проверки. Чем-то напоминает «небезопасную десериализацию», только используются не дополнительные атрибуты, а SQL код или команды OS. В результате SQL инъекции можно получить несанкционированный доступ к данным. С помощью инъекции команд OS можно получить доступ к серверу или вывести его из строя. Например, в строке ввода пользователь ввел имя каталога «name» и на сервер посылается команда:
GET /run
{"mkdir":"name"}
Если сервер выполняет команды без проверки, то злоумышленник может послать следующую команду с большой вероятностью вывода сервера из строя:
GET /run
{"mkdir":"name && format C:/"}
Для предотвращения подобных атак:
- Нельзя подавать введенные данные напрямую в команды.
- Если без этого никак, то необходимо делать все возможные проверки, очистку, фильтрацию и валидацию данных.
API9:2019 Improper Assets Management (Недостатки управления API)
API может иметь несколько точек входа (endpoints) с разными версиями и функциональными назначениями. Например:
http://localhost:5000/myAPI/v1
http://localhost:5000/myAPI/v2
http://localhost:5000/myTestAPI/v1
Необходимо обеспечить учет и контроль версий API:
- Нужно вести список имеющихся API, их версий, назначение (production, test, development) и кто имеет к ним доступ (public, internal, partners).
- Необходимо управлять жизненным циклом API и своевременно запускать новые версии, снимать с поддержки старые.
- В открытом доступ выставлять только актуальные версии API.
- Не оставлять в открытом доступе endpoints, предназначенные для отладки.
Если не обеспечить подобный контроль, то возможно использование API в непредусмотренных целях. Например, злоумышленник обнаружит рабочий endpoint с версией API, которая имела уязвимости в безопасности, но была оставлена на время перехода на новую безопасную версию, но так и осталась в эксплуатации.
API10:2019 Insufficient Logging & Monitoring (Недостатки журналирования и мониторинга)
Чтобы выявить атаку или подозрительное поведение пользователей, систему надо мониторить, а события логировать с достаточным уровнем подробности:
- Логировать все неудачные попытки аутентификации, отказы в доступе, ошибки валидации входных данных.
- Обеспечить целостность логов, чтобы предотвратить возможность их подделки.
- Мониторить надо не только приложения и вызовы API, но и инфраструктуру, сетевую активность, загрузку OS.
- Необходимо обеспечить не только мониторинг, но и оперативное оповещение о нарушениях штатной работы системы.
- Общие советы по мониторингу можно посмотреть в статье Monitoring Done Right
Insecure Transport (Небезопасный транспортный уровень)
Если не шифровать трафик между клиентом и сервером, то все HTTP данные и заголовки будут передаваться в открытом виде. Чтобы предотвратить утечку данных, надо использовать протокол HTTPS (Hyper Text Transfer Protocol Secure) или реализовывать шифрование самостоятельно. Для использования HTTPS нужен SSL-сертификат. Сайты в интернете должны получать такие сертификаты в доверительных центрах выдачи сертификатов CA (Certificate Authority). Но для целей шифрования данных между нашим клиентом и сервером можно поступить проще:
- Самостоятельно сгенерировать, так называемый, self-signed сертификат.
- На сервере настроить использование HTTPS протокола.
- С клиента формировать запросы, начинающиеся с https.
Браузер, конечно, будет ругаться, что сертификат сервера подписан не известно кем, но мы-то можем сами себе доверять).
Обеспечить поддержку HTTPS можно также средствами Apache, Nginx или других веб-серверов.
Insecure Passwords (Небезопасные пароли)
С этой темой все просто:
- Пароли пользователей должны быть достаточно сложными и длинными. В настоящее время не существует единых требований к паролям, все определяется бизнесом.
- На сервере нельзя хранить пароли пользователей в открытом виде.
- На сервере храним только хеши паролей, вычисленные надежным алгоритмом, например, Argon2.
Insecure Cookies and Local Storage (Небезопасные Cookies и данные в Local Storage)
Cookies должны использоваться безопасно:
- Нельзя использовать дефолтные имена.
- При создании Cookies следует устанавливать следующие опции:
secure - браузер будет отправлять cookies только по HTTPS протоколу.
httpOnly - браузер будет отправлять cookies только по HTTP или HTTPS и не отправлять при запросах из JavaScript, что предотвратит атаки Cross-site Scripting (XSS).
domain - определяет domain cookie.
path - определяет path cookie.
expires - определяет дату устаревания cookies.
SameSite - браузер будет отправлять cookies только тому сайту, который их установил.
- Европейские сайты должны явно спрашивать разрешение у пользователя о применении Cookies. Так как, например, если в Cookies записать последовательность действий пользователя на сайте, то это уже считается персональной информацией.
Общие правила безопасности для Cookies и Local Storage:
- Нельзя хранить важную информацию с сервера, т.к. она доступна пользователю.
- Нельзя хранить персональную информацию пользователя, т.к. она может стать доступна другим пользователям компьютера.
- Соответственно, можно хранить только зашифрованные данные или служебную информацию.
Using Components with Known Vulnerabilities (Использование компонент с известными уязвимостями)
Компоненты, такие как библиотеки и framework-и выполняются с теми же привилегиями, что и приложение. Поэтому если среди используемых библиотек окажется небезопасный компонент, то это может привести к захвату или выводу из строя сервера. Для проверки безопасности компонент используются специальные приложения, например, для JavaScript можно использовать Retire.
CWE-79 Cross-site Scripting (XSS) (Межсайтовое выполнение скриптов)
Межсайтовое выполнение скриптов считается самой опасной web-атакой. Суть ее в том, что вредоносный скрипт может быть внедрен в нашу страницу, а результат выполнения может привести к утечке конфиденциальных данных или к повреждению сервера. Чтобы защититься от атаки в запрос надо включить HTTP заголовок, который включает Cross-site scripting (XSS) фильтр:
X-XSS-Protection : 1; mode=block
или
Content-Security-Policy: script-src 'self'
CWE-352 Cross-Site Request Forgery (CSRF) (Межсайтовая подмена запросов)
Для понимания сути атаки приведу пример: предположим, есть финансовая организация с онлайн кабинетом. В Cookies запоминается пользователь, чтобы при входе ему не надо было каждый раз вводить свой логин/пароль. Пользователь случайно заходит на сайт злоумышленника, который отправляет в финансовую организацию транзакцию на перевод денег, в которую браузер автоматически помещает данные из запомненных Cookies.
Финансовый сайт успешно проверяет валидность Cookies и выполняет несанкционированную транзакцию. Для защиты от атак CSRF надо:
- На сервере реализовать механизм «CSRF токенов». Это такой механизм, когда для каждой сессии пользователя генерируется новый токен и сервер проверяет его валидность при любых запросах с клиента.
- На сервере проверять заголовки Origin и Referer, в которых содержится адрес источника запроса. Но эти заголовки могут отсутствовать.
- Также можно всегда требовать от пользователя подтверждать критические действия вводом пароля или вторым фактором аутентификации, но возможность таких мер зависит от бизнеса.
- При создании Cookies выставлять параметр SameSite, но этот механизм поддерживают не все браузеры.
Cross-origin resource sharing (CORS) (Кросс-доменное использование ресурсов)
CORS — это механизм безопасности, который позволяет серверу задать правила доступа к его API. Например, если на сервере установить заголовок:
Access-Control-Allow-Origin: *
то это позволит использовать API без ограничения. Если это не публичное API, то для безопасности надо явно устанавливать Origin-ы, с которых разрешен доступ к API, например:
Access-Control-Allow-Origin: https://example.com:8080
Также можно ограничивать HTTP методы, которые могут быть использованы для доступа к API:
Access-Control-Allow-Methods: GET, POST, DELETE, PUT
И задать список заголовков, которые сервер может принимать:
Access-Control-Allow-Headers: Origin, Content-Type, Authorization
Insecure HTTP Headers (Безопасность HTTP заголовков)
HTTP протокол включает в себя большое число заголовков, которые можно использовать в HTTP запросах/ответах. Для того, чтобы определить наиболее важные заголовки с точки зрения обеспечения безопасности, я использовал несколько списков:
- OWASP Secure Headers Project
- Рекомендации Express: Production Best Practices
Далее рассмотрим основные заголовки:
X-Powered-By
Этот заголовок автоматически вставляется некоторыми серверами, что дает понять злоумышленнику, с каким сервером он имеет дело, например:
X-Powered-By: Express
Отсутствие этого заголовка, конечно, никого не остановит, но сразу давать такую подсказку не стоит. Поэтому передачу этого заголовка надо запретить.
HTTP Strict Transport Security (HSTS)
Strict-Transport-Security заголовок запрещает браузеру обращаться к ресурсам по HTTP протоколу, только HTTPS:
Strict-Transport-Security: max-age=31536000
max-age=31536000 — это год в секундах. Рекомендуется выcтавлять этот заголовок, т.к. он предотвратит атаки, связанные с принуждением браузера перейти на HTTP протокол и начать передавать информацию (например cookies) в открытом виде, которую может перехватить злоумышленник. Запрос к серверу по HTTP и атака возможна только при первом обращении к серверу, при последующих браузер запомнит настройку Strict-Transport-Security и будет обращаться только по HTTPS.
X-Frame-Options (защита от Clickjacking)
Позволяет защититься от атаки Clickjacking. Так называется технология, когда злоумышленник помещает кнопку или поле ввода в прозрачный фрейм и пользователь думает, что он нажимает нужную кнопку или безопасно вводит данные, а на самом деле идет перенаправление на другой ресурс, полезный атакующему, например, на сайт с навязчивой рекламой. Для защиты от Clickjacking сервер должен посылать запрет использовать страницу во фрейме вообще:
X-Frame-Options: deny
или разрешить использование только в нашем домене:
X-Frame-Options: sameorigin
А лучше для предотвращения атаки Clickjacking использовать более современный механизм и установить правильную политику безопасности Content-Security-Policy
Content-Security-Policy
Позволяет защититься от атаки Cross-site scripting и других кросс-сайтовых инъекций, в том числе Clickjacking. Требует вдумчивого конфигурирования, т.к. параметров много. Но надо хотя бы поставить дефолтную политику, что предотвратит возможность атаки Cross-site Scripting:
Content-Security-Policy: default-src 'self'
Подробно значения заголовка Content-Security-Policy разбираются, например, по ссылке.
X-Content-Type-Options
Установка данного заголовка запрещает браузеру самому интерпретировать тип присланных файлов и принуждает использовать только тот, что был прислан в заголовке Content-Type. Без этого возможна ситуация, когда, например, посылается безобидный на вид txt файл, внутри которого вредоносный скрипт и браузер его выполняет как скрипт, а не как текстовой файл. Поэтому устанавливаем:
X-Content-Type-Options: nosniff
Cache-Control
Cache-Control позволяет управлять кешом на стороне клиента, рекомендуется запретить кеширование, чтобы в кеше случайно не оставались приватные данные:
Cache-Control: no-store
Заключение
В статье мы рассмотрели угрозы, которые подстерегают API при его эксплуатации и способы борьбы с ними. В заключении приведу несколько общих выводов:
- Нужно держать круговую оборону и защищаться со всех сторон. Как ни банально звучит, но безопасность системы определяется самым слабым звеном. И если мы забыли защитить даже незначительную часть, последствия могут быть весьма печальными.
- Разработчик API должен не только уметь программировать, но и разбираться в безопасности систем и приложений. Или в команде должен быть сотрудник, отвечающий за безопасность.
- Нужно следить за актуальным положением дел с безопасностью, т.к. даже относительно свежая информация может быстро устареть, и система окажется неработоспособной или беззащитной перед атаками.
Ссылки на использованные списки:
- API Security Top 10
- Top 25 Most Dangerous Software Errors
- Рекомендации RedHat: API security
- Рекомендации Express: Production Best Practices
- Рекомендации Node.js: Security Checklist
Желаю всем легкодоступных, но безопасных API! )
It's only the beginning!
KYuri
AlexeySushkov Автор
Спасибо за уточнение, поправил, действительно, при использовании HTTPS шифруется весь HTTP запрос, включая URL и параметры, а не шифруется только IP адрес и порт, т.к. это нужно для маршрутизации.
Perlovich
Все равно совет про то, что не следует посылать чувствительные данные в URL, был здравым.
Навскидку две проблемы могу вспомнить, но, мне кажется, их больше:
— (редкая проблема) если пароль/токен попал в URL, то пользователь может добавить этот URL в закладки, скопировать его куда-то, URL попадет в историю, и т.д. Такая проблема была актуальна, когда юзали в основном html submit формы, а не SPA;
— (более актуальная проблема) многие сервере и reverse proxy логируют урлы целиком со всеми параметрами. А попадание незашифрованных credentials в логи — это, однозначно, bad practice.
AlexeySushkov Автор
Согласен и OWASP об этом явно говорит в разделе: Sensitive information in HTTP requests
Добавил пункт в список: «API7:2019 Security Misconfiguration»
dmitryb-dev
Почитайте про модель OSI. Выглядит так, будто вы представляете это как набор полей, а HTTPS типо выбирает какие поля шифровать, а какие нет.
Но на самом деле это даже близко не так, просто SSL находится на уровне между HTTP и TCP. И шифруется абсолютно все, что находится выше него, потому что нижние протоколы, как будто бы «заворачивают/упаковывают» вышестоящие. Поэтому весь трафик HTTP шифруется, потому что SSL шифрует все, что находится на более высоком уровне и ему все равно, HTTP это или нет. Тут еще конечно сбивает с толку, что HTTPS это на самом деле два протокола, а не один, SSL + HTTP.
AlexeySushkov Автор
Если придираться, то HTTPS использует не SSL, а TLS протокол. Но вы, конечно, правы URL шифруется полностью, а IP:Port мы видим в открытом виде, т.к. они используются на другом уровне сетевого стека.
Busla
Модель OSI тут не при чём. Модель на то и модель, что это абстракция для разработчика/пользователя — последовательность обработки данных внутри ОС. Для примера, VLAN как бы вносит дополнительный уровень, но ничего никуда не заворачивается, это просто поле данных в том же самом Ethernet-фрэйме.