소개
JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 는 stateless 성격을 가지고 있습니다. 그래서 별도의 세션 관리를 위한 DB가 필요없어 Microservice 환경에서도 많이 사용이 되고 있는데요.
하지만 이로인해 정해진 만료시간(expire) 시간 전에는 토큰이 유출되었다고 하더라도 유출된 토큰만 서버에서 파기할 방안이 없습니다. 그래서 짧은 만료시간을 설정하기를 권고하곤 하는데요.
공격자가 JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 토큰을 가로채 정상 사용자로 가장하는 공격인 JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... sidejacking 공격에 취약할 수 있는데 이를 보완할 방안에 대해 한번 살펴보려 합니다.
JWT Sidejacking
JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 는 어플리케이션이나 시스템의 인증 및 관련 정보 교환을 위해 사용되는 JSON Web Token 입니다. JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 가 유출되거나 공격자가 이 토큰을 가로챈다면 정상 사용자로 인증을 할 수 있습니다.
JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... sidejacking 은 이처럼 공격자가 인증 token 을 가로채 정상 사용자로 가장하는 공격입니다.
JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... sidejacking 을 보안적으로 보완하기 위해서는 token 이 하이재킹 당하든 유출이 되든 token 만으로 인증을 할수 있도록 하기보다, 별도의 context 를 만들어 추가 검증을 할 수 있는 메커니즘을 만들어야 하는데요.
OWASP 에서는 별도의 user context 를 구현하여 JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... sidejacking 공격에 대한 보안적 방안을 제시해주고 있습니다.
JWT Sidejacking 보안 방안
user context 를 구현하라는 의미는 아래와 같습니다.
- JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 와 더불어 추가 검증을 위한 context 를 만듭니다. - context 라 함은 random string 을 만들어 Cookie 헤더에 저장(wiht
SameSite
,HttpOnly
,Secure
flags)하고, - 만든 random string 의 hash 값을 JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 의 paylaod 에 추가합니다.
- client 에서 server 로 응답이 오면 서버에서는 user context 를 검증합니다.
- 검증은 아래 두값이 동일한지 확인을 하여 이루어집니다.
- Cookie 에 저장된 random string 을 hashing
- JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... payload 내 hashing 된 random string
- 동일하다면 인증 성공
sequence diagram 으로 확인하면 아래와 같습니다.
해당 flow 를 통해 JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 가 유출되어 사용되더라도 cookie(보안 flags 가 적용된)에 저장된 랜덤값과 다르다면 검증실패하여 인증이 되지 않을 것입니다. JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 의 payload 값이 디코딩으로 확인이 되더라도 랜덤값의 hash 된 값이기 때문에 cookie 에 적용해야할 랜덤값 유추도 힘들어 집니다.
Node.js 로 구현
node express 를 이용하여 간단하게 구현해보면 아래와 같습니다.
import express from "express";
import crypto from "crypto";
import jwt from "jsonwebtoken";
const app = express();
const port = 3000;
app.get("/generate-token", (req, res) => {
// Random data generator
const secureRandom = crypto.randomBytes;
// Generate a random string that will constitute the fingerprint for this user
const randomFgp = secureRandom(50);
const userFingerprint = randomFgp.toString("hex");
// Add the fingerprint in a hardened cookie
const fingerprintCookie = `__Secure-Fgp=${userFingerprint}; SameSite=Strict; HttpOnly; Secure`;
res.setHeader("Set-Cookie", fingerprintCookie);
// Compute a SHA256 hash of the fingerprint to store in the token
const hash = crypto.createHash("sha256");
hash.update(userFingerprint);
const userFingerprintDigest = hash.digest("hex");
// Create the token with a validity of 15 minutes and client context (fingerprint) information
const now = Math.floor(Date.now() / 1000);
const expirationTime = now + 15 * 60;
const headerClaims = {
typ: "JWT",
};
const secret = "secretKey"; // Use a secure key
const token = jwt.sign(
{
sub: "user-login",
exp: expirationTime,
iss: "issuer-id",
iat: now,
nbf: now,
userFingerprint: userFingerprintDigest,
},
secret,
{
header: headerClaims,
algorithm: "HS256",
}
);
// Send the token to the client
res.send({ token });
});
app.listen(port, () => {
console.log(`http://localhost:${port}`);
});
/generate-token
엔드포인트 접속하여 잘 동작하는지 JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... 와 Cookie 를 확인해봅니다.
Cookie 의 plain random string 을 hashing 하고,
JWT
• JSON Web Tokens
• RFC 7519
• 위조 불... payload 의 hashing random string 과 동일한지 아래 코드로 검증해봅니다.
import crypto from "crypto";
// plain random string in cookie to hash
const userFingerprint = "8c9fc6bf6f039f96ae06289e4b6d76103ff9171eabd6a47606b58c0f5ce0ad9a9888594fd1658e5908bf29d1881c30881628";
const hash = crypto.createHash("sha256");
hash.update(userFingerprint);
const userFingerprintDigest = hash.digest("hex");
// hashing random string in JWT payload
const hasgedUserFingerprint =
"801ac5401d3f5983f44f2a61265e1667d5faef8b6d0d9287ee63cdc8ef852125";
// verify
if (hasgedUserFingerprint === userFingerprintDigest) {
console.log("pass");
} else {
console.log("drop");
}
잘 동작하네요.
Refs
- https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#symptom_2
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies
- https://security.stackexchange.com/questions/220060/usefulness-of-token-sidejacking-prevention-mentioned-by-owasp-jwt-cheat-sheet