Безопасность REST API от А до ПИ

Введение


Умение реализовать грамотное REST API — полезный навык в наше время, т.к. все больше сервисов предоставляют свои возможности с помощью API. Но разработка REST API не ограничивается реализацией HTTP запросов в определенном стиле и формированием ответов в соответствии со спецификацией. Задача обеспечения безопасности REST API не так очевидна, как, например, обеспечение безопасности баз данных, но ее необходимость не менее важна.
В настоящее время многие онлайн системы с помощью API передают приватные данные пользователей, такие как медицинские или финансовые. Текущая же ситуация с безопасностью в веб-приложениях весьма печальна: по данным Comnews порядка 70% содержат кри­тичес­кие уязвимости. Поэтому всем, кто участвует в проектировании, реализации и тестировании онлайн систем, важно иметь общую картину по существующим угрозам и способам обеспечения безопасности как всей системы, так и используемого REST API.

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

image

Стандарты безопасности


Начнем со стандартов. Существует несколько стандартов, которые помогут нам сформулировать список требований к безопасности 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, но относятся к нашей теме:


А также уязвимости из списка другой организации 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 аккаунта»

image

  1. Пользователь заходит на сайт и нажимает кнопку «Зайти с помощью Google аккаунта»
  2. Сервер посылает запрос на Google.
  3. Google показывает пользователю свою форму логина.
  4. Пользователь вводит логин/пароль.
  5. Google проверяет логин/пароль и отправляет на наш сервер приложений access token и refresh token.
  6. Для аутентификации сервер расшифровывает token или получает информацию о пользователе по Google API.
  7. Далее сервер находит пользователя в своей базе, сообщает об успешной аутентификации и сохраняет токены в локальном хранилище пользователя для реализации возможности «Запомнить меня на этом устройстве». В каком конкретно: Local Storage, Session Storage или Cookies, решается в зависимости от требований бизнеса и безопасности. OWASP склоняется к Cookies с реализацией дополнительных механизмов безопасности: JSON Web Token Cheat Sheet. Нужно ли генерировать дополнительный «session token», где его хранить и как использовать — также должно определяться бизнесом, для которого реализуется система.
  8. После этого при каждом запросе к серверу клиент будет передавать access token в запросе, а наш сервер проверять его на валидность в Google и только после этого передавать запрошенные данные.
  9. При окончании срока действия access токена сервер использует refresh токен для получения нового.

Какие плюсы Token-Based Authentication для сервера приложений:

  1. Не надо хранить пароли в базе данных на сервере, таким образом сразу избавляемся от уязвимости Insecure Passwords.
  2. В некоторых случаях можно вообще избавиться от базы данных на сервере и получать всю необходимую информацию из Google или других систем.
  3. Нет проблем с безопасностью, характерных для остальных методов:

  • При компрометации логина/пароля доступ к данным получается сразу и длится пока пользователь сам не заметит факт взлома, у токенов же есть время жизни, которое может быть небольшим.
  • Токен автоматически не уйдет на сторонний сайт, как 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-атаки)

  • Ограничить число запросов от одного пользователя или по одному ресурсу в течении определенного времени.
  • Также атаки по отказу в обслуживании могут основываться на передаче заведомо больших значений.
Например, сервер ожидает в параметре size число записей:

/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 запросах/ответах. Для того, чтобы определить наиболее важные заголовки с точки зрения обеспечения безопасности, я использовал несколько списков:


Далее рассмотрим основные заголовки:

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! )

