Безопасность 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!
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 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
                      Да, спасибо, почитаю:)

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое