We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
李建国是个倒霉蛋,小时候爬树摔断腿,考试抄错题;长大了骑车被碰瓷,吃饭吃出钢丝球。
一天,李建国打开了某网银要转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 最有效的方式,就是每次提交都要求手动输入验证码,但这样的用户体验很差。现在应用最广泛的就是为提交的表单增加伪随机字段。在服务器上生成一串随机字符串,带到页面上并把随机码保存起来。在用户提交回的表单中取出随机码并与服务器上保存的作对比,如果匹配,那就是合法的请求;要是不匹配,就可以认为这是一个非法的请求。
基于 [email protected]。以下 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 作对比,就可以判断是否为跨站攻击。
The text was updated successfully, but these errors were encountered:
解释的很清楚,hah~~
Sorry, something went wrong.
叙述的方式很有趣
No branches or pull requests
李建国是个倒霉蛋,小时候爬树摔断腿,考试抄错题;长大了骑车被碰瓷,吃饭吃出钢丝球。
一天,李建国打开了某网银要转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
基于 [email protected]。以下 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 作对比,就可以判断是否为跨站攻击。
The text was updated successfully, but these errors were encountered: