지난 글에 이어 이번에도 보안 관련 글이다. JWT는 쿠키 세션 토큰 글에서 간략히 다룬 적이 있지만 이것 자체도 내용이 꽤 되어서 따로 글을 작성한다. 이왕 작성하는거 더 자세히 다뤄본다.
Token 방식 중 가장 많이 사용되는 것이 JWT로 JSON 포멧으로 저장하는 web Token이다.
정보를 비공개로 전달하거나 인증할 때 주로 사용한다.
→ 클라이언트와 서버 사이에서 인증 및 인가 시 사용하는 토큰이다.

JWT는 점으로 3개의 영역(header, payload, signature)을 구분한다.
JWT를 어떻게 검증하는지에 대한 내용. JWT의 정보
서명 시 사용하는 알고리즘, 사용하는 키를 식별하는 값 등이 여기에 들어간다.
{
"alg": "RSA",
"typ": JWT
}
JWT의 내용이다. 여기에 있는 속성들을 Claim이라고 하며 이곳에는 토큰 생성자의 정보, 생성일 등 클라이언트와 서버 간 주고 받기로 약속한 데이터들이 담겨있다.
점(.)을 구분자로 한 헤더와 페이로드를 합친 문자열을 서명한 값. 사실상 가장 중요한 부분이다.
header에서 정의된 알고리즘을 이용해 payload와 서버가 가진 고유한 key 값을 합친 것을 암호화한다.
Header 와 페이로드는 단순히 인코딩된 값이기 때문에 제 3자가 복호화 및 조작할 수 있지만, Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없기 때문에 토큰의 위변조 여부를 확인하는데 사용할 수 있다.
JWT는 인증과 관련된 것인 만큼 HTTP 프로토콜에 담겨질 것이다. 여기서 중요한 것은 어디에 담기느냐이다. Header인가 Body인가.
정답은 Header이다.
우선 길이가 그렇게 길지도 않고 JWT가 제안된 RFC7519 문서에서 Header를 이용해 보내자고 약속 했기 때문에 Header에 실어 보낸다.
이때 서버에서는 이를 받고 처리해야 하는데 이때 사용하는 것이 Oauth에서 사용하는 Bearer 인증 방식이다.
그럼 이런 복잡한 구조들을 일일히 다 적어야 할까?
스프링에서 JWT를 구현할 땐 JJWT(Java JWT)라이브러리를 이용해 구현한다고 한다.
자바에서 JWT를 생성, 서명, 검증, 디코딩 하기 위한 라이브러리로 해당 라이브러리에는 아래와 같은 기능들이 있따.
JWT의 단점에서 볼 수 있듯 JWT는 완벽한 방식이 아니다. 그러다보니 고려해야 하는 부분들이 존재한다.
결국 Key를 탈취당한다면 나머지의 내용들은 JSON 파일로 있기에 정보가 도난당할 수 있다. 그러니 Key에 대한 관리가 추가로 필요하다. 관리에 대한 방법은 아래의 두가지 방법이 있다.
이는 JWT만의 문제가 아니라 토큰 방식의 문제인데 인증에 사용되는 토큰 자체가 도난 당한다면 막을 수 있는 방법이 없다. 그러다 보니 토큰 자체의 관리도 필요하다. 이는 토큰에 관해 정리한 글에서도 확인 할 수 있어 해당 글을 가져왔다.
짧은 만료 기한 설정
토큰의 만료 시간이 짧으면 탈취 되더라도 금방 만료되기 때문에 피해를 최소화 할 수 있다. 하지만 사용자가 자주 로그인 해야 하는 불편함이 있다.
Sliding Session
서비스를 지속적으로 이용하는 클라이언트에게 자동으로 토큰 만료 기한을 늘려주는 방법으로, 1번의 단점을 보완해줄 수 있는 전략이다. 이는 곧 로그인을 하지 않아도 항상 유지가 되므로 보안상 취약점이 생길 수 있다.
Refresh Token
위에서 인증에 사용되는 Token을 Access Token 이라고 하고 그보다 만료 기간이 긴 Refresh Token을 따로 생성해 같이 내려준다. 클라이언트는 Access Token이 만료되었을 때, Refresh Token을 사용하여 Acess Token의 재발급을 요청할 수 있다. 서버는 DB에 저장된 Refresh Token과 비교하여 유효한 경우 새로운 Access Token을 발급하고, 만료된 경우 다시 로그인 하도록 한다. 이렇게 한다면 1번과 2번의 문제를 한번에 해결할 수 있지만 검증을 위해서는 서버에 Refresh Token을 별도로 저장 시켜야 하기에 JWT의 Stateless의 장점이 없어지게 되고 구조적 구현 과정이 복잡해진다.
당연한 것이지만 토큰이 어디에 저장되는가에 따라 고려해야 하는 부분이 달라진다.
HTTP Only: 중간에 쿠키를 탈취하고자 하는 XSS 공격 등에 대비해 브라우저에서 쿠키로 바로 접속할 수 없도록 하는 것.
secure: 네트워크 직접 감청으로 인한 탈취를 막기 위해 HTTPS를 이용해 보안을 유지한다.
samesite: 쿠키가 사용 가능한 도메인을 지정하는 옵션으로 브라우저 주소란과 동일한 도메인에 대한 요청시에만 쿠키를 전송하는 것.
→ CSRF 공격에 대한 예방.
CSRF: Cross Site Request Forgery의 약자. 공격자의 요청이 사용자의 요청인 것처럼 속여서 정보를 빼돌리는 것.
어찌되었든 토큰이 탈취 되었을 때 해당 토큰을 무효화할 방법이 있어야 추가적인 예방이 가능한 것은 어찌 보면 당연한 것이다. 이런 해결책에는 로그아웃 처리, 블랙리스트 관리 등의 방법이 있다.
위의 방법들과 언급하지 않았지만 다른 방법들까지 포함해 보안을 유지할 수 있도록 고려한다면 JWT에 대한 보안을 강화할 수 있다. 또한 각 부분들을 보면 서로 다른 부분을 보완하고 있기 때문에 다양한 방법을 혼합해 더욱 강화된 보안 전략 구축이 필요하다.
JWT는 정보를 암호화해 전달하거나 인증할 때 사용하는 Token이다.
JWT 단독 뿐 만 아니라 다양한 보안 대책을 같이 활용하면 더욱 우수한 보안 안전성을 가질 수 있다.