- 토큰 방식 이전에는 세션 기반 인증이 많이 사용되었음.
- 세션은 사용자의 상태(정보)를 서버에 저장하고 있기 때문에 서버에 부담을 줌
1) 사용자가 많아질 수록, 많은 메모리를 차지
2) 매 요청마다, 서버는 세션 저장소를 조회해야함.- 세션 방식은 서버의 수평확장(Scale-Out: 서버의 대수를 늘림)이 어려움
- 세션 저장소에 문제가 생기면, 사용자 인증 체계가 무너짐
- 토큰 기반 인증은 암호화된 보안 토큰을 생성하는 인증 방식이다. 토큰은 사용자가 웹 사이트에 자신의 신원을 확인하게 해주며, 웹 사이트는 고유한 암호화된 인증 토큰을 생성한다.
- 사용자는 해당 토큰을 통해 아이디, 비밀번호를 입력하지 않아도, 인가가 필요한 페이지 및 자원에 접근할 수 있다.
- 즉, 토큰은 문을 열어주는 열쇠와 같은 역할을 한다.
토큰 기반 인증은 사용자의 자격 증명을 한번만 확인하고, 자격이 증명되면 토큰이 할당되고 정해진 시간동안 접근할 수 있다. 해당 절차는 다음과 같다.
- 요청: 사용자는 새로운 사이트에 접속하려 할 때 인증되지 않은 상태
- 검증: 사용자는 자격증명(아이디와 비밀번호)를 제공하여 서버에 보냄
- 토큰 발급: 서버는 제공된 자격증명을 검증하고, 유효하다면 고유한 토큰을 생성
- 저장 : 생성된 토큰은 서버가 아닌 클라이언트에 저장
- 만료 : 토큰은 일정 기간동안 유효하며, 만료되면 다시 인증을 하여 새 토큰을 발급받아야함.
- 물리적 토큰 (Hardware Token)
- 실제로 존재하는 물리적 장치
- USB 토큰
- JWT 토큰 (JSON WEB Token)
- JSON 형식으로 데이터를 표현하고 전송하기 위한 토큰
- 사용자 인증과 데이터 전송을 위해 사용됨
- OTP 토큰 (One-Time password Token)
- 일회용 비밀번호를 생성하는 토큰
- API 토큰
- 웹 서비스나 애플리케이션 간의 인증 및 권한 부여를 위해 사용되는 토큰
- 클라이언트가 서버의 API를 호출하거나 데이터를 전송할 때 사용됨
- Oauth
JWT는 정보를 안전하게 전송하기 위한 인터넷 표준(RFC 7519)으로 사용자의 인증(Authentication)이나 인가(Authorization) 정보를 서버와 클라이언트 간에 안전하게 주고 받기 위해 사용된다. JSON 객체를 이용하여 토큰을 전송한다.
크기가 작기 때문에 URL, HTTP Header, HTTP body로 보낼 수 있고 빠르게 전송할 수 있다.
인터넷 표준: 컴퓨터 네트워크 공학에서 인터넷 표준(Internet Standard, STD)은 인터넷에 적용되는 기술이나 방법론을 표준으로 제정한 규격
JWT는 Header, Payload, Signature로 구성되어있다.
"alg"와 "typ"을 가지고 있다.
- alg: 서명 알고리즘(암호화 알고리즘)
- typ : 토큰 유형
iss, exp, sub 등 여러가지 정보가 담긴다. 해당 데이터들은 Base64 디코딩으로 쉽게 알 수 있기 때문에 민감한 정보는 저장할 수 없다.
- 등록된 클레임(Registered claims): JWT 표준에 정의된 클레임(미리 정의됨)이다.
토큰의 유효 기간, 발급자, 주제 등을 포함한다.
iss: 발급자, exp(만료시간), sub(주제), aud(대상자)- 공개 클레임(Public claims): 사용자 정의 Claim
공개영 정보이며, 충돌방지를 위해 URI 포맷을 이용해 저장한다.- 비공개 클레임(Private claims): JWT 표준에 포함되지 않았지만, 특정 애플리케이션에서만 사용하는 사용자 지정 정보를 나타냄.
- 공개 클레임은 여러 애플리케이션 간에 공유되며 사용자 정의 정보를 전달하는 데 사용되고, 비공개 클레임은 특정 애플리케이션 내에서만 필요한 정보를 전달하고 저장하는 데 사용됨
클레임(Claim)은 JWT(JSON Web Token) 내에서 토큰에 포함되는 정보를 의미한다. 페이로드(Payload) 부분에 담기는 데이터들을 클레임이라고 부른다.
Example
"iss": "example.com", "sub": "user123", "aud": "app", "exp": 1679680000, "iat": 1679000000, "role": "user", "email": "user@example.com", "language": "en", "account_number": "123456789", "custom_data": "Some custom data only for this app" }
iss: 토큰 발급자(issuer)를 나타냄
sub: 토큰 주제(subject)를 나타냄
aud: 토큰 대상자(audience)를 나타냄
exp: 토큰 만료 시간(expiration time)을 나타냄
iat: 토큰 발급 시간(issued at)을 나타냄
role: 사용자 역할(role)을 나타냄
email: 사용자 이메일 주소를 나타냄
language: 사용자 언어 설정을 나타냄
account_number: 사용자 계정 번호를 나타냄
custom_data: 특정 애플리케이션 내에서만 사용되는 사용자 지정 데이터를 나타냄
토큰의 무결성을 보장하기 위해 사용된다. Siganture(시그니처)는 Header와 Payload를 함께 암호화하여 생성되며, 이를 통해 토큰이 변조되지 않았음을 검증할 수 있음.
주요 역할은 다음과 같다.
- 무결성 보장 : 토큰의 헤더와 페이로드가 생성 시점과 내용 그대로인지 확인할 수 있음. 토큰이 중간에 수정되었다면 시그니처의 일치 여부를 통해 확인할 수 있음.
- 변조 방지 : 시그니처는 비밀 키를 사용하여 생성됨으로, 변경 및 조작을 탐지할 수 있음.
생성방식
- 헤더와 페이로드 결합: 토큰의 헤더와 페이로드를 JSON 형식으로 문자열로 결합함. 이 떄 문자열은 인코딩 되지 않은 원본 데이터
- 비밀 키 사용: 비밀 키를 사용하여 결합된 문자열을 암호화함. 사용하는 암호 알고리즘은, 토큰의 헤더에 정의되어 있는 알고리즘
- 암호화 결과 생성: 암호화된 결과는 시그니처가됨. 시그니처는 토큰의 무결성을 검증하는데 사용
JWT는 헤더와 페이로드를 각각 Base64 인코딩을 한 후, 시그니처를 합쳐서 생성한다. 각 부분은 '.'으로 구분한다.
헤더.Base64인코딩된헤더 + "." + 페이로드.Base64인코딩된페이로드 + "." + 시그니처
유효기간이 짧은 Token을 발급하게 되면. 사용자 입장에서 자주 로그인(사용자 인증)을 해야 하기 때문에 번거럽고, 유효 기간이 길다면 제 3자에게 토큰을 탈취당할 수 있다. 또한 Statelss 하기 때문에, 해당 토큰을 가지고 있는 클라이언트가 본인이 맞는지 확인할 수 없다. 그 점들을 보완하기 위해 Refresh Token을 사용한다.
Access Token은 사용자를 인증하고, 클라이언트가 보호된 자원에 접근할 수 있도록 하는 토큰이다. 보통 짧은 유효 기간을 가지며, 유효 기간이 만료되면 다시 로그인해야한다. 반면, Refresh Token은 Access Token을 재발급 받을 때 사용되는 토큰으로, 일정 기간 동안 보관되며, Access Token이 만료되었을 때 사용자의 로그인 상태를 유지한다.
즉 Access Token의 유효기간을 짧게 하여, 만약 Access Token이 탈취 당하더라도, 그 피해를 줄이기 위해(만료시간을 짧게하여) Refresh Token을 사용한다.
만약 Access Token의 유효기간을 7일이라 가정하면, 해커는 해당 계정에 대한 7일 이용권... 그래서 짧게(30분~1시간) 정도로 설정해서 피해를 최소화.
대표적으로 accessToken과 Refresh Token 방식을 사용하는 프로토콜임.Oauth2.0은 클라이언트 애플리케이션이 사용자의 데이터에 접근할 수 있도록 도와주는 개방형 표준 프로토콜
위 그림처럼 로그인의 과정을 페이스북, 네이버, 카카오 등 다른 인가 서버를 이용하여 사용자 인증을 하는 방식을 Oauth라고 한다.Oauth 프로토콜은 인가서버와 리소스 서버간의 통신을 통해, 사용자의 인증 및 권한을 부여한다. Refresh Token은 인가 서버에서 생성되어 클라이언트에게 제공된다.
인가 서버는 Referesh Token을 안전한 방식으로 저장하고 유효성 검사를 수행하여 악의적 사용을 방지하고, 새로운 Access Token을 발급할 때도 인가 서버의 관여가 필요하다.
우선 털리면 답이 없다고 한다. 정확히는 예방 방법
서버에서 Refresh Token은 DB(Redis)에 저장하게 된다면, 서버와 클라이언트 간에 연결고리가 생기기 때문에, 완전한 Statelss라고 보긴 어렵다고 한다. 하지만 세션보다는 DB에 IO 할 일이 없긴 하다.
Refresh Token을 탈취하여, 해커가 사용자가 Access Token을 발급받을 수 있음 -> 해당 방법의 방지로 RTR 기법 도입.
Resdis를 이용한 토큰 탈취 대응 시나리오 해당 글에서 Access Token에 발급 과정에 대해 설명해준다. Refresh Token은 사용자 정보를 가져올 Key 역할을 하는데, Access Token이 만료된다면, 서버는 Rrefresh Token으로 사용자의 정보를 가져와서 Access Token을 발급
이 부분은 좀 더 공부해야할 듯..
https://stackoverflow.com/questions/56133083/how-to-generate-a-refresh-token
해당 링크에 따르면, 굳이 JWT일 필요도 없고, 임의의 문자열 정도?
만약 JWT라면, 유효성 검증을 위해 DB에 별도로 접근하지 않아도 되는듯.
참고글: https://hudi.blog/refresh-token/
https://www.logintc.com/types-of-authentication/token-authentication/
https://velopert.com/2350
https://velopert.com/2389
https://frontegg.com/blog/token-based-authentication
https://jwt.io/introduction
https://supertokens.com/blog/what-is-jwt
https://velog.io/@park2348190/JWT%EC%97%90%EC%84%9C-Refresh-Token%EC%9D%80-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80
https://subscription.packtpub.com/book/security/9781784395407/8/ch08lvl1sec51/reference-pages
https://puleugo.tistory.com/154#article-6--refresh-token%EC%9D%B4-%ED%83%88%EC%B7%A8-%EB%8B%B9%ED%95%98%EB%A9%B4-%EC%9A%B0%EC%A7%A4%EA%B1%B4%EB%8D%B0?
https://mgyo.tistory.com/832