JWT 서명 검증 누락

Improper Verification of JWT Signature

설명

JWT 토큰을 사용할 때 서명(signature)을 검증하지 않고 decode만 하면, 악의적인 사용자가 위조한 JWT를 서버가 정상 토큰으로 인식하고 허용할 수 있습니다. 검증을 생략하면 토큰의 무결성과 진위 여부를 확인할 수 없어 인증 우회나 권한 상승 등의 공격에 취약해집니다.

잠재적 영향

  • 인증 우회: 공격자가 임의의 JWT를 생성해 인증 절차를 우회할 수 있습니다.
  • 권한 상승: 공격자가 위조된 토큰을 사용하여 더 높은 권한을 가진 사용자로 접근할 수 있습니다.
  • 데이터 노출: 신뢰할 수 없는 토큰으로 민감한 정보를 안전하지 않게 노출할 수 있습니다.

해결 방법

  • JWT를 사용할 때 항상 서명 검증(verify)을 수행하세요.
  • decode, verify 등의 옵션이나 라이브러리 설정 시 항상 검증이 활성화되어 있는지 확인하세요.
  • 신뢰할 수 있는 비밀 키(secret)을 안전하게 관리하세요.
  • 유지보수되는 JWT 라이브러리를 사용하고, 허용 알고리즘과 발급자·대상·만료 조건을 서비스 정책에 맞게 검증하세요.

예시

아래는 jwt-simple의 서명 검증 옵션을 비교한 발췌입니다. Authorization 헤더에서 토큰을 추출하는 처리와 키 설정 검증은 생략했습니다. 일반적인 Bearer 헤더는 접두사를 분리한 뒤 JWT 문자열만 전달하세요.

변경 전

javascript
const jwt = require('jwt-simple');
const secret = process.env.JWT_SECRET;

app.get('/profile', (req, res) => {
  const token = req.headers.authorization;
  // ⚠️ 검증 없이 디코딩만 함 (서명 미검증)
  const decoded = jwt.decode(token, secret, true);
  res.json({ user: decoded.username });
});

변경 후

javascript
const jwt = require('jwt-simple');
const secret = process.env.JWT_SECRET;

app.get('/profile', (req, res) => {
  const token = req.headers.authorization;
  try {
    // ✅ 서명 검증을 반드시 수행
    const decoded = jwt.decode(token, secret, false); // 또는 noVerify 인수 생략
    res.json({ user: decoded.username });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized. Invalid token.' });
  }
});

설명:

  • 변경 전: 세 번째 noVerify 인수를 true로 전달하여 검증을 건너뛰고 토큰의 유효성을 확인하지 않습니다. 이로 인해 공격자가 임의의 토큰을 만들어서 인증을 우회할 수 있습니다.
  • 변경 후: noVerify를 false로 지정하여 서명을 검증하고, 실패한 토큰을 거부합니다. 별도로 허용 알고리즘과 필요한 클레임을 검증하고, 사용자별 접근 권한을 확인하세요.

참조