blog-imgDucklog

JWT를 제대로 써야하는 이유

JWT를 제대로 써야하는 이유

우리가 로그인을 구현할 때 2가지 방식으로 구현하게 됩니다.

  1. 세션(session) 방식
  • 사용자가 로그인을 합니다.

  • 서버에서는 계정 정보를 읽어 사용자를 확인한 후, 사용자에게 고유한 ID값을 부여하여 세션 저장소에 저장한 후, 이와 연결되는 Session ID를 발급합니다.

  • 서버는 HTTP 응답 헤더에 발급된 Session ID를 실어 보냅니다. 이후 매 요청마다 HTTP 요청 헤더에 Session ID가 담킨 쿠키를 실어 보냅니다.

  • 서버에서는 쿠키를 받아 세션 저장소에서 대조를 한 후 대응되는 정보를 가져옵니다.

  • 인증이 완료되고 서버는 사용자에 맞는 데이터를 보내줍니다.

장점

사용자의 정보는 세션 저장소에 저장되고, 쿠키는 그 저장소를 통과할 수 있는 출입증 역할을 합니다. 따라서 쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 쿠키 자체에는 유의미한 값을 갖고있지 않아서 쿠키에 사용자 정보를 담아 인증을 거치는 것 보다 안전합니다.

각 각의 사용자는 고유의 Session ID를 발급 받기 때문에 일일이 회원 정보를 확인할 필요가 없어 서버 자원에 접근하기 용이합니다.

단점

쿠키에 사용자 정보를 담아 인증을 거치는 것 보다 안전하지만, 해커가 쿠키를 탈취한 후 그 쿠키를 이용해 HTTP 요청을 보내면 서버는 사용자로 오인해 정보를 전달하게 됩니다. 이를 세션 하이재킹 공격이라고 합니다. 해결책으로는 HTTPS 프로토콜 사용과 세션에 만료 시간을 넣어주는 것 입니다. 서버에서 세션 저장소를 사용하기 때문에 추가적인 저장공간을 필요로 합니다. 만약 사용자가 많은 경우 세션정보를 일일히 다 조회해야하기 때문에 비 효율적입니다.

  1. JWT을 이용한 Token 방식
  • 사용자가 로그인을 합니다.

  • 서버에서는 계정 정보를 읽어 사용자를 확인 후, 사용자의 고유한 ID값을 부여하고 Payload에 정보를 넣습니다.

  • JWT 토큰의 유효기간을 설정합니다.

  • SECRET KEY를 통해 암호화된 Access Token을 HTTP 응답 헤더에 실어 보냅니다.

  • 사용자는 Access Token을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 HTTP 요청 헤더에 실어 보냅니다.

  • 서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후, 조작 여부, 유효 기간을 확인합니다.

  • 검증이 완료된다면, Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져옵니다.

장점

간편합니다. 세션과 쿠키를 이용한 인증은 별도의 세션 저장소의 관리가 필요합니다. 그러나 JWT는 발급 후 검증만 거치면 되기 때문에 추가 저장소가 필요없습니다. 확장성이 뛰어납니다. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능합니다.

단점

JWT는 한 번 발급되면 유효기간이 완료될 때까지는 계속 사용이 가능하며 중간에 삭제가 불가능합니다. 따라서 해커에 의해 정보가 털린다면 대처할 방법이 없습니다. 해결책으로는 Refresh Token을 추가적으로 발급하여 해결하는 방식으로 아래에서 설명하겠습니다. Payload 정보가 디코딩하면 누구나 접근할 수 있기에 중요한 정보들을 보관할 수 없습니다. JWT의 길이가 길기 때문에, 인증 요청이 많아지면 서버의 자원낭비가 발생합니다.


JWT를 썼을 때 발생하는 문제들

문제 1

해커들이 헤더의 알고리즘을 none으로 바꾸어 로그인을 시도하는 경우가 있습니다. 간혹 none으로 했을 때 로그인이 될 수 있기 때문

해결방안 - 최신 라이브러리를 사용하거나 none으로 로그인이 되지 않게 설정한다.

{
  "alg": "none",
  "typ": "JWT"
}

문제 2

디코딩이 쉬워 정보를 해킹당할 수 있다. Base64의 코드이기 때문에 디코딩 한번으로 내부 정보를 확인할 수 있기 때문.

해결방안 - 최소한의 정보만 담아놓는다.

문제 3

시크릿키 시크릿키를 단순한 문자로 해버리면 해커들이 임의로 맞추기 쉬워 해킹을 당할 수 있습니다.

HMACSHA256 {
  base64UrlEncode(header) + '.' +
  base64UrlEncode(payload),
 [시크릿 키]
}

해결방안 -

  1. 시크릿키를 매우 길게 설정한다
  2. 시크릿 키를 안전하게 보관한다.
  3. 생성용 키/ 검증용 키 2개를 사용한다.

문제 4

JWT 탈취 만약 탈취됐을 때 임의로 사용정지를 할 수 없음. 해결방안 -

  1. HttpOnly cookie와 같은 훔치기 어려운 저장소에 저장
  2. JWT 블랙리스트 제작 (특정 입장권은 입장할 수 없게)..하지만 이 방식은 세션 방식와 똑같기 때문에 JWT의 장점이 없어짐.
  3. JWT의 유효기간을 짧게 하기. (입장권 재발급을 위한 refresh 토큰을 사용을 추가로 해야함.)
  4. refresh 토큰 또한 탈취 될 수 있기 때문에, refresh token rotation을 사용

결론

특별한 일이 없으면 세션 방식을 이용하는게 좋지만, 회원이 많으면 JWT를 사용해야하고 보안을 위해서 꼼꼼하게 도입해야 함.