分享群友在Shopee面试中遇到的JWT面试真题。相关面试题如下:什么是JWT?为什么要使用智威汤逊?JWT由哪几部分组成?如何基于JWT做认证?JWT如何防止Token被篡改?如何加强JWT的安全性?如何使令牌失效?......什么是智威汤逊?JWT(JSONWebToken)是目前最流行的跨域认证方案,是一种基于Token的认证授权机制。从JWT的全称可以看出,JWT本身也是一种Token,一种规范化JSON结构的Token。Token本身包含了认证所需的所有信息,所以我们的服务器不需要存储Session信息。这显然增加了系统的可用性和可扩展性,大大减轻了服务器的压力。可以看出JWT在设计RESTfulAPI时更符合“Stateless(无状态)”的原则。而且使用Token认证可以有效避免CSRF攻击,因为Token一般存在于localStorage中,使用JWT进行认证的过程中不涉及cookie。我在JWT优缺点分析[1]一文中详细介绍了使用JWT进行身份认证的优缺点。以下是RFC7519[2]中对JWT更正式的定义。JSONWebToken(JWT)是一种紧凑的URL安全方式,用于表示要在两方之间传输的声明。JWT中的声明被编码为JSON对象,用作JSONWeb签名(JWS)结构的有效负载或用作JSONWeb加密(JWE)结构的明文,从而使声明能够进行数字签名或完整性保护使用消息验证码(MAC)和/或加密。——JSONWebToken(JWT)[3]JWT是由哪些部分发布的?JWT本质上是一组字符串,由(.)进行Base64编码,分为三部分:Header:描述了JWT的元数据,定义了生成签名的算法和Token的类型。Payload:用于存放实际需要传递的数据。Signature(签名):服务器使用Payload、Header和一个密钥(Secret),使用Header中指定的签名算法生成它(默认是HMACSHA256)。JWTsusuallylooklikethis:xxxxx.yyyyy.zzzzz.示例:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c你可以在?jwt.io这个网站上对其JWT进行解码,解码之后得到的就是Header、Payload、Signature这三部分。Header和Payload都是JSON格式的数据,Signature是通过特定的计算公式和加密算法从Payload、Header和Secret(key)中得到的。HeaderHeader通常由两部分组成:typ(Type):token类型,即JWT。alg(Algorithm):签名算法,如HS256。示例:{"alg":"HS256","typ":"JWT"}JSON格式的Header转换为Base64编码,成为JWT的第一部分。PayloadPayload也是JSON格式的数据,其中包含Claims(声明,包括JWT相关信息)。Claims分为三种类型:RegisteredClaims(注册声明):一些预定义的声明,推荐的,但不是强制的。PublicClaims:JWT发行者可以自定义的声明,但为避免冲突,应在IANAJSONWebTokenRegistry[5]中定义。PrivateClaims(私有声明):JWT发布者因项目需要自定义声明,更符合实际项目场景。以下是一些常见的注册语句:iss(issuer):JWTissuer。iat(issuedattime):JWT发布时间。sub(主题):JWT主题。aud(听众):JWT接收者。exp(过期时间):JWT的过期时间。nbf(notbeforetime):JWT生效时间,早于定义时间的JWT不能被接受和处理。jti(JWTID):JWT唯一标识。示例:{"uid":"ff1212f5-d8d1-4496-bf41-d2dda73de19a","sub":"1234567890","name":"JohnDoe","exp":15323232,"iat":1516239022,"scope":["admin","user"]}Payload部分默认不加密,请勿在Payload中存储隐私信息!!!JSON形式的Payload转换为Base64编码,成为JWT的第二部分。SignatureSignature部分是前两部分的签名,其作用是防止Token(主要是payload)被篡改。这个签名的生成需要使用:Header+Payload。存储在服务器上的密钥(不得泄露)。签名算法。签名的计算公式如下:HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)计算完签名后,将Header、Payload、Signature三部分组合成一个字符串,用"点”(.)分隔,成为JWT的第三部分。如何基于JWT做认证?在基于Token认证的应用中,服务端通过Payload、Header和Secret(密钥)创建一个Token(令牌),并将Token发送给客户端。客户端收到这个Token后,会保存在Cookie或者localStorage中,客户端发出的所有请求都会携带这个token。简化步骤如下:用户向服务器发送用户名、密码和验证码,即可登录系统。如果用户名、密码和验证码验证无误,服务器将返回签名后的Token。每次用户向后端发送请求时,Header中都会包含这个Token。服务器检查Token,并从中获取用户相关信息。两个建议:建议将Token存放在localStorage,cookie存在CSRF风险。向服务器请求并携带Token的常见方式是将Token放在HTTPHeader的Authorization字段中(Authorization:BearerToken)。spring-security-jwt-guide[6]是一个简单的基于JWT的身份认证案例,有兴趣的可以看看。JWT如何防止Token被篡改?有了签名,即使Token被泄露或被破解,黑客也无法同时篡改Signature、Header和Payload。为什么是这样?因为服务器拿到Token后,会解析出其中包含的Header、Payload和Signature。服务器会根据Header、Payload和key重新生成一个Signature。将新生成的Signature与Token中的Signature进行比较。如果相同,说明Header和Payload没有被修改。但是,如果服务器的秘钥也被泄露,黑客就可以同时篡改Signature、Header和Payload。黑客直接修改Header和Payload后,重新生成一个Signature就可以了。密钥必须妥善保管,不得外泄。JWT安全的核心在于签名,签名安全的核心在于密钥。如何加强JWT的安全性?使用安全系数高的加密算法。使用成熟的开源库,无需发明轮子。Token存储在localStorage中,而不是Cookie中,以避免CSRF风险。不要在Payload中存储私人信息。密钥必须妥善保管,不得外泄。JWT安全的核心在于签名,签名安全的核心在于密钥。Payload需要加上exp(JWT的过期时间),永久有效的JWT不合理。而且JWT的过期时间也不容易过长。……
