[Web] Web · 작성: 2026-07-20 03:10:34 · 수정: 2026-07-20 03:11:15 · 조회 6
세션 대신 JWT(JSON Web Token)로 인증 상태를 유지하는 서비스가 많아지면서, JWT 구현 실수로 인한 인증 우회 사례도 늘었다. JWT는 Header.Payload.Signature 세 부분을 점(.)으로 이어붙인 구조인데, 이 서명(Signature) 검증 로직에 허점이 있으면 payload를 임의로 조작할 수 있다.
JWT 표준은 alg(서명 알고리즘)를 Header에 명시하도록 되어 있는데, none이라는 값도 표준에 정의되어 있다 — "서명 없음"을 뜻한다. 서버가 이걸 제대로 거부하지 않으면, 공격자가 Header의 alg를 none으로 바꾸고 Signature 부분을 아예 비운 토큰을 만들어도 유효한 토큰으로 받아들여진다.
// 원본 Header: {"alg":"HS256","typ":"JWT"}
// 변조 Header: {"alg":"none","typ":"JWT"}
// → Base64 인코딩 후 Signature를 비운 채로 전송
RS256(비대칭키: 개인키로 서명, 공개키로 검증)을 쓰는 서비스에서, 검증 로직이 Header의 alg 값을 그대로 믿고 검증 방식을 바꾼다면 문제가 생긴다. 공격자가 alg를 HS256(대칭키)으로 바꾸고, 누구나 알 수 있는 공개키 문자열 자체를 HMAC 대칭키처럼 사용해서 서명을 만들면, 서버는 "HS256이니까 이 공개키로 HMAC 검증"을 해버려서 위조 토큰이 통과한다.
// 취약: 토큰이 스스로 주장하는 alg를 그대로 신뢰할 위험이 있음
jwt.verify(token, secret);
// 안전: 서버가 기대하는 알고리즘을 명시적으로 고정
jwt.verify(token, secret, { algorithms: ['HS256'] });
검증 시 반드시 허용할 알고리즘을 서버 쪽에서 고정 지정해야 한다. 토큰이 스스로 "나는 이 알고리즘으로 서명됐다"고 주장하는 값을 그대로 믿으면 안 된다.
exp(만료 시간) 클레임이 실제로 검증되는지