Understanding JWT, JWS, JWE based on JJWT

JWT, full-written JSON Web Token, is an open industry standard RFC7591, which is used to implement end-to-end security verification.
From the perspective of developers' understanding:

  • JWT is a standard that defines the delivery of information
  • The Token of JWT is a Base64 encoded string, similar to
eyJhbGciOiJIUzI1NyJ9.eyJzdWIiOiJvc2NhciJ9.p1no61S/XIQ0QNEhzB8e0eI9Q39jIGgkDxUjYipKnzw=

This string contains 2 dots (.), which can be divided into 3 segments, representing the header, payload and signature respectively.

For more introduction about JWT, please refer to:
Introduction to JWT and the use of java-jwt

How JWT Token is generated

  1. The simplest JWT consists of two parts: header (header) and payload (load).
    For a basic introduction to JWT, please refer to:
    Introduction to JWT and the use of java-jwt

For example the head is:

{
  "alg": "none"
}

The load is:

Hello, JWT
  1. remove unnecessary spaces
		String header = "{\"alg\":\"none\"}";
		String payload= "Hello, JWT";
  1. After getting the bytes of UTF-8, use Base64 to encode
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());

4. Connect the encoded characters with a dot (.)

String compact= encodedHeader + "." + encodedPayload + ".";

The connected Token is as follows:

eyJhbGciOiJub25lIn0=.SGVsbG/vvIwgSldU.

It can be seen from here that JWT is actually not mysterious, it just encodes the string with Base64, so the result can be obtained directly by decoding or some online Base64 decoding tools, such as https://base64.us/
insert image description here

Because there is no digital signature, the above Token is insecure and unprotected, and there is no guarantee that no third party will modify this content, so in order to improve security, it is necessary to add a digital signature.

JWS , signed JWT - a cryptographically signed JWT

The above example payload is a string, but in actual use, the payload is more data in JSON format, and the Token after digitally signing the JWT is called JWS.

Still from a simple example:

  1. head
{
  "alg": "HS256"
}

Digital signature using HS256 algorithm
2. Payload

{
"sub":"oscar"
}
  1. Contents without spaces
		String header = "{\"alg\":\"HS257\"}";
		String payload=  "{\"sub\":\"oscar\"}";
  1. Get the byte array and use Base64 encoding, and use dot notation to connect
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());
		String concatenated = encodedHeader + '.' + encodedPayload;
  1. Use a sufficiently secure digest encryption algorithm (such as HMAC-SHA-256) to obtain the encrypted digest, that is, the digital signature. Finally, the header, payload and signature are combined to form a complete Token.
		String header = "{\"alg\":\"HS257\"}";
		String payload=  "{\"sub\":\"oscar\"}";
		Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());
		String concatenated = encodedHeader + '.' + encodedPayload;
		
		Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        sha256_HMAC.init(secretKey);
        byte[] signature = sha256_HMAC.doFinal(concatenated.getBytes("utf-8"));//使用加密算法产生签名
        String compact = concatenated + '.' + Base64.getEncoder().encodeToString( signature ); //将签名和头,载荷连接起来
        System.out.println(compact);

The resulting Token is as follows:

eyJhbGciOiJIUzI1NyJ9.eyJzdWIiOiJvc2NhciJ9.HjomJsGXx3vO/x16euJo7kFsBFJaOEdyoj5Czbt3XE4=

PLAY,encrypted JWT

JWE is to encrypt the digitally signed Token. After encryption, the content of the Token cannot be directly obtained after decoding with Base64. The encryption method can be symmetric encryption or asymmetric encryption. JJWT also provides some fast encryption methods, but the support varies in different versions. Here, Java's own DES symmetric encryption is used for demonstration.
The sample code is as follows:

	
	@Test
	public void jwe() throws Exception {
		String header = "{\"alg\":\"HS257\"}";
		String payload = "{\"sub\":\"oscar\"}";
		Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
		String encodedHeader = Base64.getEncoder().encodeToString(header.getBytes());
		String encodedPayload = Base64.getEncoder().encodeToString(payload.getBytes());
		String concatenated = encodedHeader + '.' + encodedPayload;

		Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
		sha256_HMAC.init(secretKey);
		byte[] signature = sha256_HMAC.doFinal(concatenated.getBytes("utf-8"));
		String compact = concatenated + '.' + Base64.getEncoder().encodeToString(signature);
		
		//使用DES算法对称加密
		String strKey = "this is my password";
		DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		SecretKey key = keyFactory.generateSecret(desKeySpec);

		Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, key);

		byte[] encryptedBytes = cipher.doFinal(compact.getBytes(StandardCharsets.UTF_8));
		String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
		System.out.println(encryptedText);
		
	}

The content obtained after the encrypted Token is decoded with Base64 is as follows:
insert image description here

To get the correct content, you need to use the key to decrypt and then perform Base64 decoding.

For Java symmetric encryption and decryption, you can refer to:
Java implementation of symmetric encryption (DES, AES) quick start example

Glossary

  • JWT, JSON Web Token. Web token in JSON format
  • JWS: signed JWT, signed JWT
  • JWE: encrypted JWT, signed and encrypted JWT (also encrypts the payload)

The relationship between the three is as follows:
insert image description here

Complete sample code



Guess you like

Origin blog.csdn.net/oscar999/article/details/132418249