flawopen.com/SSRF/Node.js fetch()와 SSRF
Node.js fetch()는 SSRF를 막아 주나요?
아니요. 서버의 fetch()는 서버에서 요청을 보냅니다. 호출자가 목적지를 정하면 자신은 접근할 수 없는 시스템에 서버를 보내도록 유도할 수 있습니다. 주소를 확인하지 않고 택배를 보내는 것과 같습니다. 위험은 서버 네트워크, 권한, URL 정책과 리디렉션에 달려 있습니다.
providerId 같은 사용자 선택을 앱에서 설정한 출처에 고정 매핑해 임의 URL을 받지 않습니다.근본 원인: 서버가 호출자 선택 목적지를 신뢰
Node.js fetch()는 일반 HTTP client이지 SSRF 정책 엔진이 아닙니다. 허용 네트워크를 결정하지 않으며 브라우저 CORS도 서버 경계를 만들지 않습니다. URL 파싱만으로는 부족합니다. 허용 hostname이 금지 IP로 해석되거나 응답이 다른 host로 redirect할 수 있습니다. 사용자 avatar, webhook, 문서, 미리보기를 가져오는 기능이 위험 경로가 됩니다.
요청이 신뢰 경계를 넘는 과정
호출자가 URL에 영향을 줌
이미지 미리보기처럼 endpoint가 전체 URL이나 URL을 구성할 데이터를 받습니다.
서버가 요청을 보냄
HTTP client는 서버 프로세스의 네트워크 경로, DNS, proxy와 권한을 사용합니다.
리디렉션이 목적지를 바꿈
Fetch는 기본적으로 redirect를 따릅니다. 처음 허용된 대상이 Location으로 금지된 host를 가리킬 수 있습니다.
응답이 접근 가능한 데이터를 노출
네트워크와 정책에 따라 내부 서비스나 클라우드 metadata에 닿을 수 있습니다. 모든 fetch에서 자동 발생하는 것은 아닙니다.
위험한 Node.js 패턴과 안전한 패턴
// 호출자가 준 임의 URL을 가져오지 마세요.
const response = await fetch(userProvidedUrl);
// 호출자는 key만 고르고 네트워크 목적지는 고르지 않습니다.
const destinations = new Map([
["status", new URL("https://status.example/")],
["docs", new URL("https://docs.example/")],
]);
const target = destinations.get(providerId);
if (!target) throw new Error("Unknown provider");
const response = await fetch(target, {
redirect: "error",
signal: AbortSignal.timeout(3000),
});
if (!response.ok) throw new Error("Upstream request failed");
사용자가 URL을 입력해야 한다면
가능하면 provider ID만 받고 고정 목적지 맵으로 요청을 만드세요. 임의 공개 URL이 필수라면 필요한 scheme과 port만 허용하고 user-info, loopback, private, link-local 및 금지된 IPv4/IPv6 주소는 거부합니다. 모든 DNS 주소를 검증하고 재검증되지 않은 lookup 없이 검증된 IP로 연결합니다. 자동 redirect를 끄거나 매 홉을 검증하세요. 169.254.169.254와 활성화된 IPv6 metadata를 포함해 outbound 네트워크도 제한합니다. 시간, 응답 크기, 동시성을 제한하고 내부 자격 증명은 전달하지 않습니다.
SSRF 방지 체크리스트
- ✓임의 URL 대신 검증된 provider key를 앱 소유 고정 목적지에 매핑합니다.
- ✓
https:와 예상 port만 허용하고 URL 자격 증명, 알 수 없는 host, IP literal, 금지 대역을 거부합니다. - ✓
redirect: "error"로 redirect를 끕니다. 필요하면 연결 전 매 목적지를 검증합니다. - ✓모든 A/AAAA 응답을 검증하고 hostname 인증을 유지하며 연결을 검증된 주소에 고정합니다. retry와 proxy에도 적용합니다.
- ✓IPv6 포함 loopback, private, link-local, metadata 네트워크를 egress 방화벽/proxy에서 차단합니다. 앱 검사만 믿지 마세요.
- ✓시간, 응답 byte, 동시성 제한을 두고 cookie, 인증 header, 클라우드 자격 증명을 전달하지 않습니다.
- ✓AWS에서는 심층 방어로 IMDSv2를 요구하고 metadata 접근을 제한합니다. URL과 egress 통제를 대체하지 않습니다.
자주 묻는 질문
아니요. redirect, IPv4/IPv6 표기, DNS rebinding, proxy, DNS 확인과 연결 사이의 경합이 단순 검사를 우회할 수 있습니다. 고정 허용 목록을 우선하고 임의 목적지가 필요하면 모든 주소를 검증해 연결을 고정하며 네트워크 출구에서도 차단하세요.
아니요. IMDSv2 토큰 절차는 일부 위험을 줄이지만 다른 내부 서비스나 설정에 따른 metadata는 여전히 대상이 될 수 있습니다. 목적지와 egress 제어를 유지하세요.
1차 출처
- OWASP — SSRF 방지 치트 시트
- Node.js — 전역 fetch API
- WHATWG Fetch 표준 — redirect 모드
- AWS — EC2 인스턴스 메타데이터 옵션
- CWE-918 — Server-Side Request Forgery