애플리케이션에 로그인, 등록, 비밀번호 재설정/복구, 확인 링크 재전송 및 서버 요청이 필요한 기타 특정 기능과 같은 기본 기능이 포함되어 있는 경우 무차별 대입 공격 및 서비스에 상당한 부하 생성을 방지하는 메커니즘을 구현하는 것이 중요합니다. 이러한 메커니즘이 없으면 애플리케이션은 사용자에게 과도한 수의 이메일/OTP를 보내는 등 다양한 위협에 취약할 수 있으며 잠재적으로 금전적 및 평판 손상으로 이어질 수 있습니다.
많은 웹 애플리케이션에는 적절한 속도 제한 조치가 부족하여 결제 모델을 기반으로 요청 수를 제한하는 등 비즈니스 논리에 따른 제한에만 의존합니다. 그러나 일부 애플리케이션에는 특히 로그인 시도, 등록 및 기타 중요한 기능과 같은 작업에 대한 속도 제한이 포함되어 있습니다. 이러한 구현은 IP 주소 추적을 위해 X-Forwarded-For 헤더에 의존하는 경우가 많습니다.
간단한 예를 설명하기 위해 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과 같은 도구를 사용하면 비교적 쉽게 검사를 자동화할 수 있습니다.
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
사용자 에이전트, 콘텐츠 유형, 허용 언어 등이나 쿠키 등 사용자 식별자로 사용될 수 있는 모든 항목을 변경해 보세요.
IP당 3회 시도의 비율 제한이 있는 경우 3회 시도마다 헤더(또는 요청의 다른 헤더 또는 매개변수)의 IP 값을 변경합니다.
보내는 매개변수에 추가해 보세요.
%00, %0d%0a, %0d, %0a, %09, %0C, %20
예를 들어
param1=value1%%0d%0a param2=value2%00
예를 들어, 이메일 확인을 위해 OTP를 요청하는데 3번만 시도할 수 있는 경우 3번 시도를 사용하세요.
[email protected] [email protected]%00 [email protected]%0d%0a And so on
예를 들어 /API/v1/signup 엔드포인트를 테스트하는 경우 /Signup, /SignUp, /sign-up에 대해 무차별 공격을 수행해 보세요. 원래 끝점에 빈 문자(위의 내용)를 추가해 보세요.
/api/v1/resetpassword 엔드포인트의 요청에 제한이 있는 경우 일부 쿼리 매개변수를 추가하여 무차별 대입을 시도해 보세요. 비율 제한에 도달하면 예를 들어 /api/v1/resetpassword?param1=value1을 시도해 보세요.
앱의 논리에 결함이 있는 경우가 있을 수 있습니다. 각 시도/연속 시도 전에 계정에 로그인하면 IP에 대한 속도 제한이 재설정되고 비밀번호 무차별 대입 공격을 계속할 수 있습니다. 로그인 기능을 테스트하는 경우 각 시도/일련의 시도에 대해 설정에서 Pitchfork 공격을 사용하여 Burp Suit에서 이 작업을 수행할 수 있습니다(또는 이에 대해 고유한 스크립트를 작성할 수 있음).
다음은 POW를 얻기 위해 X-Forwarded-For 헤더에 대한 간단한 검사를 자동화하는 방법에 대한 예입니다.
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}")
가능한 해결책은 Cloudflare와 그 메커니즘을 사용하는 것일 수 있습니다. 자세한 설명은 여기 Restore-original-visitor-ips에서 확인할 수 있습니다. 나는 방어 메커니즘에 대한 간략한 개요만 제공하겠습니다.
원래 방문자의 수신 IP 주소에 의존하는 애플리케이션을 사용하는 경우 Cloudflare IP 주소가 기본적으로 기록됩니다. 원래 방문자 IP 주소는 CF-Connecting-IP라는 추가된 HTTP 헤더에 나타납니다. 당사의 웹 서버 지침에 따라 원본 서버에 원래 방문자 IP 주소를 기록할 수 있습니다. 요청이 원본 서버에 도달할 때 이 HTTP 헤더를 사용할 수 없는 경우 변환 규칙 및 관리형 변환 구성을 확인하세요.
의사 IPv4가 헤더 덮어쓰기로 설정된 경우 Cloudflare는 CF-Connecting-IPv6 헤더에 실제 IPv6 주소를 유지하면서 기존 Cf-Connecting-IP 및 X-Forwarded-For 헤더를 의사 IPv4 주소로 덮어씁니다.
참고: 이러한 방어 메커니즘을 구현할 때는 철저한 테스트를 수행해야 한다는 점을 기억하십시오. 이 접근 방식은 나중에 전체 클러스터에 적용될 수 있으며 불필요한 특정 기능과 마이크로서비스에 부정적인 영향을 미칠 수 있습니다. 간단히 말해서, 보안 위반을 수정하는 동안 잠재적으로 전체 애플리케이션에 영향을 미칠 수 있으므로 주의해야 합니다. 시스템의 어느 부분이 부정적인 영향을 받을 수 있는지 분석하고 프로덕션 환경에 변경 사항을 적용하기 전에 모든 것을 테스트하세요.
여기에도 게시되었습니다.