CSRF(Cross-Site Request Forgery,跨站請求偽造)是一種網絡攻擊方式,它利用已認證用戶在受信任網站上的身份,誘使用戶在不知情的情況下執行惡意操作。具體來說,攻擊者通過各種方式(如發送惡意鏈接、在第三方網站上嵌入惡意代碼等)誘導用戶的瀏覽器發送未經授權的請求到受信任的網站。這些請求會攜帶用戶的認證信息(如Cookie、Session),從而讓受信任的網站誤以為是用戶本人發起的合法請求。
目錄
1?CSRF攻擊的基本原理
2 預防CSRF攻擊的方法?
3?使用CSRF令牌(Token)的具體實現
3.1?在服務器端生成CSRF令牌
3.2?在HTML表單中包含CSRF令牌
3.3?在服務器端驗證CSRF令牌
3.4?解析請求體(中間件)
3.5?完整的示例代碼
3.7?注意事項
1?CSRF攻擊的基本原理
- 用戶登錄受信任的網站:用戶在受信任的網站上登錄,瀏覽器保存了該網站的會話Cookie。
- 用戶訪問惡意網站:攻擊者誘導用戶訪問惡意網站或點擊惡意鏈接。
- 惡意網站發送請求:惡意網站構造一個請求,利用用戶的瀏覽器發送到受信任的網站。由于用戶已經登錄,瀏覽器會自動附帶用戶的會話Cookie。
- 受信任的網站處理請求:受信任的網站接收到請求后,看到附帶的合法會話Cookie,以為這是用戶發起的合法請求,從而執行相應的操作。
2 預防CSRF攻擊的方法?
- 使用CSRF令牌(Token):在每次提交表單時,服務器生成一個唯一的CSRF令牌,并將其包含在表單中。服務器在處理請求時驗證令牌的有效性,確保請求來自合法的來源。
- 驗證HTTP頭部:檢查請求的來源(Referer或Origin頭部),確保請求是從受信任的域名發出的。
- 使用雙重提交Cookie:在請求中同時包含會話Cookie和一個自定義的CSRF令牌,服務器驗證這兩個值是否一致。
- 使用SameSite Cookie屬性:設置Cookie的SameSite屬性為Strict或Lax,限制Cookie的跨站使用,從而減少CSRF攻擊的風險。
CSRF攻擊的目標通常是執行用戶不希望的操作,例如更改賬戶設置、進行交易或發送敏感數據等。因此,理解和防范CSRF攻擊對于保護用戶的安全至關重要。
3?使用CSRF令牌(Token)的具體實現
使用CSRF令牌(Token)是防范CSRF攻擊的一種有效方法。下面是一個具體的實現步驟,假設你使用的是Node.js和Express框架,前端使用HTML和JavaScript。
3.1?在服務器端生成CSRF令牌
首先,需要在服務器端生成一個唯一的CSRF令牌,并將其存儲在用戶的會話中。
const express = require('express');
const session = require('express-session');
const crypto = require('crypto');const app = express();app.use(session({secret: 'your_secret_key',resave: false,saveUninitialized: true
}));// 中間件:生成CSRF令牌并存儲在會話中
app.use((req, res, next) => {if (!req.session.csrfToken) {req.session.csrfToken = crypto.randomBytes(32).toString('hex');}next();
});
3.2?在HTML表單中包含CSRF令牌
在服務器端的響應中,需要將CSRF令牌包含在HTML表單中,通常以隱藏字段的形式。
app.get('/form', (req, res) => {res.send(`<form action="/submit" method="POST"><input type="hidden" name="csrfToken" value="${req.session.csrfToken}"><!-- 其他表單字段 --><button type="submit">Submit</button></form>`);
});
3.3?在服務器端驗證CSRF令牌
在處理表單提交請求時,服務器需要驗證提交的CSRF令牌是否有效。
app.post('/submit', (req, res) => {const { csrfToken } = req.body;if (csrfToken !== req.session.csrfToken) {return res.status(403).send('CSRF token mismatch');}// 處理表單提交res.send('Form submission successful');
});
3.4?解析請求體(中間件)
為了從POST請求中解析CSRF令牌,需要使用body-parser中間件。
const bodyParser = require('body-parser');app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
3.5?完整的示例代碼
下面是完整的示例代碼,將上述步驟結合起來:
const express = require('express');
const session = require('express-session');
const crypto = require('crypto');
const bodyParser = require('body-parser');const app = express();app.use(session({secret: 'your_secret_key',resave: false,saveUninitialized: true
}));app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());app.use((req, res, next) => {if (!req.session.csrfToken) {req.session.csrfToken = crypto.randomBytes(32).toString('hex');}next();
});app.get('/form', (req, res) => {res.send(`<form action="/submit" method="POST"><input type="hidden" name="csrfToken" value="${req.session.csrfToken}"><!-- 其他表單字段 --><button type="submit">Submit</button></form>`);
});app.post('/submit', (req, res) => {const { csrfToken } = req.body;if (csrfToken !== req.session.csrfToken) {return res.status(403).send('CSRF token mismatch');}// 處理表單提交res.send('Form submission successful');
});app.listen(3000, () => {console.log('Server is running on http://localhost:3000');
});
3.7?注意事項
- CSRF令牌的生成和驗證應盡量使用加密安全的隨機數生成方法。
- 確保CSRF令牌的存儲和傳輸安全,避免令牌被第三方竊取。
- 每次會話開始時生成新的CSRF令牌,確保令牌的唯一性和不可預測性。