Spring Security - JWT

·2024년 6월 10일

Spring Security

목록 보기
12/13

유튜브 "개발자 유미" 님 강의를 듣고 정리한 내용입니다.

JWT

Json Web Token 의 약자로 사용자의 인증을 위해 사용되는 토큰이다.

JWT의 사용 이유

세션 기반 인증 방식에서 세션의 저장을 서버 측에서 하고, 클라이언트는 세션 ID 만을 쿠키로 가지고 있었다. 이러한 세션 기반 인증 방식의 단점은 서버 측의 부하가 커진다는 것이다.

서버 측의 부하를 줄이기 위해서 인증에 사용하는 토큰을 클라이언트 측이 저장하는 JWT가 등장했다.

특징

서버 측의 부하를 줄임

인증을 위한 토큰이 서버 측에서 발행된 후, 클라이언트가 JWT를 저장한다. 이후 요청에서 클라이언트가 JWT를 함께 전송하면 서버가 JWT를 확인하고 검증하여 인가를 해준다.

기본적으로는 stateless

서버 측에서는 클라이언트 측의 정보를 유지하지 않으며, stateless로 동작하게 된다. (기본적으로는 stateless가 맞으나, 보안과 관련된 문제들로 인하여 어느정도 stateful하게 관리하기도 한다. 추후 설명)

CSR 방식에서 많이 사용됨

일반적인 CSR 방식에서는 클라이언트의 요청이 들어왔을 때 프론트엔드 서버에서 초기 뷰를 클라이언트에게 전송하게 된다. 그리고 클라이언트(브라우저)가 백엔드 서버로 데이터를 요청한 후, 응답받은 데이터로 렌더링을 하게 된다.

이러한 경우 프론트엔드 서버와 백엔드 서버가 다르기 때문에(Origin이 다름) CORS(Cross Origin Resource Sharing) 문제가 발생할 수 있다.

세션 인증 방식에서는 서버에 세션을 관리하여 클라이언트를 인증, 인가하게 된다. 프론트엔드 서버와 백엔드 서버가 분리되었기 때문에 두 서버 간의 세션 공유와 관련된 문제가 있을 수 있다.

JWT 인증 방식에서는 클라이언트가 토큰을 가지고 인증을 하기 때문에, 상대적으로 유연하게 CORS 문제를 해결할 수 있다. (물론 추가적인 보안을 적용하는 것이 필요하다.)

JWT의 구조

JWT는 헤더, 페이로드, 서명으로 구성된다.
이름에 맞게 Json 구조로 되어있지만, 전송될 때는 Base64 방식으로 인코딩 되어 String으로 전송된다.

헤더와 페이로드 각각이 Base64로 인코딩되며, 서명은 인코딩된 각 부분을 합쳐서 암호화 알고리즘을 통해 서명시킨 것이다. 헤더, 페이로드, 서명은 .으로 연결된다.

Base64 방식의 인코딩은 디코딩이 쉽다. 그렇기 때문에 보안에 민감한 정보들을 JWT에 담아서는 안된다.

헤더 Header

  • typ
    typ에는 JWT임을 알리기 위하여 토큰 타입을 JWT로 명시한다.
  • alg
    alg에는 서명에 사용된 암호화 알고리즘을 명시한다.

페이로드 Payload

사용자 정보와 메타 데이터를 담고 있다.
각각의 정보는 Claim(클레임) 이라고 부른다.

JWT는 인증된 사용자의 인가 작업을 위해 사용되기 때문에, Claim 에는 인가에 꼭 필요한 정보만을 담는 것이 권장된다.

=> username, role, 발행 시간, 유효 시간

또한 인코딩만 되기 때문에 외부에서 정보를 쉽게 확인할 수 있다. 보안에 민감한 정보(password)를 담지 않아야 한다.

서명 Signature

서명은 토큰의 무결성과 출처 검증을 위해 사용된다.

Base64로 인코딩된 헤더와 페이로드를 암호화 알고리즘비밀키를 사용하여 서명한 것이다.

서명은 헤더와 페이로드의 위변조가 일어났는지 확인하는 검증의 목적으로 사용된다. 서버는 전송받은 JWT를 서명했던 비밀키를 사용해서 검증한다.

※ 주의 ※

서명의 목적암호화가 아니다. 기밀성을 보장하지 않는다. Base64 방식으로 인코딩 되어서 외부에서 쉽게 디코딩할 수 있다. (이는 곧 외부에서 쉽게 토큰의 내용을 볼 수 있다는 것을 의미한다.)

그저 서명한 내용이 변경되지 않았는지 검증하기 위한 목적으로만 사용될 뿐이다.

JWT 인증 과정

리프레시 토큰과 액세스 토큰을 구분하지 않은 간단한 인증 과정이다.

  1. 클라이언트가 서버 측에 인증을 요청한다.
  2. 서버는 클라이언트에 대한 인증을 완료한 후, 인증이 성공하면 JWT를 발급한다.
  3. 발급한 JWT를 http 헤더에 담아서 응답한다.
  4. 클라이언트는 발급받은 JWT를 브라우저에 저장한다. (목적에 따라서 브라우저의 저장소를 달리하여 저장할 수 있다. local Storage, session Storage ... etc)
  5. 클라이언트는 이후 요청에서 http 헤더에 발급받은 JWT를 담아서 요청한다.
  6. 서버는 받은 JWT를 검증하여 인증을 완료하고, 클라이언트에게 인가한다.

Authorization 헤더

인증 과정에서 확인하였듯, JWT는 http 헤더에 담겨서 전송되며, Authorization 이라는 헤더에 담기게 된다.

앞에는 Bearer라는 인증 스킴을 붙여서 토큰 인증 방식임을 알린다. 그리고 공백으로 구분하여 JWT를 붙여서 Authorization 헤더에 담는다.

Authorization: <scheme> <credentials>
profile
티스토리로 블로그 이전합니다. 최신 글들은 suhsein.tistory.com 에서 확인 가능합니다.

0개의 댓글