摘要
本文主要讲述了:
- 什么是 CSRF
- 根本矛盾
- 防御措施
正文
什么是 CSRF
Cross-site request forgery(跨站请求伪造),简称为 CSRF。由于 Cross 在英语中也有交叉的意思,因此人们用 X 来取代 C,有时也将其简称为 XSRF。
示例:
a.example.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <script> document.cookie = 'userId=123'; </script> </body> </html>
|
a.foo.com
1 2 3 4 5 6 7 8 9 10 11 12
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <img src="//a.example.com/transferMoney?to=jsweibo&amount=1000" /> </body> </html>
|
用户首先登录a.example.com
,而后访问a.foo.com
。此时网页会自动发送请求。由于a.example.com
的 cookie 已存在于浏览器中,此时访问a.example.com/transferMoney?to=jsweibo&amount=1000
会自动带上a.example.com
的 cookie。而后用户在a.example.com
的资金被盗。
示例:
a.example.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <script> document.cookie = 'userId=123'; </script> </body> </html>
|
a.foo.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <iframe name="foo" hidden></iframe> <form id="bar" method="POST" action="//a.example.com/transferMoney" target="foo" > <input type="hidden" name="to" value="jsweibo" /> <input type="hidden" name="amount" value="1000" /> </form> <script> document.querySelector('#bar').submit(); </script> </body> </html>
|
用户首先登录a.example.com
,而后访问a.foo.com
。此时网页会自动提交表单。由于a.example.com
的 cookie 已存在于浏览器中,此时访问a.example.com/transferMoney
会自动带上a.example.com
的 cookie。而后用户在a.example.com
的资金被盗。
示例:
a.example.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <script> document.cookie = 'userId=123'; </script> </body> </html>
|
a.foo.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <script> let xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.open('POST', '//a.example.com/transferMoney'); xhr.send('to=jsweibo&amout=1000'); </script> </body> </html>
|
用户首先登录a.example.com
,而后访问a.foo.com
。此时网页会自动发送 Ajax 请求(此请求属于简单请求,浏览器端会正常发出,服务器端能够接受并响应,但浏览器端的 JavaScript 无法得到响应消息)。由于a.example.com
的 cookie 已存在于浏览器中,且withCredentials
为true
,故此时访问a.example.com/transferMoney
会自动带上a.example.com
的 cookie。而后用户在a.example.com
的资金被盗。
根本矛盾
服务器端只能确认请求由用户的浏览器发出,但无法确认请求是否出自用户本意
防御措施
在表单中嵌入 token
原理:
- 在服务器端生成随机的 token,并将 token 保存在服务器端的 session 中,而后将其嵌入所有
<form>
中
- 当服务器端收到请求时,校验表单里的 token 和服务器端的 token 是否一致
把 token 嵌入网络请求头
原理:
- 在服务器端生成随机的 token,并将 token 保存在服务器端的 session 中,同时将 token 告知客户端
- 客户端每次发起请求,必须把 token 嵌入 Ajax 的网络请求头
- 当服务器端收到请求时,校验网络请求头里的 token 和服务器端的 token 是否一致
SameSite
原理:阻止发送跨站 cookie
参考资料
本文对你有帮助?请支持我