手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的
协议
+ 域名
+ 端口号
组成的一个虚拟概念。跨域请求
又是什么意思呢?跨域请求的安全隐患
跨站请求伪造
。跨域请求的安全防御
登录受信任网站A,并本地已经存储了 Cookie
在不登出A的情况下,访问危险网站B,网站 B 诱导你发 A 发请求。
利用浏览器的同源策略:最基础的安全策略
对请求的来源进行验证:Referer Check
使用验证码强制使用户进行交互确认,保证请求是用户发起
CSRF Token,注意不要使用 cookie 来存储token
JSON Web Token
有的虽然实现简单,但是不够安全 有的虽然安全,但是用户体验不好 有的虽然安全,用户体验好,但是有缺点
3.1 同源策略
3.2 Referer Check
3.3 加验证码
3.4 CSRF Token
当用户请求一个更新用户名的页面时,由服务端生成一个随机数 Token,然后放入HTML表单中传给浏览器,并且存入 session 中。 当用户提交表单请求时,表单数据会带上这个 Token 发送给服务端 ; 服务端收到表单请求后,会从表单数据里取出 Token,然后和 session 里的 token 进行对比,如果是一样的,就是合法的用户请求,将新的用户名存入数据库,如果不一样,那就是非法的请求,应当拒绝。
当用户请求一个更新用户名的页面时,由服务端生成一个随机数 Token,然后放入HTML表单中,并且会把这个 Token 放在 cookie 里发给浏览器。 当用户提交表单请求时,表单数据会带上这个 Token 发送给服务端,并且带上携带 token 的 cookie ; 服务端收到表单请求后,会从表单数据里取出 Token,与 cookie 里的 token 进行对比,如果是一样的,就是合法的用户请求,将新的用户名存入数据库,如果不一样,那就是非法的请求,应当拒绝。
3.5 新增 Header
服务端每生成一个 Token,都会存放入 session 中,而随着用户请求的增多,服务端的开销会明显增大。 如果网站有多个子域,分别对应不同的服务器,比如 taobao.com 后台是服务器 a,zhibo.baotao.com 后台是 服务器b, 不同子域要想使用同一个 Token,就要求所有的服务器要能共享这个 Token。一般要有一个中心节点(且应是一个集群)来存储这个Token,这样看下来,架构就变得更加复杂了。
服务器只负责生成 Token和校验Token,而不再存储Token 将服务器的压力分摊给了所有的客户端。 服务端的 鉴权不使用 cookie ,而是由新增的 Header 字段:Authorization 里的 JWT 。
JWT 的工作原理及目的
用户以 Web表单 的形式,将自己的用户名和密码 POST 到后端的接口。 后端核对用户名和密码成功后,会计算生成JWT Payload 字符串(具体计算方法,后续会讲),然后返回 response 给浏览器。 浏览器收到 JWT 后,将其保存在 cookie 里或者 localStorage 或者 sessionStorage 里(具体如何选,后面会说)。 后续在该域上发出的请求,都会将 JWT放入HTTP Header 中的 Authorization 字段。 后端收到新请求后,会使用密钥验证 JWT 签名。 验证通过后后端使用 JWT 中包含的用户信息进行其他相关操作,返回相应结果。
JWT 如何生成?
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
.
,以 .
为分界,可以将 JWT 分为三部分。第一部分:头部(Header) 第二部分:载荷(Payload) 第三部分:签名(Signature)
5.1 头部(Header)
声明类型:这里是 JWT 声明加密的算法:通常直接使用 HMAC SHA256
{
"typ": "JWT",
"alg": "HS256"
}
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
5.2 载荷(Payload)
iss (issuer):签发人 exp (expiration time):过期时间 sub (subject):主题 aud (audience):受众 nbf (Not Before):生效时间 iat (Issued At):签发时间 jti (JWT ID):编号
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
5.3 签名(Signature)
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
.
)分隔,就可以返回给用户。如何手动生成 JWT?
Python
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.3wGDum3_A8tAt1bdal5CpYbIUlpHfPQxs96Ijx883kI
$ pip install pyjwt
import jwt
import datetime
import uuid
salt = 'minggezuishuai'
# 构造header , 这里不写默认的也是
headers = {
'typ': 'JWT',
'alg': 'HS256'
}
# 构造payload
payload = {
'user_id': str(uuid.uuid4()), # 自定义用户ID
'username': "wangbm", # 自定义用户名
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5) # 超时时间,取现在时间,五分钟后token失效
}
token = jwt.encode(payload=payload, key=salt, algorithm="HS256", headers=headers).decode('utf-8')
# token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQzMjZ9.kkEMhSx732lO6HWWNPNVQDHR9WuCEVxKgNol-LTbCP8
$ pyjwt --key="minggezuishuai" encode user_id=888f20d9-07ed-41bd-b329-17c6f058a14e username=wangbm exp=+120
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQ4NTl9.A792th12kY1YnBWyVgbr5l6OQ5emRiETIjsnmIl4Ji8
Base64URL 算法
保存在 localStorage 保存在 sessionStorage 保存在 cookie 保存在 cookie 并设置 HttpOnly
当访问量/业务量不是很大时,可以使用 CSRF Token 来防止 CSRF 攻击 而如果访问量/业务量对服务器造成很大压力,或觉得服务器共享 token 对架构要求太高了,那就抛弃CSRF Token 的方式,而改用 JWT。选择了 JWT ,就面临着要将 JWT 存储在哪的问题。 若选择了 JWT ,那么请不要使用 cookie HttpCookie 来存储它,因为使用它还是会有 CSRF 攻击风险。 那另外三种如何选择呢?这三种无论使用哪种,都不可避免有 XSS 攻击风险。我的思路是,XSS 攻击通过其他的手段来规避,这里使用JWT 只有 防御 CSRF 攻击与服务器性能的优化,这两个目标。 那我剩下的三种,我建议是使用 cookie 存储,但不使用 cookie 来鉴权。服务器鉴权还是通过请求里的 Authorization 字段(通过js写入 Header 的)。
Referer Check
、加验证码
等其他手段,已经可以保证不受 CSRF 攻击的威胁,此时你使用 JWT ,就可以选择使用 JWT + cookie HttpOnly,扼杀 XSS 攻击的可能。JWT 如何发送?
第一种:将 JWT 放在 Header 里的 Authorization
字段,并使用Bearer
标注
'Authorization': 'Bearer ' + ${token}
第二种:把 JWT 放入 cookie ,发送给服务端,虽然发送。但是不使用它来鉴权。
JWT 如何校验?
Authorization
里的 JWT ,使用之前的签名算法对 header 和 payload 再次计算生成新的签名,并与 JWT 里的签名进行对比,如果一样,说明校验通过,是个合法的 Token。HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
pyjwt
这个来生成 JWT ,事实上,这个库也可以用来验证 token。>>> import jwt
>>> token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQzMjZ9.kkEMhSx732lO6HWWNPNVQDHR9WuCEVxKgNol-LTbCP8"
>>> jwt.decode(token, 'minggezuishuai', algorithms=['HS256'])
{'user_id': '888f20d9-07ed-41bd-b329-17c6f058a14e', 'username': 'wangbm', 'exp': 1594434326}
>>>
$ pyjwt --key="minggezuishuai" decode eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiODg4ZjIwZDktMDdlZC00MWJkLWIzMjktMTdjNmYwNThhMTRlIiwidXNlcm5hbWUiOiJ3YW5nYm0iLCJleHAiOjE1OTQ0MzQ4NTl9.A792th12kY1YnBWyVgbr5l6OQ5emRiETIjsnmIl4Ji8
{"user_id": "888f20d9-07ed-41bd-b329-17c6f058a14e", "username": "wangbm", "exp": 1594434859}
--no-verify
参数即可$ pyjwt --key="minggezuishuai" decode --no-verify {token}
pyjwt --help
学习或者前往官方文档:https://pyjwt.readthedocs.io/en/latest/index.htmlJWT 的最佳搭配
公钥加密的东西,只有私钥能解。因此如果 JWT 的 payload 里有你的敏感信息,那也不要紧,只要把 JWT 用公钥(前提是这个公钥得是正确的,下面会说到)加密一下,那黑客就算拿到了这个密文,也无法解密,因为私钥只有服务器才有。 私钥加密的东西,所有的公钥也都能解。因此服务器发给客户端的 JWT 的payload 尽量不要有敏感信息。
写在最后
CSRF 攻击的产生,需要cookie 的『助攻』,否则无法完成。 CRSF 是利用 cookie,而不是盗取 cookie,这点一定要明白。 但也并不是使用了 cookie 就会有 CSRF 风险,而应该说是用 cookie 去做鉴权才会有 CSRF 风险,参考 CSRF Token (把 token 存储在 cookie 的情况)和 JWT (把 token 存储在 cookie 的情况)。 CSRF Token 和 JWT 虽然都可以做到防御 CSRF 攻击,但其实无论是哪个都无法同时做到防御 CSRF 和 XSS 攻击,在阻止了 CSRF 攻击后, 需要再通过其他手段来减少 XSS 攻击的可能性。 JWT 就是一个由服务端按照一定的规则生成的字符串, JWT 的目的是为了做一个无状态的 session,避免去频繁查询 session,减少了对服务器产生的压力,简化后端架构模型。它的主要用途是解决跨域认证的问题,而解决 CSRF 跨域攻击只是它的附带功能。 payload 是经过 base64URL 算法转换而成的字符串,是可逆的,因此尽量不要存放敏感数据,如若非要存放敏感数据,最好与 HTTPS 协议搭配使用,避免数据泄露。 JWT 的保存位置与方式,没有绝对的方案,具体如何选择要视情况而定。
推荐阅读
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号
随时掌握互联网精彩
随时掌握互联网精彩
赞助链接
排名
热点
搜索指数
- 1 准确把握守正创新的辩证关系 7999911
- 2 中国黄金原董事长家搜出大量黄金 7902735
- 3 空调英文不会男生盯着考场空调看 7875833
- 4 消费品以旧换新“加速度” 7730885
- 5 被铁路售票员的手速惊到了 7654092
- 6 网红赤木刚宪爆改赵露思 7576160
- 7 县委原书记大搞“刷白墙”被通报 7465139
- 8 山姆代购在厕所分装蛋糕 7363318
- 9 马龙刘诗雯穿正装打混双 7267261
- 10 刘强东提前发年终奖 7118943