본문 바로가기

Hub Web/Web

[Web] REST API에서 JWT를 사용하는 이유

728x90

📜 개요


🔹 내 웹 애플리케이션에 방금 로그인 요청을 받았는데 로그인 자격 증명이 포함되지 않은 요청이라면 다음 API 호출에서는 어떻게 될까? 기본적으로 HTTP는 Stateless이다. 즉, 각 요청은 독립적이고 이전 요청에 대한 상태를 저장하지 않는다. 그렇다고 사용자에게 모든 요청에 대하여 재인증을 요청하는 것은 바람직하지 못하다.

 

 세션 쿠키와 JWT(JSON 웹 토큰)는 호출 간에 이러한 인증 상태를 유지하는 가장 널리 사용되는 두 가지 방법이다. 두 가지 모두 장단점이 있으며, 둘 중 하나를 선택하려면 이러한 장단점과 애플리케이션의 특정 요구 사항과의 관계를 이해해야 한다.

 

⚙️ Session ( 세션 )


Session 이란, 비밀번호를 비롯한 인증 정보를 쿠키가 아닌, 서버 측에서 저장하고 관리하는 방식이다.

 

🔹 클라이언트의 웹 브라우저에 쿠키를 저장해 놓고, 매 요청마다 헤더에 쿠키를 넣어 전달하는 방식을 사용하는 방식으로 인증을 구현할 경우, 쿠키가 유출되거나 조작될 수 있는 등 보안상 결함이 존재한다. 개인 소유가 아닌 공용 컴퓨터에서 사용할 경우, 누구나 그 사용자의 비밀번호를 확인할 수 있게 되며 HTTP로 개인 정보를 주고받는 것은 매우 위험하다. (JsessionId 는 톰캣에서 세션을 유지하기 위해 발급하는 키)

 

그렇기 때문에 서버에 저장하고 관리하는 방식인 세션 방식을 통해 이런 문제를 해결하고자 했다. 더 자세한 내용과 세션의 장단점은 아래의 글에 담아뒀다.

 

[Web] HTTP 프로토콜에서 쿠키와 세션을 사용하는 이유

📜 개요 🔹 쿠키와 세션에 대한 공부를 하며 들었던 의문이다. HTTP는 Stateless ( 무상태성 )하고 Connectionless ( 비연결성 ) 한 특징을 갖고 있는데 그렇다면 로그인 정보는 어떻게 저장하는 걸까? 이

noxknow.tistory.com

 JWT ( JSON Web Token )


🔹 JWT(Json Web Token)란 Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token이다. JWT는 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 안전하게 전달한다.

[ 인증 타입 ] : Bearer 토큰

Bearer 토큰은 토큰을 소유한 사람에게 액세스 권한을 부여하는 일반적인 토큰 클래스이다. 액세스 토큰, ID 토큰, 자체 서명 JWT는 모두 Bearer 토큰이다.

[ JWT 구조 ]

JWT는 3개의 점(.)으로 구분된 세 부분으로 구성되며 다음과 같다.

  • Header
  • Payload
  • Signature
                               설명
 Header 토큰 유형과 사용한 서명 알고리즘의 두 부분으로 구성 {  "alg": "HS256",  "typ": "JWT"}
 Payload 사용자 및 추가 데이터에 대한 설명인 Claim을 포함Payload에는 사용자의 비밀번호와 같은 중요한 정보는 포함시키지 않음 {  
"sub": "1234567890",
  "name": "John Doe",  
"admin": true
}
Signature 토큰이 전달되는 도중에 변경되지 않았는지 확인 HMACSHA256(  base64UrlEncode(header) + "." +  base64UrlEncode(payload),  secret)

1) Header

🔹 header를 디코딩하면 두 가지 정보가 있다.

  • type : 항상 jwt가 들어간다.(고정값)
  • alg : 알고리즘의 약자, Verify signature를 만드는데 사용될 알고리즘이 지정된다.
{
  "alg": "HS256",
  "typ": "JWT"
}

