불완전한 URL 부분 문자열 검증

Incomplete URL Substring Sanitization

설명

URL을 단순 문자열로 다루며 허용 도메인이 포함되어 있는지(예: includes, indexOf, 단순 endsWith)만 확인하면, 공격자는 서브도메인, 사용자정보(@), 경로/쿼리 문자열 등에 허용 도메인 문자열을 끼워 넣어 검증을 우회할 수 있습니다. 그 결과 사용자를 외부 악성 사이트로 리다이렉트(Open Redirect)하거나, 서버가 내부망으로 요청을 보내게 만드는 SSRF로 악용될 수 있습니다. 예: https://example.com.attacker.io, http://[email protected], https://attacker.io/?next=https://example.com 등.

잠재적 영향

  • Open Redirect(오픈 리다이렉트): 피해자를 피싱 사이트로 유도하거나 OAuth redirect_uri 검증을 우회해 세션/토큰 탈취로 이어질 수 있습니다.

  • SSRF(Server-Side Request Forgery): 서버가 내부망(예: 169.254.169.254 메타데이터, 사내 API)으로 요청을 보내도록 유도되어 정보 유출, 포트 스캔이 가능해집니다.

  • 데이터 유출: 서버가 민감한 자원에 접근해 응답을 외부로 전달할 가능성이 있습니다.

  • 보안 정책 우회: 허용 도메인 기반의 리다이렉트/프록시 정책을 무력화하여 접근 제어를 우회할 수 있습니다.

해결 방법

  • URL 파싱 후 검증: new URL(url).hostname으로 호스트명을 추출하고, 명시적 Allowlist와 정확히 일치 비교하세요.

  • 서브도메인 허용 시 라벨 경계 강제: host === 'example.com' || host.endsWith('.example.com') 형태로만 허용합니다. 단순 endsWith('example.com')은 evil-example.com 같은 다른 도메인을 통과시킬 수 있어 금지합니다.

  • 스킴/포트 검증: protocol이 'https:'인지 확인하고, 필요 시 포트도 제한하세요.

  • 상대 리다이렉트 권장: 가능하면 외부 절대 URL 대신 애플리케이션 내부 경로(상대 경로)만 리다이렉트하세요.

  • SSRF 방어(서버 outbound 요청 시): IP 주소 대상 차단, 사설/메타데이터 대역(127.0.0.0/8, 10.0.0.0/8, 169.254.169.254 등) 거부, DNS 재검증, 타임아웃/리다이렉트 금지 설정을 적용하세요.

  • 부분 문자열 검증 금지: includes, indexOf, 정규식의 불완전한 패턴 등 부분 일치 기반 검증을 사용하지 마세요.

취약한 코드 및 안전한 코드 예시

취약한 코드

안전한 코드

설명:

  • 취약한 코드: includes 같은 부분 문자열 검사는 공격자가 허용 도메인 문자열을 서브도메인(example.com.attacker.io), 사용자정보([email protected]), 경로/쿼리(/?next=https://example.com) 등에 넣어 우회할 수 있습니다. 이 경우 악성 사이트로의 오픈 리다이렉트 또는 SSRF가 발생할 수 있습니다.

  • 안전한 코드: new URL로 파싱한 뒤 hostname을 추출해 정확한 Allowlist 매칭을 수행하고, 서브도메인만 허용하도록 라벨 경계를 강제했습니다(host === 'example.com' || host.endsWith('.example.com')). 또한 스킴이 https:인지 확인하고, 조건을 만족하지 않으면 안전한 기본 경로로 리다이렉트하여 우회를 차단합니다.

참조

Last updated