Open karchinkong opened 6 years ago
CSRF(Cross-site request forgery),中文名称:跨站请求伪造。
CSRF 会盗用登录者信息,模拟登录者发送请求。
CSRF 攻击是源于Web的隐式身份验证机制。Web 的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。CSRF 攻击的一般是由服务端解决。
1.用户登录了受信任网站 A,在本地生成 cookie。 2.在没退出 A 的情况下,打开 tab 访问危险网站 B,B 恶意发出请求访问 A。 3.浏览器带上 A 生成的 cookie 向 A 发出恶意请求成功,从而 B 攻击成功。
一般分为 Get 与 Post 攻击。Get 攻击最简单,假设 Github 有一个关注的 Get 接口: https://github.com/follow?id=123
https://github.com/follow?id=123
id 表示即将关注的用户,比如说关注我。我在本篇文章里内置一段恶意代码:
<img style="width:0" src="https://github.com/follow?id=123" />
如果你已经登录了 Github,同时点开了我的这篇文章,在 Github 没有防御 csrf 的情况下,你便会自动关注了我。
一般在需要操作数据时,会使用 POST 请求。但 POST 也不是绝对的安全,POST 也可以被模拟。
用 form 表单 + iframe 即可模拟 POST 请求。
<form name="myForm" method="post" target="myFrame"> <input type="hidden" name="id" value="123"/> <input type="submit" /> </form> <iframe name="myFrame" style="display:none;"></iframe>
同样发起了 CSRF 攻击。
一般防御 CSRF 有三种方法:
验证 HTTP Referer 字段。 加验证码验证。 加 token 验证。
同时,建议 Get 请求用来查找,Post 请求用来操作。
在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。服务器可以通过判断 Referer 来防御,如果是其它网站,则拒绝该请求。
该方法简单便捷,但是也不是万无一失。部分浏览器可以允许篡改 Referer 值, 同样可能防御不了 CSRF 攻击。同时有些浏览器允许用户禁用 Referer,服务器会因为没有 Referer 值而拒绝该请求。
在通常情况下,验证码能很好遏制 CSRF 攻击。但是出于用户体验考虑,总不能没请求一次服务器就要用户输一次验证码吧。所以验证码只能作为一种辅助手段,不能作为主要解决方案。
主要两种实现:
服务端分配 token。 服务端和客户端通过一样的算法和输入匹配。
但如果网站同时存在 XSS 漏洞,还是会导致 token 泄露,从而导致该方法形同虚设。
服务端随机生成一个 token,存放在 session 中,分布式环境可以使用 Redis 存储 token。然后返回给前端,前端在请求服务器时带上 token 供服务器验证。
此方法前端不用做太多的运算。
服务端和客户端通过一样的算法和输入计算 token 值,进行比较。
前端随机生成一个 sessionKey,存放在 cookie 中,再使用 time33 算法生成 token。前端请求服务端时将 sessionKey 与 token 都传过去,服务端再通过相同的 time33 算法验证。
此方法服务端不用特意保存 token。
目前有两个网站,a.jd.com 与 b.jd.com。
a 下有 sessionKey 存在 cookie 下,domain 为当前二级域名。当 b 想跨域请求 a 的接口时,由于二级域名之间无法获取 cookie,所以 b 获取不到 a 的 sessionKey(生成不了对应的 token),从而请求被拒绝。
若此时 b 自己随机生成 sessionKey 存在 cookie 里,并设置 domain 为 a。此时访问 a,会发现请求成功。但是!但是!too young,先访问 a,再来试试刚才的请求,会发现 cookie 里不仅有 b 的 sessionKey,还会带上 a 的 sessionKey。
结果就是请求被决绝, 403 Forbidden。不知道服务端是怎么取 cookie 里的 sessionKey,可能取 a 的,可能随机取一个,但是这个方法是行不通的。
此时,将 a 的 sessionKey 存在 cookie 下时将 domain 设置为顶级域名 jd.com 时,让 b 能拿到,b 才可请求成功。
什么是 CSRF?
CSRF(Cross-site request forgery),中文名称:跨站请求伪造。
CSRF 会盗用登录者信息,模拟登录者发送请求。
CSRF 攻击是源于Web的隐式身份验证机制。Web 的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。CSRF 攻击的一般是由服务端解决。
原理与过程
1.用户登录了受信任网站 A,在本地生成 cookie。 2.在没退出 A 的情况下,打开 tab 访问危险网站 B,B 恶意发出请求访问 A。 3.浏览器带上 A 生成的 cookie 向 A 发出恶意请求成功,从而 B 攻击成功。
简单攻击
一般分为 Get 与 Post 攻击。Get 攻击最简单,假设 Github 有一个关注的 Get 接口:
https://github.com/follow?id=123
id 表示即将关注的用户,比如说关注我。我在本篇文章里内置一段恶意代码:
<img style="width:0" src="https://github.com/follow?id=123" />
如果你已经登录了 Github,同时点开了我的这篇文章,在 Github 没有防御 csrf 的情况下,你便会自动关注了我。
一般在需要操作数据时,会使用 POST 请求。但 POST 也不是绝对的安全,POST 也可以被模拟。
用 form 表单 + iframe 即可模拟 POST 请求。
同样发起了 CSRF 攻击。
防御 CSRF
一般防御 CSRF 有三种方法:
同时,建议 Get 请求用来查找,Post 请求用来操作。
在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。服务器可以通过判断 Referer 来防御,如果是其它网站,则拒绝该请求。
该方法简单便捷,但是也不是万无一失。部分浏览器可以允许篡改 Referer 值, 同样可能防御不了 CSRF 攻击。同时有些浏览器允许用户禁用 Referer,服务器会因为没有 Referer 值而拒绝该请求。
在通常情况下,验证码能很好遏制 CSRF 攻击。但是出于用户体验考虑,总不能没请求一次服务器就要用户输一次验证码吧。所以验证码只能作为一种辅助手段,不能作为主要解决方案。
主要两种实现:
但如果网站同时存在 XSS 漏洞,还是会导致 token 泄露,从而导致该方法形同虚设。
服务端随机生成一个 token,存放在 session 中,分布式环境可以使用 Redis 存储 token。然后返回给前端,前端在请求服务器时带上 token 供服务器验证。
此方法前端不用做太多的运算。
服务端和客户端通过一样的算法和输入计算 token 值,进行比较。
前端随机生成一个 sessionKey,存放在 cookie 中,再使用 time33 算法生成 token。前端请求服务端时将 sessionKey 与 token 都传过去,服务端再通过相同的 time33 算法验证。
此方法服务端不用特意保存 token。
特例分享
目前有两个网站,a.jd.com 与 b.jd.com。
a 下有 sessionKey 存在 cookie 下,domain 为当前二级域名。当 b 想跨域请求 a 的接口时,由于二级域名之间无法获取 cookie,所以 b 获取不到 a 的 sessionKey(生成不了对应的 token),从而请求被拒绝。
若此时 b 自己随机生成 sessionKey 存在 cookie 里,并设置 domain 为 a。此时访问 a,会发现请求成功。但是!但是!too young,先访问 a,再来试试刚才的请求,会发现 cookie 里不仅有 b 的 sessionKey,还会带上 a 的 sessionKey。
结果就是请求被决绝, 403 Forbidden。不知道服务端是怎么取 cookie 里的 sessionKey,可能取 a 的,可能随机取一个,但是这个方法是行不通的。
此时,将 a 的 sessionKey 存在 cookie 下时将 domain 设置为顶级域名 jd.com 时,让 b 能拿到,b 才可请求成功。