Spring security JWT - 6. IUWT방식을 이용하여 방어하기
이 글은 블로그에 적힌 IUWT를 이용한 JWT보안 방식을 읽고 작성함.
위 방식은 UUID값을 만들어 같이 토큰에 넣고, 쿠키에 UUID값을 담아 토큰이 탈취 당했을 때를 대비하여, 쿠키에 있는 UUID값과 같이 비교하여 해당 토큰의 탈취 여부를 확인하고, 해킹범이 해당 토큰을 사용하지 못하도록 막는 것 같다.
위 방식은 Refresh Token이 필요없고, 그에 따라 Redis에 저장 할 필요도 없기 때문에 소규모 서비에서 적합하다고 적혀있는데, 개인적인 생각엔 Refresh Token을 사용하는 것보다 더 좋은 것 같다.
매 요청시마다 UUID 값 두개를 비교하면 되서 Access Token을 길게 가져가거나, 조금 더 보안을 강화? 하기 위해 Access Token을 짧게 가져가고 UUID 값이 맞으면 AccessToken을 재발급 해주면서 새로운 UUID를 심어 보내도 좋을 것 같다. (이러면 UUID가 refreshToken역할도 하네..)
코드는 이전 글 코드에서 부터 작성 하였습니다.
코드는 github의 feature-iuwt 브렌치에서 확인 할 수 있습니다.
코드
- 이전 장에서 적은것처럼 기존 AccessToken은 Header에 저장하도록 하였다.
- uuid 값을 만들어, tokenProvider에서 토큰을 만들 때 사용 할 수 있도록 보냈고, Cookie에도 담아 클라이언트로 보내도록 설정하였다.
- token builder에 claim이라는 값으로 key value를 넣어 컨트롤러에서 전달 받은 uuid 값을 넣도록 하였다.
실행
- 로그인 API를 실행하면 응답 헤더에 Authentication 이라는 값으로 JWT 토큰이 넘어오게 되고, Set-Cookie로 identify key로 UUID 값이 넘어오고 httpOnly 설정이 되어있다.
- Set Cookie로 저장되어있기 때문에 클라이언트에서 따로 값을 보낼 필요가 없다.
이렇게 하면 로그인이 UUID값을 identify 라는 key값으로 넣어 jwt 토큰에 넣고 인코딩하여 전달되며, 클라이언트는 해당 토큰과 쿠기로 동일한 UUID값을 받게 된다.
이제 검증 로직
코드
- 이제 검증시에 Cookie에 들어있는 identify 키의 uuid 값을 가져와야한다.
- 배열인 Cookie를 Map에 넣고 원하는 키값으로 해당 데이터를 불러오는 메소드를 만들었다.
- 값이 nullable해서 null일 때는 빈 값으로 리턴하도록 하였다.
- 기존 getToken 메소드였으나, 내용은 subject 값을 가져오는 메소드여서 이름을 getSubject로 변경하였다.
- 해당 메소드에 identify 값을 넘겨 검증을 한 뒤, 검증이 되면 subject를 리턴하도록 하였다.
- 기존 subject까지 가져오는 메소드를 getClaims 라는 메소드로 변경하여 payload 값 까지만 불러오고, 그 중 위에서 넣었던 키 값 identify로 value를 불러와 Cookie에서 받은 identify 값과 비교하도록 하였다.
- 값이 같을 때 subject를 리턴하도록 하였다.
실행
- 요청 헤더에 Cookie 에서 identify라는 키값으로 위에서 전달받은 UUID값을 보내고, 결과도 제대로 들어오는 것을 확인
- postman을 사용하여 header의 cookie에 identify값을 보내지 않았을 때에는 403에러가 발생하였다.
위처럼 코드를 구현하면 jwt가 탈취되었더라도 쿠키에 저장되어있는 identify 코드 없이는 백엔드 서버를 통과 할 수 없다.
uuid 말고 클라이언트의 IP 값으로 할 수 있으나, 로드벨런서 등의 앞단에서 IP가 변경이되면 정확한 클라이언트의 IP를 확인하기 힘들어지기에 위처럼 UUID 값을 사용하여 보안을 하는 것이 구현도 쉽고 좋을 것 같다.