我在登錄功能埋的坑:HTTP重定向攻擊差點讓公司背鍋(附解決方案)
上周我在公司捅了個簍子——自己寫的登錄模塊差點成了釣魚網站的幫兇。今天就跟大家嘮嘮這個驚險過程,以及怎么避免HTTP重定向攻擊這個"隱形炸彈"。
一、那個讓測試妹子暴走的早晨
事情發生在某個陽光明媚的周一,測試組的小美突然沖進我們開發組:"你們的登錄接口被劫持了!用戶點完登錄直接跳轉到賭博網站!"
我當時的反應:"絕對不可能!我明明做了URL白名單驗證..."
1.1 問題重現:用戶登錄變賭博
我們復現了問題場景:
- 用戶訪問 www.our-app.com/login?redirect=/profile
- 輸入正確賬號密碼
- 頁面跳轉到...澳門首家線上賭場(!)
我盯著瀏覽器的Network面板,發現請求里赫然有個302狀態碼:
HTTP/1.1 302 Found
Location: https://malicious-site.com?steal_cookie=123abc
關鍵問題解析:起初我們以為用戶訪問的是正常路徑/profile,但實際攻擊發生時,redirect參數是經過精心偽裝的:
圖片
攻擊者如何操作?
- 構造釣魚鏈接:www.our-app.com/login?redirect=%2F%2Fmalicious-site.com(%2F是"/"的URL編碼)
- 服務器收到參數后:
// 未解碼直接拼接
String redirect = request.getParameter("redirect"); // 得到"http://malicious-site.com"
response.sendRedirect("https://our-app.com" + redirect);
實際跳轉地址變成:https://our-app.com//malicious-site.com瀏覽器自動解析為:https://malicious-site.com
為什么測試時沒發現?
我們在測試環境用的都是類似/profile的簡單路徑,完全沒料到這些騷操作:
- //外部網站 的路徑拼接攻擊
- @惡意域名 的特殊解析
- %編碼 的繞過手法
二、解剖這只"重定向蟑螂"
2.1 重定向的工作原理
圖片
就像快遞員送錯包裹:
- 用戶說:"送完這個去A地址"(帶redirect參數)
- 服務器說:"好的,下個包裹送到B地址"(返回302+Location)
- 快遞員(瀏覽器)無腦照做
2.2 漏洞代碼長啥樣?
這是我最初寫的危險代碼(Java示例):
// 危險示范!請勿模仿!
String redirectUrl = request.getParameter("redirect");
response.sendRedirect(redirectUrl);
三、我是怎么填坑的
3.1 第一層防護:白名單驗證
List<String> allowedPaths = Arrays.asList("/profile", "/dashboard");
if(!allowedPaths.contains(redirectParam)){
redirectParam = "/default"; // 跳轉到安全頁面
}
3.2 第二層防護:簽名校驗
給redirect參數加"防偽碼":
# 生成簽名
sign = hashlib.sha256(redirect_path + SECRET_KEY).hexdigest()
safe_url = f"{redirect_path}?sign={sign}"
# 驗證時
client_sign = request.GET.get('sign')
server_sign = hashlib.sha256(redirect_path + SECRET_KEY).hexdigest()
if client_sign != server_sign:
abort(403)
3.3 第三層防護:相對路徑轉換
把絕對URL變成相對路徑:
// 把 https://www.our-app.com/profile 轉為 /profile
function sanitizeRedirect(url) {
return new URL(url).pathname;
}
四、預防重定向攻擊的五個要點
- 絕不信任客戶端傳參:把redirect參數當嫌疑人審
- 禁用開放重定向:就像不給陌生人留家門鑰匙
- 設置跳轉延遲:重要操作前加二次確認
- 記錄可疑日志:給異常跳轉裝監控
- 定期安全掃描:用自動化工具查漏
五、血淚教訓總結
這次事故讓我明白:安全不是功能,而是底線。現在每次處理重定向時,我都會默念三遍:
"用戶傳參猛于虎,未經驗證就是賭,白名單加簽名鎖,安全紅線不能觸。"
最后送大家一個自查清單:
? [ ] 所有redirect參數是否強制校驗?
? [ ] 是否存在裸跳轉(直接拼接URL)?
? [ ] 是否配置了CSP安全策略?
? [ ] 是否禁用非必要的HTTP方法?
? [ ] 是否定期進行滲透測試?