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' }));