hgame2022第一周赛题总结
杭电比赛第一周赛题总结
第一周的web题目没有什么需要特别记录的,大多比较简单,只有一道jwt伪造算是戳中软肋,知之甚少。
这道题本身也不算难吧,我是边学边做,也是差一点点就做出来了,就是有些有些小地方没注意到,比较可惜
这里首先记录一下jwt伪造这个知识点,后续如果有机会遇到相似的题目,再做整理
什么是JWT伪造
JWT简介
Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
说起JWT,我们应该来谈一谈基于token的认证和传统的session认证的区别。
传统的Session认证
我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
但是这种基于session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来:
Session:每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
扩展性:用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。
CSRF: 因为是 基于cookie 来进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
基于token的鉴权机制
基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。
流程上是这样的:
用户使用用户名密码来请求服务器
服务器进行验证用户的信息
服务器通过验证发送给用户一个token
客户端存储token,并在每次请求时附送上这个token值
服务端验证token值,并返回数据
这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *。
————————————————
版权声明:本文为CSDN博主「WHOAMIAnony」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45521281/article/details/106073624
(这里大佬讲的挺不错的,我引用一下)
这里另外重点介绍一下jwt的构造
jwt的内容由三段组成,三段内容由.来连接,例如
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MTA3OSwiVXNlck5hbWUiOiJzc2QiLCJQaG9uZSI6IiIsIkVtYWlsIjoiIiwiZXhwIjoxNjQ0MTYzNDIzLCJpc3MiOiJNSmNsb3VkcyJ9.HpgT7NKS6hJEFfHK6n-73Ju4E253CdMjSE1E5qD57uw
三个部分分别叫做头部,载荷,签证
jwt头部包含两个内容,声明类型和声明加密算法
例如下面的完整的JSON头部
此处声明类型为JWT,签名算法为HS256,上面这段内容经过base64加密处理后就是JWT的第一段内容。
载荷是存放有效信息的地方,其中的有效信息包括标准中注册的声明,公共的声明,私有的声明
标准中注册的声明 (建议但不强制使用) :
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端可解密。
私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
(原文链接:https://blog.csdn.net/qq_45521281/article/details/10607362)
上图中就定义了一段payload,对此段进行base64加密后就形成了jwt信息中的第二段
第三部分签证
这一部分的主要目的是保证jwt的信息不会被修改,利用前面两部分的base64加密信息加上头部声明的加密算法进行组合加密
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64加密后的)
payload (base64加密后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
// javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret,那就意味着客户端是可以自我签发jwt了。
(再次引用一下,原文链接:https://blog.csdn.net/qq_45521281/article/details/10607362)
题解
题目页面比较简单,包含注册和登录两个交互窗口
随便注册一个账号登录后发现是一个留言板
因为是留言板,所以一开始以为是xss注入,结果方法都试了一遍发现不行,压根没回显,说明不是xss
后续看到人家说是jwt伪造(笑哭),从头开始学习
抓包,获取token
利用jwt验证网站https://jwt.io/ 验证所获取的token
确认是jwt
下面开始伪造过程,这个过程比较曲折,我尝试了很多也没成功,结果wp出来发现真的很简单
ID修改为1,username改为admin,secret处清空
然后将所得的jwt存入本地缓存,伪造cookie
刷新页面获得flag
参考链接:
https://blog.csdn.net/qq_45521281/article/details/10607362