如何防禦Node.js中的不安全跳轉
什麼是不安全的重定向?
對於任何web開發人員來說,不安全或未經驗證的重定向都是重要的安全考慮因素。Express為重定向提供了本地支持,使它們易於實現和使用。然而,Express將執行輸入驗證的工作留給了開發人員。Express是一種保持最低程度規模的靈活Node.js Web應用程序框架,為Web和移動應用程序提供一組強大的功能。
下面是OWASP.org網站給出的「未經驗證的重定向和轉發」的定義:
如果web應用程序接受不可信的輸入,可能導致web應用程序將請求重定向到不可信輸入中包含的URL,則可以進行未經驗證的重定向和轉發。
重定向通常在登錄和身份驗證過程中使用,因此可以在登錄之前將用戶重定向到他們所在的頁面。但根據業務需求或應用程序類型而有所不同,也存在其他重定向情況。
為什麼要避免重定向?
不驗證用戶輸入的重定向,可以使攻擊者具備發起網路釣魚詐騙的條件,從而竊取用戶憑據並執行其他惡意操作。
注意:當在Node.js或Express中實現重定向時,在伺服器端執行輸入驗證很重要。
如果攻擊者發現用戶沒有驗證外部用戶提供的輸入,他們可能會利用這個漏洞在論壇、社交媒體和其他公共場所發布專門設計的鏈接,讓用戶點擊它。
從表面上看,這些URL看起來合法且對用戶來說並無威脅,這是因為所有這些要重定向的URL都包含目標的主機名:
https://example.com/login?url=http://examp1e.com/bad/things
但是,如果伺服器端重定向邏輯未驗證輸入url參數的數據,則用戶可能最終會訪問黑客所提前設置的網站(examp1e.com),滿足攻擊的需求!以上只是攻擊者如何利用不安全重定向邏輯的一個例子。
不安全重定向例子並將其直接傳遞到Express res.redirect()方法中。因此,只要用戶通過身份驗證,Express就會將用戶重定向到輸入或提供的URL。
var express = require("express");
var port = process.env.PORT || 3000;
var app = express();
app.get("/login", function (req, res, next) {
if(req.session.isAuthenticated()) {
res.redirect(req.query.url);
}
});
app.get("/account", function (req, res, next) {
res.send("Account page");
});
app.get("/profile", function (req, res, next) {
res.send("Profile page");
});
app.listen(port, function() {
console.log("Server listening on port " + port);
});
輸入驗證有助於防止不安全的重定向
通常,最好避免在代碼中使用重定向和轉發。如果你一定需要在代碼中使用重定向,則首選的方法是使用映射到特定目標的預定義輸入,這被稱為白名單方法。以下就是實現這種方法的一個具體樣本步驟:
1.baseHostname會確保任何重定向都將用戶保留在研究人員的主機上;
2.redirectMapping是一個對象,它將預定義的輸入(例如,傳遞給url paramer的內容)映射到伺服器上的特定路徑;
3.validateRedirect()方法會判斷預定義的輸入是否存在,如果它們存在,則返回要重定向的適當路徑;
4.研究人員修改了/login邏輯,然後將baseHostname+redirectPath變數連接在一起,這就避免了任何用戶提供的輸入內容直接傳遞到Express res.redirect()方法中;
5.最後,研究人員使用encodeURI()方法作為額外的安全保證,確保連接字元串的URI部分被正確編碼,以允許乾淨的重定向。
//Configure your whitelist
var baseHostname = "https://example.com";
var redirectMapping = {
"account": "/account",
"profile": "/profile"
}
//Create a function to validate whitelist
function validateRedirect(key) {
if(key in redirectMapping) {
return redirectMapping[key];
}else{
return false;
}
}
app.get("/login", function (req, res, next) {
if(req.session.isAuthenticated()) {
redirectPath = validateRedirect(req.query.url);
if(redirectPath) {
res.redirect(encodeURI(baseHostname + redirectPath));
}else{
res.send("Not a valid redirect!");
}
}
});
其他重定向場景
在某些情況下,將每個組合列入白名單是不切實際的,不過有些安全平台仍然希望重定向用戶並將其保留在域內某些邊界內。當外部提供的值遵循特定模式(例如16個字元的字母數字字元串)時,最好這樣做。字母數字字元串是理想的,因為它們不包含任何可能引入其他攻擊的特殊字元,例如目錄/路徑遍歷(依賴於諸如...和向後/向前斜杠之類的字元)。
例如,安全平台可能希望在用戶登錄後將其重定向回電子商務網站上的特定產品。由於電子商務網站對每種產品都有唯一的字母數字值,因此安全平台可以通過始終根據RegEx白名單驗證外部輸入來實現安全重定向。在本文所講的樣本在,研究者用的是productId變數。
//Configure your whitelist
var baseHostname = "https://example.com";
app.get("/login", function (req, res, next) {
productId = (req.query.productId || "");
whitelistRegEx = /^[a-zA-Z0-9]$/;
if(productId) {
//Validate the productId is alphanumeric and exactly 16 characters
if(whitelistRegEx.test(productId)) {
res.redirect(encodeURI(baseHostname + "/item/" + productId));
}else{
//The productId did not meet the RegEx whitelist, so return an error
res.send("Invalid product ID");
}
}else{
//No productId was provided, so redirect to home page
res.redirect("/");
}
});
最後,安全平台發出警告,警告用戶他們正在被自動重定向是值得重視的。如果安全平台有意將用戶重定向到域外,則可能需要在流程中創建一個中間頁面,該頁面會發出如下警告,並包含用戶要重定向到的URL。
註:本文是以Hailstone為例進行講解的,Hailstone是一個應用程序安全平台,它有查找代碼中的漏洞功能。
※NUUO網路視頻攝錄機Peekaboo漏洞:CVE-2018-1149、CVE-2018-1150
※安卓應用程序滲透測試(二)
TAG:嘶吼RoarTalk |