이 json은 Base64Url로 인코딩 된 JWT의 첫 번째 부분이다.

 

2) Payload

🔹 payload를 base64로 디코딩 해보면 JSON형식으로 여러 정보들이 들어있다. 이 토큰에 담긴 데이터를 claim이라고 한다. 사용자가 서버에게 요청을 하면 서버는 사용자 정보를 알기 위해 사용자에게 토큰을 받아서 claim 데이터를 읽는다. 이는 서버가 요청마다 일일이 데이터베이스에서 뒤져봐야 할 것들이 줄어드는 것이다.

  • iss: 토큰 발급자
  • sub: 토큰 제목
  • aud : 토큰 대상자
  • exp : 토큰의 만료시간
  • 그 외에 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용(ex : 사용자의 닉네임, 서비스상의 레벨, 관리자 여부 등)을 서비스 측에서 원하는 대로 담을 수 있다.

토큰의 두번째 부분은 클레임을 포함하는 payload이다. 클레임은 일반적으로 사용자 및 정보가 담겨있다.

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
  • payload에 담긴 정보는 인코딩만 되어 있기 때문에 누구라도 디코딩하여 확인할 수 있으므로 중요한 정보를 담으면 안된다.

3) Verify signature

🔹 (header + payload + 서버에 감춰놓은 비밀 값)을 암호화 알고리즘에 넣으면 Verify signature 값이 된다.

서버는 요청에 토큰이 들어오면 (header + payload + 서버에 감춰놓은 비밀 값)을 알고리즘에 넣은 값과 Verify signature 값이 일치하는 결과가 나오는지 확인한다. 이때, signature는 인코딩 된 header, 인코딩 된 payload, secret을 합친 뒤 헤더에 지정된 알고리즘으로 해싱한다. 만약 어느 하나라도 일치하지 않으면 완전히 다른 값을 갖게 된다.

 

서버가 아닌 다른 곳에서 claim을 변경하였다면 이 두 값이 일치하지 않을 것이다. 값이 일치하지 않다면 서버에서 요청을 거부하게 되고 값이 일치하고 유효기간도 지나지 않았다면 사용자는 인가를 받게 된다.

 

또한, JWT는 세션과 다르게 stateless이다.

 

🖋   Session vs JWT


🔹 서버 기반 인증의 대표적인 예인 Session과 JWT의 동작 방식의 차이, Session의 문제점과 JWT가 어떤식으로 해당 문제를 보완할 수 있는지에 대한 내용이다.

[ Session ]

  1. 클라이언트가 로그인을 위해 인증 정보를 서버에 전송합니다.
  2. 서버는 메모리에 사용자를 저장하고, 세션 아이디를 쿠키로 전달합니다.
  3. 클라이언트는 쿠키에 저장된 세션 아이디를 이용하여 요청을 보냅니다.
  4. 서버는 일치하는 세션 아이디를 메모리에서 검색한 후, 응답을 보내줍니다.

[ 서버 인증 기반의 문제점 ]

  • 세션을 DB에 저장해서 탐색하기 때문에 유저가 늘어날 수록 서버의 램이 과부하된다.
  • 여러 개의 프로세스를 돌리거나 서버 컴퓨터를 추가하는 것이 어려워진다. => 확장성이 좋지 않음
  • 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 있어 여러 도메인에서 관리하기 번거롭다.

[ JWT ]

  1. 클라이언트가 로그인을 위해 인증 정보를 서버에 전송합니다. (동일)
  2. 서버는 secret 정보를 이용하여 JWT를 생성하고, 클라이언트에게 전달합니다.
  3. 클라이언트는 로컬 혹은 브라우저에 저장해두었던 JWT를  이용하여 요청을 보냅니다.
  4. 서버는 JWT가 일치하는지 확인한 후, 응답을 보내줍니다.

[ Token 인증방식의 장점 ]

  • 무상태와 확장성. token은 클라이언트쪽에만 저장되므로 staeless하며, 서버를 확장하기에 적합한 환경을 제공한다.
  • 쿠키를 사용함으로 인해 발생하는 보안 취약점이 사라진다.
  • 토큰을 사용하여 다른 서비스에도 권한을 공유할 수 있다.

