Open Redirect는 SaaS가 사용자 입력 URL을 검증 없이 redirect Location 헤더에 그대로 사용하는 결함이다.
공격자는 정상 도메인(예: yoursaas.com)의 redirect URL을 자기 피싱 사이트로 가리키게 만들고, 그 링크를 메일에 넣어 보낸다. 사용자는 정상 도메인이라 신뢰하고 클릭한 후 가짜 로그인 페이지에 도달한다.
이 글은 4가지 우회 패턴, Django 표준 화이트리스트 코드, 30초 자가진단을 정리했다.
한눈에 보는 Open Redirect
Q. Open Redirect는 왜 위험한가요? A. 피싱 메일이 정상 도메인 URL을 거쳐 가짜 사이트로 도착합니다. 도메인 검증 + SPF/DMARC 통과 상태로 메일 필터를 우회하며, 사용자 신뢰가 깨집니다. Q. ?next= 같은 파라미터를 안 쓰면 되나요? A. OAuth 콜백, SSO redirect, 결제 완료 페이지 등에 사실상 필요합니다. 제거가 아닌 화이트리스트 검증이 표준입니다. Q. URL 검증을 어떻게 하나요? A. urlparse로 netloc을 추출하고 자기 도메인 화이트리스트와 비교합니다. 상대 경로(/dashboard)만 허용하는 게 가장 안전합니다. Q. //evil.com 같은 우회는 막을 수 있나요? A. //로 시작하는 프로토콜 상대 URL은 자기 도메인으로 보이지만 다른 호스트로 향합니다. urlparse 검증이 필수입니다.4가지 자주 우회되는 패턴
| # | 패턴 | 예시 |
|---|---|---|
| 1 | startswith('/') 단순 검증 | //evil.com이 통과 (프로토콜 상대 URL) |
| 2 | 도메인 부분 일치 검색 | yoursaas.com.evil.com이 통과 |
| 3 | URL 디코딩 누락 | %2F%2Fevil.com이 디코드 후 //evil.com |
| 4 | OAuth state 미검증 | redirect_uri 변경 + state 재사용으로 토큰 탈취 |
Django 표준 화이트리스트 구현
from urllib.parse import urlparse
from django.http import HttpResponseRedirect
from django.conf import settings
ALLOWED_HOSTS_REDIRECT = {'yoursaas.com', 'www.yoursaas.com'}
def safe_redirect(request, default='/'):
next_url = request.GET.get('next', '') or request.POST.get('next', '')
if not next_url:
return HttpResponseRedirect(default)
parsed = urlparse(next_url)
# 1. 상대 경로만 허용 (가장 안전)
if not parsed.netloc and not parsed.scheme:
# //evil.com 같은 프로토콜 상대 URL 차단
if next_url.startswith('//'):
return HttpResponseRedirect(default)
return HttpResponseRedirect(next_url)
# 2. 절대 URL은 화이트리스트 호스트만
if parsed.netloc in ALLOWED_HOSTS_REDIRECT and parsed.scheme in {'http', 'https'}:
return HttpResponseRedirect(next_url)
return HttpResponseRedirect(default)
핵심 4요소: (1) urlparse 사용 (2) // 프로토콜 상대 차단 (3) 화이트리스트 완전 일치 (4) scheme http(s) 한정.
javascript: 스킴은 XSS 진입점이 되므로 반드시 차단해야 한다.
Django 기본 django.utils.http.url_has_allowed_host_and_scheme 사용이 가장 깔끔하다.
30초 자가진단
# 1. ?next= 우회 시도 — //evil.com
curl -sI "https://yourdomain.com/login?next=//evil.com" | grep -i location
# 2. URL 인코딩 우회 — %2F%2Fevil.com
curl -sI "https://yourdomain.com/login?next=%2F%2Fevil.com" | grep -i location
# 3. javascript: 스킴
curl -sI "https://yourdomain.com/login?next=javascript:alert(1)" | grep -i location
Location 헤더에 evil.com 또는 javascript:가 들어가면 Open Redirect 결함이다. CWE-601: URL Redirection to Untrusted Site 참조.
24시간 패치 절차
| 순위 | 조치 |
|---|---|
| 1 | 모든 redirect 함수에 url_has_allowed_host_and_scheme 적용 |
| 2 | OAuth redirect_uri 사전 등록 + state 파라미터 검증 |
| 3 | 로그인·결제 완료·SSO 콜백 next 파라미터 화이트리스트화 |
| 4 | access log에 redirect Location 모니터링 알람 |
지금 해야 할 것
실무자: CodeScan 무료 스캔으로 30초 점검.
CISO·임원: 피싱 시뮬레이션 포함 점검은 SENTRIX 30분 1:1 상담.
정상 도메인 신뢰가 깨지면 브랜드 피해는 회복이 어렵다.