// HMAC String JVM private transient byte[] keyHMAC = ...; ... // // HMAC-256 - JWTVerifier verifier = JWT.require(Algorithm.HMAC256(keyHMAC)).build(); // DecodedJWT decodedToken = verifier.verify(token);
// HMAC String JVM private transient byte[] keyHMAC = ...; // private SecureRandom secureRandom = new SecureRandom(); ... // , byte[] randomFgp = new byte[50]; secureRandom.nextBytes(randomFgp); String userFingerprint = DatatypeConverter.printHexBinary(randomFgp); // cookie String fingerprintCookie = "__Secure-Fgp=" + userFingerprint + "; SameSite=Strict; HttpOnly; Secure"; response.addHeader("Set-Cookie", fingerprintCookie); // SHA256 // ( ) XSS // cookie MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] userFingerprintDigest = digest.digest(userFingerprint.getBytes("utf-8")); String userFingerprintHash = DatatypeConverter.printHexBinary(userFingerprintDigest); // 15 Calendar c = Calendar.getInstance(); Date now = c.getTime(); c.add(Calendar.MINUTE, 15); Date expirationDate = c.getTime(); Map<String, Object> headerClaims = new HashMap<>(); headerClaims.put("typ", "JWT"); String token = JWT.create().withSubject(login) .withExpiresAt(expirationDate) .withIssuer(this.issuerID) .withIssuedAt(now) .withNotBefore(now) .withClaim("userFingerprint", userFingerprintHash) .withHeader(headerClaims) .sign(Algorithm.HMAC256(this.keyHMAC));
// HMAC String JVM private transient byte[] keyHMAC = ...; ... // cookie String userFingerprint = null; if (request.getCookies() != null && request.getCookies().length > 0) { List<Cookie> cookies = Arrays.stream(request.getCookies()).collect(Collectors.toList()); Optional<Cookie> cookie = cookies.stream().filter(c -> "__Secure-Fgp" .equals(c.getName())).findFirst(); if (cookie.isPresent()) { userFingerprint = cookie.get().getValue(); } } // SHA256 cookie // MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] userFingerprintDigest = digest.digest(userFingerprint.getBytes("utf-8")); String userFingerprintHash = DatatypeConverter.printHexBinary(userFingerprintDigest); // JWTVerifier verifier = JWT.require(Algorithm.HMAC256(keyHMAC)) .withIssuer(issuerID) .withClaim("userFingerprint", userFingerprintHash) .build(); // DecodedJWT decodedToken = verifier.verify(token);
create table if not exists revoked_token(jwt_token_digest varchar(255) primary key, revokation_date timestamp default now());
// (logout). // , // . public class TokenRevoker { // @Resource("jdbc/storeDS") private DataSource storeDS; // public boolean isTokenRevoked(String jwtInHex) throws Exception { boolean tokenIsPresent = false; if (jwtInHex != null && !jwtInHex.trim().isEmpty()) { // byte[] cipheredToken = DatatypeConverter.parseHexBinary(jwtInHex); // SHA256 MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] cipheredTokenDigest = digest.digest(cipheredToken); String jwtTokenDigestInHex = DatatypeConverter.printHexBinary(cipheredTokenDigest); // try (Connection con = this.storeDS.getConnection()) { String query = "select jwt_token_digest from revoked_token where jwt_token_digest = ?"; try (PreparedStatement pStatement = con.prepareStatement(query)) { pStatement.setString(1, jwtTokenDigestInHex); try (ResultSet rSet = pStatement.executeQuery()) { tokenIsPresent = rSet.next(); } } } } return tokenIsPresent; } // HEX public void revokeToken(String jwtInHex) throws Exception { if (jwtInHex != null && !jwtInHex.trim().isEmpty()) { // byte[] cipheredToken = DatatypeConverter.parseHexBinary(jwtInHex); // SHA256 MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] cipheredTokenDigest = digest.digest(cipheredToken); String jwtTokenDigestInHex = DatatypeConverter.printHexBinary(cipheredTokenDigest); // // if (!this.isTokenRevoked(jwtInHex)) { try (Connection con = this.storeDS.getConnection()) { String query = "insert into revoked_token(jwt_token_digest) values(?)"; int insertedRecordCount; try (PreparedStatement pStatement = con.prepareStatement(query)) { pStatement.setString(1, jwtTokenDigestInHex); insertedRecordCount = pStatement.executeUpdate(); } if (insertedRecordCount != 1) { throw new IllegalStateException("Number of inserted record is invalid," + " 1 expected but is " + insertedRecordCount); } } } } }
Authorization: Bearer <token>
A&'/}Z57M(2hNg=;LE?~]YtRMS5(yZ<vcZTA3N-($>2j:ZeX-BGftaVk`)jKP~q?,jk)EMbgt*kW'
Source: https://habr.com/ru/post/457090/