Open brunoyang opened 8 years ago
李建国是个倒霉蛋,小时候爬树摔断腿,考试抄错题;长大了骑车被碰瓷,吃饭吃出钢丝球。
一天,李建国打开了某网银要转1000块给王红霞,转账当然是要登录的。转完账后,李建国关闭了 tab 页。随后,李建国打开了不可描述的网站,半分钟后关闭了这个网站。突然,李建国的手机收到银行发来的两条短信,一条是转给王红霞的1000,另一条是不知道转给谁的10000。李建国慌了,他知道网银被盗了。他很疑惑,我啥也没干,咋就被盗了捏,难道见鬼了。
当然,李建国没见鬼,他只是碰上了 CSRF 漏洞。
所谓 CSRF(Cross-site request forgery),跨站攻击,指的是攻击者盗用你的身份,向某个网站发起恶意请求。
我们看李建国的例子,被盗分这么几步:
http://bank.com/transfer/1000/to/wang-hong-xia
<img src="http://bank.com/transfer/10000/to/huai-yin" />
这个漏洞能够成立,基于以下事实:
有了以上的信息,CSRF 漏洞就能成立了。
银行知道了该信息后,紧急组织专家堵漏洞。
银行的转账接口使用 GET 请求,这是严重的错误,因为 GET 请求应该是幂等的,不管调用多少次都是一个结果。于是把银行把接口升级为 POST 请求。
恶意网站也升级了,每次访问都会发起 POST 请求。李建国又被盗了10000。
银行知道了该信息后,又紧急组织专家堵漏洞。
这次他们开始校验请求头中的 referer 信息,因为 referer 信息记录了该请求从哪个域名发出。
恶意网站又升级了,这次他们加了一个代理服务器,在请求发给银行之前先通过代理服务器修改referer信息。李建国再次被盗了10000。
银行知道了该信息后,再次紧急组织专家堵漏洞。
这次他们给表单上增加一个隐藏域,<input type="hidden" value="23kh4acsdudesfr45hoiad" name="ctoken" />,在每次表单提交时都带上 ctoken。
<input type="hidden" value="23kh4acsdudesfr45hoiad" name="ctoken" />
恶意网站发现升级也没用了,就去寻找下一个漏洞了……
防范 CSRF 最有效的方式,就是每次提交都要求手动输入验证码,但这样的用户体验很差。现在应用最广泛的就是为提交的表单增加伪随机字段。在服务器上生成一串随机字符串,带到页面上并把随机码保存起来。在用户提交回的表单中取出随机码并与服务器上保存的作对比,如果匹配,那就是合法的请求;要是不匹配,就可以认为这是一个非法的请求。
基于 koa-csrf@2.4.0。以下 koa-csrf 简称为kcsrf。
先来看最基本用法
const koa = require('koa'); const csrf = require('koa-csrf'); const session = require('koa-generic-session'); const app = koa(); app.keys = ['session secret']; app.use(session()); csrf(app); app.use(csrf.middleware); app.use(function* () { if (this.method === 'GET') { this.body = this.csrf; } else if (this.method === 'POST') { this.status = 204; } }); app.listen(3000);
kcsrf 依托于 session,所以我们引入了koa-generic-session。kcsrf 接受一个配置项,可以传入 saltLength 和 secretLength,分别为盐长度和token长度。这两个参数被透传给 csrf 模块,用于生成 token。
koa-generic-session
该模块很简单,通过定义一个 getter 方法,通过如下形式传给模板,用于生成html页面。
app.use(function *() { this.render({ csrf: this.csrf }); });
而在 getter 方法内部,生成并返回token的同时,还往 session 上增加了一个 secret 字段,用以保存生成的token。
在第二次请求过来时,就会将 token 带回来,位置可以在表单、查询串或自定义头上,将请求中的 token 取出与 session.secret 作对比,就可以判断是否为跨站攻击。
解释的很清楚,hah~~
叙述的方式很有趣
李建国是个倒霉蛋,小时候爬树摔断腿,考试抄错题;长大了骑车被碰瓷,吃饭吃出钢丝球。
一天,李建国打开了某网银要转1000块给王红霞,转账当然是要登录的。转完账后,李建国关闭了 tab 页。随后,李建国打开了不可描述的网站,半分钟后关闭了这个网站。突然,李建国的手机收到银行发来的两条短信,一条是转给王红霞的1000,另一条是不知道转给谁的10000。李建国慌了,他知道网银被盗了。他很疑惑,我啥也没干,咋就被盗了捏,难道见鬼了。
当然,李建国没见鬼,他只是碰上了 CSRF 漏洞。
所谓 CSRF(Cross-site request forgery),跨站攻击,指的是攻击者盗用你的身份,向某个网站发起恶意请求。
我们看李建国的例子,被盗分这么几步:
http://bank.com/transfer/1000/to/wang-hong-xia
;<img src="http://bank.com/transfer/10000/to/huai-yin" />
;这个漏洞能够成立,基于以下事实:
有了以上的信息,CSRF 漏洞就能成立了。
银行知道了该信息后,紧急组织专家堵漏洞。
银行的转账接口使用 GET 请求,这是严重的错误,因为 GET 请求应该是幂等的,不管调用多少次都是一个结果。于是把银行把接口升级为 POST 请求。
恶意网站也升级了,每次访问都会发起 POST 请求。李建国又被盗了10000。
银行知道了该信息后,又紧急组织专家堵漏洞。
这次他们开始校验请求头中的 referer 信息,因为 referer 信息记录了该请求从哪个域名发出。
恶意网站又升级了,这次他们加了一个代理服务器,在请求发给银行之前先通过代理服务器修改referer信息。李建国再次被盗了10000。
银行知道了该信息后,再次紧急组织专家堵漏洞。
这次他们给表单上增加一个隐藏域,
<input type="hidden" value="23kh4acsdudesfr45hoiad" name="ctoken" />
,在每次表单提交时都带上 ctoken。恶意网站发现升级也没用了,就去寻找下一个漏洞了……
防范 CSRF
防范 CSRF 最有效的方式,就是每次提交都要求手动输入验证码,但这样的用户体验很差。现在应用最广泛的就是为提交的表单增加伪随机字段。在服务器上生成一串随机字符串,带到页面上并把随机码保存起来。在用户提交回的表单中取出随机码并与服务器上保存的作对比,如果匹配,那就是合法的请求;要是不匹配,就可以认为这是一个非法的请求。
koa-csrf
基于 koa-csrf@2.4.0。以下 koa-csrf 简称为kcsrf。
先来看最基本用法
kcsrf 依托于 session,所以我们引入了
koa-generic-session
。kcsrf 接受一个配置项,可以传入 saltLength 和 secretLength,分别为盐长度和token长度。这两个参数被透传给 csrf 模块,用于生成 token。该模块很简单,通过定义一个 getter 方法,通过如下形式传给模板,用于生成html页面。
而在 getter 方法内部,生成并返回token的同时,还往 session 上增加了一个 secret 字段,用以保存生成的token。
在第二次请求过来时,就会将 token 带回来,位置可以在表单、查询串或自定义头上,将请求中的 token 取出与 session.secret 作对比,就可以判断是否为跨站攻击。