It's only the beginning!

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 18

    +2
    • Для безопасного использования схем аутентификации должен использоваться протокол, который обеспечивает шифрование данных и HTTP заголовков, например HTTPS.
    • Нельзя посылать аутентификационные данные (логин/пароль или токен) в URL, т.к. URL не шифруется
    При использовании HTTPS URL шифруется.
      +1
      Спасибо за уточнение, поправил, действительно, при использовании HTTPS шифруется весь HTTP запрос, включая URL и параметры, а не шифруется только IP адрес и порт, т.к. это нужно для маршрутизации.
        +5
        Все равно совет про то, что не следует посылать чувствительные данные в URL, был здравым.

        Навскидку две проблемы могу вспомнить, но, мне кажется, их больше:

        — (редкая проблема) если пароль/токен попал в URL, то пользователь может добавить этот URL в закладки, скопировать его куда-то, URL попадет в историю, и т.д. Такая проблема была актуальна, когда юзали в основном html submit формы, а не SPA;

        — (более актуальная проблема) многие сервере и reverse proxy логируют урлы целиком со всеми параметрами. А попадание незашифрованных credentials в логи — это, однозначно, bad practice.
        +4
        Почитайте про модель OSI. Выглядит так, будто вы представляете это как набор полей, а HTTPS типо выбирает какие поля шифровать, а какие нет.

        Но на самом деле это даже близко не так, просто SSL находится на уровне между HTTP и TCP. И шифруется абсолютно все, что находится выше него, потому что нижние протоколы, как будто бы «заворачивают/упаковывают» вышестоящие. Поэтому весь трафик HTTP шифруется, потому что SSL шифрует все, что находится на более высоком уровне и ему все равно, HTTP это или нет. Тут еще конечно сбивает с толку, что HTTPS это на самом деле два протокола, а не один, SSL + HTTP.
          0
          Если придираться, то HTTPS использует не SSL, а TLS протокол. Но вы, конечно, правы URL шифруется полностью, а IP:Port мы видим в открытом виде, т.к. они используются на другом уровне сетевого стека.
            0
            Модель OSI тут не при чём. Модель на то и модель, что это абстракция для разработчика/пользователя — последовательность обработки данных внутри ОС. Для примера, VLAN как бы вносит дополнительный уровень, но ничего никуда не заворачивается, это просто поле данных в том же самом Ethernet-фрэйме.
        –2
        Спасибо! Очень полезная инфа. С удовольствием бы апвоутнул, но за 5 лет чтения хабра не накопил кармы :)
          +1
          API1:2019 Broken Object Level Authorization
          — Проверять, что залогиненный пользователь имеет доступ только к разрешенным объектам.


          Подскажите, пожалуйста, какие есть способы реализовать это? Дело в том, что мы это реализовываем в своих проектах через т.н. реализацию МРД (модели разграничения доступа, но, возможно, это наш внутренний термин).

          МРД — это документ в котором мы прописываем для каждого объекта правила доступа нему со стороны каждого субъекта. Потом эту МРД реализуем в коде на Java. Но получается жутко сложно, много ошибок и косяков.

          Может есть какая-то книжка или бест-практика как это реализовывать проще?
            +1
            модели разграничения доступа бывают разные.
            Access Control List (ACL) — это когда ручками прописывается кто имеет доступ и на что (см. файловая система в *nix)

            более эффективной практикой считается разграничение по ролям RBAC — но тут надо предусмотреть разделение обязанности на разные роли (segregation of duties), например чтобы создавая запись об объекте, он не имел дальнейшего доступа к его функциям, чтобы потенциально не смог злоупотребить.
            Например если админ создал учетку юзера, то он не знает пароль к учетке и не может под ней залогиниться. Только отправить ссылку со сбросом пароля на почту юзеру. Также не может удалить запись аудита своих действий (логи о создании учетки и сбросе пароля например)

            более продвинутым является ABAC — это расширение RBAC, только используются любые атрибуты, а не только роли. Если вам надоело создавать список ролей и поддерживать отношения субъект->роли и объект->роль->доступ то можете заменить «роль» на аттрибуты и это больше похоже станет на разграничение доступа по бизнес-правилам
              0
              OWASP рекомендует (Access Control Cheat Sheet) следующие модели обеспечения контроля доступа:

              • Role-Based Access Control (RBAC)
              • Discretionary Access Control (DAC)
              • Mandatory Access Control (MAC)
              • Permission Based Access Control

              +1
              Спасибо. очень полезно. Вечный вопрос — где хранить Bearer токен в случае с Single Page Applications? В cookies, local store, session store или переменной? Недавно читал что все же рекомендуют в cookies, потому что CSRF атаку легче предотвратить фильтруя в какие запросы вставлять cookies, а все остальные методы подвержены XSS, которая и чаще встречается и легче эксплуатируется. Что думаете?
                +1
                ИМХО главное чтобы при генерации нового bearer token генерировался и новый refresh token (и чтобы они протухали быстро. Помнится с амазоновскими токенами мне понравилась их гибридная схема «первый токен протухает за 5 минут, остальные — через час»)
                А почему сомнения в cookies? Насколько я понимаю- HttpOnly именно для этого и был сделан.
                  0
                  Да, насчет времени актуальности токена согласен. Ну а если ставить HttpOnly, то для SPA приложения не будет доступна дополнительная информациях из токена (например о пользователе, уровне доступа и прочее). Тут как вариант можно делать дополнительный запрос чтобы получить нужную инфу или можно разделить токен, инфу хранить в доступной для JS части, а подпись в cookies.
                    0
                    а что мешает сделать это одним запросом? Можно же установить несколько кук — в одной токен+HttpOnly, в остальных — нужная инфа
                      0
                      Просто думал о том, что бы не хранить избыточные данные, но вариант работающий, Вы правы.
                  0
                  OWASP склоняется к cookies с реализацией дополнительных механизмов безопасности:
                  JSON Web Token Cheat Sheet for Java

                    0
                    Да, спасибо, почитаю:)

                Only users with full accounts can post comments. Log in, please.