설명
Open Redirect는 서버가 사용자 입력을 충분히 검증하지 않고 리다이렉트 대상 URL에 그대로 사용하여 발생하는 취약점입니다. 공격자는 합법적으로 보이는 도메인 링크를 먼저 클릭하게 만든 뒤, 쿼리스트링 등의 파라미터를 통해 사용자를 임의의 외부 악성 사이트로 이동시킬 수 있습니다. 이를 통해 피싱 페이지로 유도하여 자격 증명을 탈취하거나, OAuth/SSO 흐름에서 코드 또는 토큰을 가로채는 등의 공격이 가능합니다.
잠재적 영향
- 피싱/자격 증명 탈취: 합법적인 사이트를 거쳐 이동되는 것처럼 위장하여 로그인 페이지 등으로 유도, ID/비밀번호와 같은 민감 정보를 수집할 수 있습니다.
- 세션/토큰 탈취 (OAuth/SSO): 리다이렉트 파라미터를 악용해 인증 코드나 액세스 토큰의 반환 경로를 공격자 도메인으로 바꾸어 탈취할 수 있습니다.
- 악성 사이트 유도 및 악성코드 감염: 사용자를 악성 다운로드/피싱 사이트로 이동시켜 악성코드 감염, 추가 공격(스미싱/스피어피싱)으로 이어질 수 있습니다.
- 보안 정책 우회: Open Redirect를 중간 단계로 활용해 도메인 허용 정책을 우회하거나, 이메일/메신저 보안 필터를 회피할 수 있습니다.
해결 방법
- 상대 경로(내부 경로)만 허용: 내부 이동은 미리 허용한 서버 내 경로로 제한하세요. 외부 이동이 필요하면 아래의 고정 매핑을 사용하세요.
- 허용 목록(allowlist) 사용: 내부 이동은 허용된 경로 목록에서만 선택하고, 외부 도메인은 미리 정의된 키→URL 매핑으로만 허용하세요.
- 기본값(fallback) 적용: 검증 실패 시 안전한 기본 경로("/")로 리다이렉트하세요.
- URL 검증: 위험해 보이는 부분 문자열만 차단하는 방식에 의존하지 말고, 정규화한 값을 허용 목록과 정확히 비교하세요.
- Next.js에서는
NextResponse.redirect(new URL(..., request.url))또는 App Router의redirect(...)에 들어가는 값을 같은 기준으로 검증하세요.
예시
변경 전
javascript
const express = require("express");
const app = express();
// 취약: 사용자 입력을 그대로 사용하여 리다이렉트
app.get("/go", (req, res) => {
const target = req.query.u; // 사용자 제어 입력
return res.redirect(target); // 검증 없음 (Open Redirect)
});
app.listen(3000);
변경 후
javascript
const express = require("express");
const app = express();
// 안전: 내부 경로 허용 목록 + 외부 도메인 키 매핑
const allowedPaths = new Set(["/home", "/dashboard", "/help"]);
const externalMap = new Map([
["docs", "https://docs.example.com"],
["status", "https://status.example.com"],
]);
app.get("/go", (req, res) => {
const next = typeof req.query.next === "string" ? req.query.next.trim() : "";
const siteKey = typeof req.query.site === "string" ? req.query.site.trim() : "";
// 1) 내부 경로만 허용: 사전에 정의된 경로로 제한
if (allowedPaths.has(next)) {
return res.redirect(next);
}
// 2) 외부 리다이렉트는 키→URL 매핑으로만 허용
const extUrl = externalMap.get(siteKey);
if (extUrl) {
return res.redirect(extUrl);
}
// 3) 검증 실패 시 안전한 기본 경로로 이동
return res.redirect("/");
});
app.listen(3000);
설명:
- 변경 전: 사용자 입력(u)을 검증 없이 Location 헤더에 반영하여 임의의 도메인으로 이동이 가능합니다. 공격자는 합법적인 사이트 링크를 이용해 사용자를 악성 사이트로 리다이렉트하는 피싱(Open Redirect) 공격을 수행할 수 있습니다.
- 변경 후: 내부 이동은 사전 정의한
allowedPaths에 포함된 경로만 허용해 외부 URL을 차단합니다. - 변경 후: 쿼리 값의 문자열 타입을 먼저 확인하고, 외부 이동은
Map에 등록된site키만 선택하게 하여 배열 입력이나 상속 프로퍼티가 리다이렉트 대상으로 해석되지 않도록 합니다. - 변경 후: 검증에 실패하면 안전한 기본 경로(
/)로 리다이렉트하여 악용 가능성을 줄입니다.