csrf攻擊防范的核心在于驗證請求來源合法性。解決方案包括:1.referer頭檢查,通過nginx配置限制請求來源,但存在被偽造風險;2.origin頭檢查,相比referer更可靠,但瀏覽器兼容性需注意;3.雙重提交Cookie,前端生成Token并同時置于cookie和請求參數中,nginx初步驗證,安全性更高但實現復雜;4.自定義請求頭驗證,適用于api接口,避免跨域問題。選擇方案時應權衡安全性和實現成本,結合多種方法提升防護效果。此外,nginx層防護不能替代后端驗證,仍需后端進一步確認token有效性。其他手段如同步令牌模式、samesite cookie及用戶行為驗證也應納入整體防御策略。
CSRF攻擊防范的核心在于驗證請求的來源是否合法。在Nginx層進行防護,可以有效攔截惡意請求,減輕后端服務器的壓力。
解決方案:
-
Referer Header 檢查: Nginx可以配置檢查Referer請求頭。如果Referer頭不存在或不在白名單內,則拒絕請求。 這種方法簡單直接,但Referer頭可以被篡改,因此并非萬無一失。
server { listen 80; server_name example.com; location / { if ($http_referer !~ "^https?://(www.)?example.com") { return 403; } proxy_pass http://backend; } }
-
Origin Header 檢查: Origin頭比Referer頭更可靠,因為它不能被瀏覽器在跨域請求中修改。 Nginx可以配置檢查Origin頭,并只允許來自特定域的請求。 但要注意,Origin頭并非所有瀏覽器都支持。
server { listen 80; server_name example.com; location / { if ($http_origin !~ "^https?://(www.)?example.com") { return 403; } proxy_pass http://backend; } }
-
雙重提交 Cookie (double Submit Cookie): 這種方法需要在前端生成一個隨機的token,將其同時存儲在cookie中和一個請求參數中。 Nginx可以配置驗證這兩個token是否一致。 雖然增加了復雜度,但安全性更高。
-
前端生成token并設置cookie: (假設使用JavaScript)
function setCookie(name,value,days) { var expires = ""; if (days) { var date = new Date(); date.setTime(date.getTime() + (days*24*60*60*1000)); expires = "; expires=" + date.toUTCString(); } document.cookie = name + "=" + (value || "") + expires + "; path=/"; } function generateToken() { // 簡單示例,實際應用中應使用更安全的隨機數生成方法 return Math.random().toString(36).substring(2); } const csrfToken = generateToken(); setCookie('csrf_token', csrfToken, 7); // 設置cookie有效期為7天 // 將csrfToken添加到表單或AJAX請求參數中 // 例如: <input type="hidden" name="csrf_token" value="${csrfToken}">
-
Nginx配置: (這里假設后端服務會驗證這個token,Nginx只做初步的檢查)
server { listen 80; server_name example.com; location / { # 檢查是否存在cookie和請求參數中的csrf_token if ($http_cookie !~* "csrf_token=([^;]+)") { return 403; } if ($request_method = POST) { if ($arg_csrf_token = "") { return 403; } # 這里無法直接比較cookie和參數的值,只能簡單判斷存在性 # 實際的token驗證需要在后端進行 } proxy_pass http://backend; } }
-
-
自定義請求頭驗證: 類似于雙重提交Cookie,但將Token放在自定義的請求頭中。 這種方式避免了Cookie的跨域問題,更適用于API接口。
-
前端設置自定義請求頭:
// 假設已經通過某種方式獲取了CSRF token (例如從cookie中讀取) const csrfToken = getCookie('csrf_token'); // 需要自己實現getCookie函數 fetch('/api/resource', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken // 自定義請求頭 }, body: JSON.stringify({ data: 'your data' }) }) .then(response => response.json()) .then(data => console.log(data));
-
Nginx配置:
server { listen 80; server_name example.com; location /api/ { if ($http_x_csrf_token = "") { return 403; } proxy_pass http://backend; } }
-
如何選擇合適的CSRF防護方案?
選擇哪種方案取決于你的應用場景和安全需求。 Referer和Origin檢查簡單易用,但安全性較低。 雙重提交Cookie和自定義請求頭驗證安全性更高,但實現起來更復雜。 可以根據實際情況選擇組合使用多種方案。 關鍵在于理解每種方案的優缺點,并根據自身情況進行權衡。
Nginx層防護CSRF的局限性是什么?
Nginx層主要負責請求的初步過濾,它無法完全替代后端服務器的CSRF防護。 例如,Nginx無法驗證雙重提交Cookie中的token是否與用戶的Session關聯。 因此,即使在Nginx層進行了防護,后端服務器仍然需要進行更嚴格的驗證。 Nginx主要起一個前置過濾的作用,減輕后端壓力,提高整體安全性。
除了Nginx,還有哪些CSRF防護手段?
除了Nginx層防護,還有以下CSRF防護手段:
- 同步令牌模式 (Synchronizer Token Pattern, STP): 這是最常見的CSRF防護方法。 服務器為每個用戶的會話生成一個唯一的CSRF令牌,并將該令牌嵌入到html表單中。 當用戶提交表單時,服務器會驗證表單中的CSRF令牌是否與會話中存儲的令牌匹配。
- SameSite Cookie: SameSite屬性可以控制Cookie是否隨跨站請求發送。 設置SameSite=Strict可以完全阻止Cookie在跨站請求中發送,從而有效防止CSRF攻擊。 但要注意,SameSite=Strict可能會影響某些正常的跨站請求,需要謹慎使用。 SameSite=Lax 則允許部分跨站請求(例如GET請求)攜帶Cookie。
- 用戶行為驗證: 例如,要求用戶在執行敏感操作前輸入密碼或進行驗證碼驗證。
這些方法通常需要在后端代碼中實現。 結合Nginx層的防護,可以構建更強大的CSRF防御體系。