Защита вашего веб-приложения: руководство по ограничению скорости и предотвращению атак методом перебора
23 января 2024 г.Если ваше приложение включает в себя фундаментальные функции, такие как вход в систему, регистрацию, сброс/восстановление пароля, повторную отправку ссылок для подтверждения и другие специфические функции, требующие запросов к серверу, крайне важно реализовать механизмы против атак методом перебора и создания значительной нагрузки на ваш сервис. Без таких механизмов ваше приложение может быть уязвимо для различных угроз, включая отправку пользователям чрезмерного количества электронных писем и одноразовых паролей, что потенциально может привести к финансовому и репутационному ущербу.
Многие веб-приложения не имеют адекватных мер по ограничению скорости и полагаются исключительно на ограничения, налагаемые их бизнес-логикой, например ограничение количества запросов на основе модели оплаты. Однако некоторые приложения включают ограничения скорости, особенно для таких операций, как попытки входа в систему, регистрация и другие важные функции. Эти реализации часто зависят от заголовка X-Forwarded-For для отслеживания IP-адресов.
Чтобы проиллюстрировать простой пример, я придумал этот фрагмент кода в Flask.
from flask import Flask, request, jsonify
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
app = Flask(__name__)
limiter = Limiter(
app,
key_func=get_remote_address,
storage_uri="memory://",)
def get_ipaddr():
# Retrieve the client's IP address from the request
# X-Forwarded-For header is used to handle requests behind a proxy
ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
return ip_address
# Rate limit to 5 requests per minute per IP
@limiter.limit("5 per minute")
@app.route('/')
def index():
ip_address = get_ipaddr()
return ip_address
В следующих разделах я объясню различные подходы к тестированию и попыткам обойти ограничения скорости в вашем приложении.
Для эффективного тестирования вашего приложения на наличие уязвимостей такого типа автоматизация является мощным инструментом. Вы можете добиться этого, используя сценарии, например, на Python (как я часто делаю), или используя такие инструменты, как Burp Suite (кстати, отличный инструмент для тестировщиков и специалистов по кибербезопасности). Кроме того, такие инструменты, как Postman, можно относительно легко использовать для автоматизации проверок.
Ограничение частоты тестирования
Изменение значения IP в заголовке X-Forwarded-For
X-Originating-IP: 127.0.0.1
Используйте разные значения IP в каждом отправляемом запросе.
Используйте двойной заголовок X-Forwared-For.
X-Forwarded-For:
X-Forwarded-For: 127.0.0.1
Попробуйте то же самое с разными заголовками.
X-Originating-IP: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-Client-IP: 127.0.0.1
X-Host: 127.0.0.1
X-Forwared-Host: 127.0.0.1
Изменить другие заголовки
Попробуйте изменить пользовательский агент, тип контента, язык принятия и т. д. или файлы cookie — все, что может использоваться в качестве идентификатора пользователя.
Если существует ограничение скорости в 3 попытки на один IP, каждые три попытки меняйте значение IP заголовка (или других заголовков или параметров в ваших запросах).
Добавьте пустые символы в параметры
Попробуйте добавить к отправленным параметрам
%00, %0d%0a, %0d, %0a, %09, %0C, %20
Например
param1=value1%%0d%0a
param2=value2%00
Например, если вы запрашиваете OTP для подтверждения электронной почты и у вас есть только 3 попытки, используйте 3 попытки для
example@email.com
example@email.com%00
example@email.com%0d%0a
And so on
Использовать похожие конечные точки
Если вы тестируете, например, конечную точку /API/v1/signup, попробуйте выполнить перебор к /Signup, /SignUp, /signup. Попробуйте добавить пустые символы (из приведенных выше) к исходным конечным точкам.
Добавление дополнительных параметров в запрошенную конечную точку API
Если ограничение установлено на запросы конечной точки /api/v1/resetpassword, попробуйте перебрать его, добавив некоторые параметры запроса. Как только предел скорости будет достигнут, попробуйте, например, /api/v1/resetpassword?param1 =значение1
Логины имеют значение
Возможно, логика приложения некорректна: если вы входите в свою учетную запись перед каждой попыткой/серией попыток, ограничение скорости для вашего IP-адреса сбрасывается, и вы можете продолжить атаку методом перебора пароля. Если вы тестируете функцию входа в систему, вы можете сделать это в Burp Suit с атакой Pitchfork в настройках (или написать для этого собственный скрипт) для каждой попытки/серии попыток.
Вот пример того, как я автоматизировал простую проверку заголовка X-Forwarded-For только для получения POW:
from random import randint
import requests
import json
url = "https://yourapp.net/api/v1/regconfirm-resend"
data = {
"email": "yourtest@mail.com"
}
N = 100
def generate_random_ip():
return '.'.join(
str(randint(0, 255)) for _ in range(4)
)
for _ in range(N):
headers = {
"Host": "yourapp.net",
"Content-Type": "application/json",
"X-Forwarded-For": generate_random_ip()
}
response = requests.post(url, headers=headers, data=json.dumps(data))
print(headers)
print(f"Status Code: {response.status_code}, Response: {response.text}")
Восстановление исходных IP-адресов посетителей
Возможным решением может быть использование Cloudflare и его механизмов. Подробное объяснение можно найти здесь restoring-original-visitor-ips< /а>. Я предоставлю лишь краткий обзор его защитных механизмов.
<блок-цитата>Если вы используете приложения, которые зависят от входящего IP-адреса исходного посетителя, по умолчанию регистрируется IP-адрес Cloudflare. Исходный IP-адрес посетителя отображается в добавленном HTTP-заголовке под названием CF-Connecting-IP. Следуя инструкциям нашего веб-сервера, вы можете зарегистрировать исходный IP-адрес посетителя на исходном сервере. Если этот HTTP-заголовок недоступен, когда запросы достигают исходного сервера, проверьте правила преобразования и конфигурацию управляемых преобразований.
<блок-цитата>Если для псевдо-IPv4 установлено значение «Перезаписать заголовки», Cloudflare перезаписывает существующие заголовки Cf-Connecting-IP и X-Forwarded-For псевдоадресом IPv4, сохраняя при этом реальный адрес IPv6 в заголовке CF-Connecting-IPv6.
>ПРИМЕЧАНИЕ. Помните: при реализации такого защитного механизма необходимо провести тщательное тестирование. Этот подход впоследствии может быть применен ко всему кластеру и может отрицательно повлиять на определенные функции и микросервисы там, где в нем нет необходимости. Короче говоря, при устранении нарушений безопасности будьте осторожны, поскольку это потенциально может повлиять на все приложение. Проанализируйте, какая часть вашей системы может быть затронута негативно, и протестируйте все перед отправкой изменений в рабочую среду.
Также опубликовано здесь .
Оригинал