[ Token 인증방식의 단점 ]

🔹 JWT방식에서 토큰은 서버가 아닌 클라이언트에 존재하므로 서버에서 통제할 수 없다.

 

예를 들어 세션을 이용한 인가 방식에서는 서버의 메모리에서 세션 id를 지워버리면 사용자를 강제로 로그아웃 시킬 수 있다. 그러나 JWT 방식으로는 서버에서 관리할 수 없기 때문에 이러한 기능을 구현하지 못한다. 또한 이 토큰이 외부로 유출되었을 때 서버에서 이 토큰을 무효화할 방법도 없다.

 

이를 해결하기 위한 방법 :

 

사용자가 로그인을 하면 서버에서 두 개의 토큰을 발급한다.

서버는 클라이언트에게 수명이 짧은 Access 토큰과 수명이 긴 Refresh 토큰을 발급하고 Refresh 토큰의 상응값을 데이터베이스에 저장한다. ( 이때 db에 저장하면 서버가 느려질 수 있기 때문에 redis를 사용할 수도 있다. ) 사용자는 Access 토큰의 수명이 다하면 Refresh 토큰을 서버에게 보낸다. 서버는 Refresh 토큰을 데이터베이스에서 조회해보고 맞다면 새 Access 토큰을 사용자에게 보낸다. 이 Refresh 토큰이 안전하게 관리된다면 Refresh 토큰이 유효할 동안에는 Access 토큰이 만료될 때마다 다시 로그인할 필요 없게 된다.

서버에서 사용자를 강제 로그아웃 시키려면 데이터베이스의 refresh 토큰을 삭제하면 된다. 그렇게 하면 사용자가 refresh 토큰을 보내도 서버에서 새로운 access 토큰을 보내지 않을 것이기 때문이다. 그렇지만 access 토큰이 유효한 동안에는 이를 바로 차단할 방법은 없다. 이것이 JWT의 한계이다. 

 

[ Session 인증과 JWT 차이점 ]

두 방식의 가장 큰 차이점은 서버에 인증 정보를 저장하지 않는다는 점이다. 그렇기 때문에 클라이언트의 요청마다 인증을 위해 DB를 탐색하는 과정이 필요하지 않고, 저장 공간도 필요하지 않다.

 

  장점 단점
Cookie & Session Cookie만 사용하는 방식보다 보안 향상
서버쪽에서 Session 통제 가능
네트워크 부하 낮음
세션 저장소 사용으로 인한 서버 부하
쿠키와 세션의 정보가 유출되면 보안의 위험이 있다.
쿠키는 클라이언트 내에 존재하므로 변조, 위조가 될 수 있다.
JWT 인증을 위한 별도의 저장소가 필요 없음
별도의 I/O 작업 없는 빠른 인증 처리
확장성이 우수함
토큰의 길이가 늘어날수록 네트워크 부하
특정 토큰을 강제로 만료시키기 어려움

 

📜 결론


🔹 세션 쿠키와 JWT(JSON 웹 토큰) 두 가지 모두 장단점이 있으며, 둘 중 하나를 선택하려면 이러한 장단점과 애플리케이션의 특정 요구 사항과의 관계를 이해하고 사용해야 한다.

 

📸 참조


https://stytch.com/blog/jwts-vs-sessions-which-is-right-for-you/

https://jhbljs92.tistory.com/entry/1-JWT-%ED%86%A0%ED%81%B0-%EC%9D%B8%EC%A6%9D%EA%B3%BC-%EC%BF%A0%ED%82%A4-%EC%84%B8%EC%85%98-%ED%86%A0%ED%81%B0

'Hub Web > Web' 카테고리의 다른 글

[Web] HTTP 프로토콜에서 쿠키와 세션을 사용하는 이유  (0) 2024.04.05
[Web] CORS와 해결 방법  (0) 2024.04.01
[Web] REST API와 URI 설계  (0) 2024.03.16