SSRF: 서버 측 요청 위조
SSRF란?
SSRF (Server-Side Request Forgery)는 서버를 속여서, 공격자가 직접 접근할 수 없는 내부망(Internal Network)의 자원에 접근하게 만드는 공격입니다.
보통 해커는 방화벽 밖에서 공격하지만, SSRF는 "서버가 서버를 공격하게" 만듭니다. 마치 은행원이 보이스피싱에 속아서, 금고 문을 직접 열어주는 것과 같습니다.
2. 왜 위험한가? (AWS 메타데이터 탈취)
많은 개발자들이 "클라우드 썼으니까 안전하겠지"라고 생각하지만, SSRF는 클라우드 환경에서 더 치명적입니다.
2.1. AWS EC2 메타데이터 서비스 (IMDS)
AWS EC2 인스턴스는 169.254.169.254라는 특수한 IP를 통해 자신의 정보를 조회할 수 있습니다.
문제는 여기에 IAM Role 자격 증명(Access Key, Secret Key)이 포함되어 있다는 점입니다.
# 공격자가 웹 애플리케이션에 이런 요청을 보냄
GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/admin-role
만약 웹 서버가 이 요청을 그대로 실행해서 결과를 공격자에게 보여준다면? 공격자는 서버의 관리자 권한을 탈취하게 됩니다. 그 뒤로는 S3 버킷을 다 지우거나, 채굴기를 돌리는 등 마음대로 할 수 있습니다.
3. 실제 사례: Capital One 해킹 사건 (2019)
역대급 개인정보 유출 사건으로 꼽히는 Capital One 해킹도 SSRF가 원인이었습니다.
- Capital One은 AWS를 사용 중이었고, WAF(Web Application Firewall)에 SSRF 취약점이 있었습니다.
- 해커는 WAF 서버를 속여서 메타데이터 서비스(
169.254.169.254)에 접근했습니다. - WAF 서버에 부여된 IAM Role 권한을 획득했습니다. (불행히도 권한이 너무 강력했습니다 - S3 Full Access).
- 탈취한 권한으로 S3에 저장된 1억 명의 신용 카드 신청 정보를 훔쳤습니다.
이 사건 이후로 AWS는 보안을 강화한 IMDSv2를 내놓았습니다. (세션 토큰 필수).
3. 언어별 대응 방법
Java, Python, Node.js 등 언어별로 방어 코드를 짜는 법을 정리해봤다.
3.1. Java
Java는 java.net.URL 클래스를 사용할 때 주의해야 합니다. 오픈 소스 라이브러리인 'ssrf-agent'를 사용하는 것이 좋습니다.
// 위험한 코드
URL url = new URL(userInput);
URLConnection conn = url.openConnection();
3.2. Python
requests 라이브러리를 많이 쓰지만, 기본적으로 리다이렉트를 따라갑니다. allow_redirects=False 옵션을 꼭 켜세요.
또한 SafeCurl 같은 래퍼 라이브러리를 쓰는 것도 방법입니다.
4. 방어 방법 (Defense in Depth)
SSRF는 단순히 "URL 검사"만으로는 막기 어렵습니다. 여러 계층에서 방어해야 합니다.
4.1. 입력값 검증 (Whitelisting is King)
가장 확실한 방법은 허용 목록(Allow-list)을 쓰는 것입니다.
// ✅ 안전한 코드: 도메인 화이트리스트
const ALLOWED_DOMAINS = ['api.google.com', 'graph.facebook.com'];
function isValidUrl(inputUrl) {
const url = new URL(inputUrl);
return ALLOWED_DOMAINS.includes(url.hostname);
}
블랙리스트(차단 목록)는 우회하기 쉽습니다.
127.0.0.1차단 ->2130706433(십진수),0x7F000001(16진수) 등으로 우회 가능.localhost차단 ->lvh.me,localtest.me(DNS Rebinding) 등으로 우회 가능.
4.2. 네트워크 격리 (VPC)
애플리케이션이 외부 인터넷으로 나가는 트래픽(Outbound Traffic)을 제어해야 합니다.
- 웹 서버가 내부망의 다른 포트나 사설 IP 대역(Private Subnet)에 접근하지 못하도록 방화벽 규칙(Security Group)을 설정하세요.
4.3. 결과값 검증
요청을 보냈더라도, 응답값을 사용자에게 그대로 보여주지 마세요. 응답의 Content-Type이나 포맷이 예상한 것인지 확인해야 합니다.
6. 테스트 도구 (Red Team)
내 서버가 취약한지 어떻게 알 수 있을까요? 다음 도구들을 사용해 보세요.
- Burp Suite Collaborator: 외부로 나가는 요청(OOB)을 탐지하는 데 필수적입니다.
- SSRFmap: SSRF 취약점을 자동으로 스캔하고 익스플로잇하는 도구입니다.
- Gopherus: Redis나 MySQL 공격을 위한 Gopher 페이로드를 생성해 줍니다.
- Interactsh: Burp Collaborator의 무료 오픈소스 대안입니다.
7. FAQ
Q. fetch 말고 Axios나 Request 라이브러리는 안전한가요?
A. 아니요. 라이브러리 문제가 아니라, 로직 문제입니다. 어떤 HTTP 클라이언트를 쓰든, 사용자가 입력한 URL을 검증 없이 요청하면 취약합니다. Axios도 기본적으로 리다이렉트를 따라갑니다.
Q. 리다이렉트(Redirect)는 괜찮나요?
A. 위험합니다. http://safe.com으로 요청을 보냈는데, 그 서버가 http://internal-server로 리다이렉트 응답(302)을 줄 수 있습니다. 많은 HTTP 라이브러리가 리다이렉트를 자동으로 따라갑니다. 옵션에서 fail on redirect를 설정하거나, 리다이렉트 된 최종 URL도 검사해야 합니다.
Q. DNS Rebinding 공격이 뭔가요?
A. 처음엔 evil.com이 1.2.3.4(외부 IP)를 가리키다가, 검증을 통과한 직후(Time-of-Check to Time-of-Use), 127.0.0.1(내부 IP)로 DNS 응답을 바꾸는 공격입니다.
방어법:
- 호스트네임을 먼저 IP로 변환(Resolve)합니다.
- 그 IP가 안전한지 검사합니다.
- 호스트네임이 아닌, 검증된 IP 주소로 요청을 보냅니다. (Host 헤더는 원래 호스트네임 유지)
Q. Gopher 프로토콜은 어디에 쓰나요?
A. Gopher는 옛날 프로토콜이지만, 공격자에게는 강력한 무기입니다. 개행 문자(\r\n)를 포함할 수 있어서, Gopher URL 안에 Redis 명령어, SMTP 이메일 전송 명령 등을 숨겨서 보낼 수 있습니다.
사용하지 않는 프로토콜(gopher, ftp 등)은 라이브러리 차원에서 비활성화하세요.