SSRF(Server-Side Request Forgery, 서버 사이드 요청 위조)는 공격자가 서버를 매개체로 삼아 내부 네트워크나 외부 서비스에 악의적인 요청을 보내는 취약점이다. 방화벽 뒤에 있는 내부 서비스, 클라우드 메타데이터, 데이터베이스에 접근할 수 있다.
공격 시나리오
공격자 → 서버(취약) → 내부 서비스 (직접 접근 불가 경로)
예시:
1. URL 패치 기능 악용:
POST /api/fetch
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
2. 이미지 URL 악용:
POST /upload
{"image_url": "http://internal-db:6379/"} ← Redis 접근
3. PDF 생성 악용:
<img src="http://localhost:8080/admin"> ← 내부 어드민 페이지
주요 공격 대상
| 대상 | URL | 획득 가능 정보 |
|---|
| AWS 메타데이터 | 169.254.169.254/latest/meta-data/ | IAM 자격증명 |
| GCP 메타데이터 | metadata.google.internal | 서비스 계정 토큰 |
| 내부 Redis | redis://localhost:6379 | 캐시 데이터 |
| 내부 Elasticsearch | localhost:9200/_cat/indices | 인덱스 목록 |
| 내부 Kubernetes API | kubernetes.default.svc | 클러스터 정보 |
우회 기법
IP 표현 변형:
http://127.0.0.1 → http://2130706433 (10진수)
http://127.0.0.1 → http://0x7f000001 (16진수)
http://127.0.0.1 → http://127.1 (단축형)
http://localhost → http://spoofed.attacker.com → 127.0.0.1 (DNS 리바인딩)
URL 인코딩:
http://127.0.0.1 → http://%31%32%37%2e%30%2e%30%2e%31
리다이렉트 체인:
http://attacker.com/redirect → 301 → http://internal-service/
방어 방법
python
import ipaddress, socket
from urllib.parse import urlparse
BLOCKED_NETS = [
ipaddress.IPv4Network("10.0.0.0/8"),
ipaddress.IPv4Network("172.16.0.0/12"),
ipaddress.IPv4Network("192.168.0.0/16"),
ipaddress.IPv4Network("127.0.0.0/8"),
ipaddress.IPv4Network("169.254.0.0/16"), # 링크-로컬
]
def is_safe_url(url: str) -> bool:
parsed = urlparse(url)
ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
return not any(ip in net for net in BLOCKED_NETS)
| 방어책 | 설명 |
|---|
| 허용 목록(Allowlist) | 요청 가능한 도메인/IP 명시 |
| 사설 IP 차단 | RFC1918, 링크-로컬 주소 차단 |
| DNS 재바인딩 방어 | DNS 결과 캐싱 후 재확인 |
| 응답 필터링 | 내부 정보 포함 응답 차단 |
관련 개념