Si votre application inclut des fonctionnalités fondamentales telles que la connexion, l'enregistrement, la réinitialisation/récupération de mot de passe, le renvoi de liens de confirmation et d'autres fonctionnalités spécifiques nécessitant des requêtes du serveur, il est crucial de mettre en œuvre des mécanismes contre les attaques par force brute et la génération d'une charge substantielle sur votre service. Sans de tels mécanismes, votre application peut être vulnérable à diverses menaces, notamment l'envoi d'un nombre excessif d'e-mails/OTP aux utilisateurs, entraînant potentiellement des dommages financiers et de réputation.
De nombreuses applications Web ne disposent pas de mesures de limitation de débit adéquates et s'appuient uniquement sur les limitations imposées par leur logique métier, comme la restriction du nombre de requêtes basées sur un modèle de paiement. Certaines applications intègrent cependant des limites de débit, en particulier pour les opérations telles que les tentatives de connexion, l'enregistrement et d'autres fonctionnalités critiques. Ces implémentations dépendent souvent de l'en-tête X-Forwarded-For pour le suivi des adresses IP.
Pour illustrer un exemple simple, j'ai trouvé cet extrait de code sur 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
Dans les sections suivantes, j'expliquerai différentes approches pour tester et tenter de contourner les limites de débit dans votre application.
Pour tester efficacement votre application pour ce type de vulnérabilité, l'automatisation est un outil puissant. Vous pouvez y parvenir en employant des scripts, tels que ceux de Python (comme je le fais souvent), ou en utilisant des outils comme Burp Suite (d'ailleurs, un excellent outil pour les testeurs et les professionnels de la cybersécurité). En outre, des outils comme Postman pourraient être utilisés pour automatiser les contrôles relativement facilement.
X-Originating-IP: 127.0.0.1
Utilisez des valeurs IP différentes dans chaque demande que vous envoyez.
Utilisez le double en-tête X-Forwared-For.
X-Forwarded-For: X-Forwarded-For: 127.0.0.1
Essayez la même chose avec des en-têtes différents.
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
Essayez de modifier l'agent utilisateur, le type de contenu, la langue d'acceptation, etc., ou les cookies, tout ce qui pourrait être utilisé comme identifiant d'utilisateur.
S'il existe une limite de débit de 3 essais par IP, tous les trois essais, modifiez la valeur IP de l'en-tête (ou d'autres en-têtes ou paramètres dans vos requêtes).
Essayez d'ajouter aux paramètres que vous envoyez
%00, %0d%0a, %0d, %0a, %09, %0C, %20
Par exemple
param1=value1%%0d%0a param2=value2%00
Par exemple, si vous demandez OTP pour la vérification des e-mails et que vous ne disposez que de 3 essais, utilisez les 3 essais pour
[email protected] [email protected]%00 [email protected]%0d%0a And so on
Si vous testez, par exemple, le point de terminaison /API/v1/signup, essayez d'effectuer une opération de force brute sur /Signup, /SignUp, /sign-up. Essayez d'ajouter des caractères vides (ci-dessus) aux points de terminaison d'origine.
Si la limite concerne les requêtes du point de terminaison /api/v1/resetpassword, essayez de le forcer brutalement en ajoutant des paramètres de requête - une fois la limite de débit atteinte, essayez, par exemple, /api/v1/resetpassword?param1=value1
Il se peut qu'une application ait une logique défectueuse : si vous vous connectez à votre compte avant chaque tentative/série de tentatives, la limite de débit est réinitialisée pour votre adresse IP et vous pouvez continuer votre attaque par force brute avec votre mot de passe. Si vous testez une fonctionnalité de connexion, vous pouvez le faire dans Burp Suit avec une attaque Pitchfork dans les paramètres (ou vous pouvez écrire votre propre script pour cela) pour chaque tentative/série de tentatives.
Voici mon exemple de la façon dont j'ai automatisé une simple vérification de l'en-tête X-Forwarded-For juste pour obtenir un POW :
from random import randint import requests import json url = "https://yourapp.net/api/v1/regconfirm-resend" data = { "email": "[email protected]" } 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}")
Une solution possible pourrait être l'utilisation de Cloudflare et de ses mécanismes. Une explication détaillée peut être trouvée ici restauration-original-visitor-ips . Je ne fournirai qu'un bref aperçu de ses mécanismes de défense.
Si vous utilisez des applications qui dépendent de l'adresse IP entrante du visiteur d'origine, une adresse IP Cloudflare est enregistrée par défaut. L'adresse IP d'origine du visiteur apparaît dans un en-tête HTTP ajouté appelé CF-Connecting-IP. En suivant les instructions de notre serveur Web, vous pouvez enregistrer l'adresse IP d'origine du visiteur sur votre serveur d'origine. Si cet en-tête HTTP n'est pas disponible lorsque les requêtes atteignent votre serveur d'origine, vérifiez la configuration de vos règles de transformation et de vos transformations gérées.
Si Pseudo IPv4 est défini sur Overwrite Headers - Cloudflare écrase les en-têtes Cf-Connecting-IP et X-Forwarded-For existants par une pseudo-adresse IPv4 tout en préservant la véritable adresse IPv6 dans l'en-tête CF-Connecting-IPv6.
REMARQUE : N'oubliez pas que lors de la mise en œuvre d'un tel mécanisme de défense, effectuez des tests approfondis. Cette approche pourrait ensuite être appliquée à l’ensemble du cluster et pourrait nuire à certaines fonctions et microservices là où elle n’est pas nécessaire. En un mot, lorsque vous corrigez une faille de sécurité, soyez prudent, car cela pourrait potentiellement avoir un impact sur l'ensemble de l'application. Analysez quelle partie de votre système pourrait être affectée négativement et testez tout avant d'envoyer les modifications à l'environnement de production.
Également publié ici .