1.connect中間件csrf
原理:在express框架中csrf 是通過connect 模塊的中間件來解決的。其原理是在前端構造一個隱藏的表單域“_csrf” ,后端生成一個值,作為該表單域,然后在提交表單的時候,將這個值提交到后端,后端再根據這個值來比較,如果和之前的值相等的,就認為是正確的,否則就是錯誤的。 我們來看看代碼:
module.exports = function csrf(options) { options = options || {}; var value = options.value || defaultValue; return function(req, res, next){ // already have one var secret = req.session._csrfSecret; if (secret) return createToken(secret); // generate secret uid(24, function(err, secret){ if (err) return next(err); req.session._csrfSecret = secret; createToken(secret); }); // generate the token function createToken(secret) { var token; // lazy-load token req.csrfToken = function csrfToken() { return token || (token = saltedToken(secret)); }; // compatibility with old middleware Object.defineProperty(req.session, '_csrf', { configurable: true, get: function() { console.warn('req.session._csrf is deprecated, use req.csrfToken() instead'); return req.csrfToken(); } }); // ignore these methods if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next(); // determine user-submitted value var val = value(req); // check if (!checkToken(val, secret)) return next(utils.error(403)); next(); } } };
我們看到,直接以function(req,res,next){} 返回,在這個函數里面有一個 createToken 函數,就是生成token 的,將token的值直接綁定在請求對象req的屬性上,req.csrfToken = function
我們可以直接調用這個函數,生成值,返回給頁面,賦值給表單域。然后表單提交 經過checkToken 函數,比較是否相同,如果是就調用next 函數,否則直接調用utils.error(403) 了。
2. cookie_secret
express 可以通過connect的中間件模塊cookieParser 來解決
使用方法:
connect() * .use(connect.cookieParser('optional secret string')) * .use(function(req, res, next){ * res.end(JSON.stringify(req.cookies)); * })
3.paypal 的lusca 模塊
這個模塊很簡潔,可以解決csrf,p3p,xframe,csp 等問題。使用起來很簡單。官方地址
原理: csrf 是直接調用express 框架的csrf來解決的,p3p和xframe ,csp 都是設置response header 來解決的。
調用方式為:
var express = require('express'), appsec = require('lusca'), server = express(); server.use(appsec.csrf()); server.use(appsec.csp({ /* ... */})); server.use(appsec.xframe('SAMEORIGIN')); server.use(appsec.p3p('ABCDEF'));
也可以直接這么使用
server.use(appsec({ csrf: true, csp: { /* ... */}, xframe: 'SAMEORIGIN', p3p: 'ABCDEF' }));