SpringBoot로 개발을 하다 보면, 로그인 기능을 구현할 일이 분명히 생긴다.
우리는 일반적으로 로그인 기능을 구현할 때 아래의 3가지 방법을 사용한다.
- Cookie를 이용한 로그인 방법
- 브라우저에 정보를 저장하며, 값을 그대로 보내기 때문에 보안에 가장 취약하다!
- 쿠키엔 용량 제한이 존재해서 많은 정보를 담을 수 없다.
- 쿠키의 크기가 커지면, 서버에 부하가 심해진다.
- Session을 이용한 로그인 방법
- Client 쿠키에 Session ID 값만을 남겨둔다.
- 쿠키가 노출이 되더라도, Session ID 자체는 개인정보가 없어 괜찮다.
- 하지만 해커가 Session ID를 탈취한다면, 해당 클라이언트로 위장이 가능하다!
- 서버 저장소를 쓰므로 요청이 많아지면 서버에 부하가 심해진다.
- Token을 이용한 로그인 방법
- Data의 길이가 길어 인증 요청이 많으면 네트워크에 부하가 심해진다.
- Payload가 암호화되지 않기 때문에 중요 정보는 담을 수 없다.
- 탈취 당하면 대처가 어렵다!
위의 3가지 중 Token을 이용한 방법이 바로 JWT가 되겠다.
JWT(JSON Web Token), 즉 JSON의 형태로 Token을 발급해주는 방식인 것이다.
Authorization Header
먼저, 컴퓨터 보안에서의 인증은 아래의 두 가지가 있다.
- Authentication : 신분을 제시한 사람이 과연 본인이 맞는가?
- Authorization : 인증을 받은 사람이 해당 API를 호출할 권한이 있는가?
보통 Token은, Authorization을 위해 Request Header에
Authorization : <type> <credentials>
의 형태로 담겨져 온다.
- Type
- Basic : 사용자 ID/PW를 Base64로 인코딩한 값을 Token으로 쓴다.
- Bearer : JWT나 OAuth에 대해 토큰을 쓴다.
- Digest : 서버에서 난수 데이터 문자열을 보낸다.
- Client는 사용자 정보와 Nonce를 포함한 해쉬 값으로 응답.
- HOBA : 전자 서명을 기반으로 한다.
- Mutual : 암호를 이용한 Client-Server 상호 인증
- AWS4-HMAC-SHA256 : AWS 전자 서명 기반 인증
당연히 우리는 OAuth Bearer Type을 통해서 JWT를 이용할 것이다.
OAuth 2.0(Open Authorization)
OAuth 2.0은 인증을 위한 개방형 표준 보안 프로토콜이다.
해당 프로토콜은, 사용자가 비밀번호를 제공하지 않아도 접근 권한을 부여함이 핵심이다.
대표적으로, Google, KAKAO, Facebook 등에서 제공 하는 간편 로그인 기능이 있다.
다음과 같은 용어를 사용한다.
- Resource Owner : Application의 사용자로, 보호된 리소스에 접근 권한을 부여한다.
- Client : 보호된 자원을 사용하려 접근 요청하는 Application
- Resource Server : 사용자의 자원을 제공하는 서버
- Authorization Server : 인증 및 인가를 수행해 접근 자격을 확인하고 Token을 부여하는 서버
- Resource, Authorization Server는 Naver, Google 같은 Server가 될 수 있다.
다음과 같은 4가지 종류의 방식이 존재한다.
- Authorization Code Grant
- OAuth의 기본이 되는 방식으로 가장 많이 사용된다.
- Refresh Token의 사용이 가능하다.
- Implicit Grant
- 따로 코드 승인 없이 바로 Access Token을 발급한다.
- Refresh Token의 사용이 불가능하다.
- Resource Owner Password Credentials Grant
- Code가 아닌 Username과 Password로 Token을 받는다.
- Refresh Token의 사용이 가능하다.
- 외부 서비스의 경우엔 이 방식을 적용하면 안된다.
- Client Credentials Grant
- Client에서 제출하는 자격증명을 통해 Token을 발급한다.
- Client 측에서 자격증명을 안전하게 보관해야 한다.
OAuth Protocol Flow
해당 Flow Diagram을 미루어보아, OAuth와 JWT의 관계를 알 수 있다.
OAuth는 보안을 제공하는 프로토콜이자 프레임워크라고 볼 수 있으며,
JWT는 해당 과정에 사용되는 Token의 종류라고 볼 수 있을 것이다.
JWT의 구성
JWT는 BASE64
로 인코딩 된 아래와 같은 구조를 갖는다.
암호화 된 3개의 부분을 .
으로 직렬화 하여 사용한다.
JWT의 로그인 전략
위 사진과 같이 로그인 과정이 진행된다.
- Access Token
- ID의 권한을 인증하는 Token이다.
- 만료 기한이 존재하며, 보안을 위해 기한을 짧게 가져간다.
- Refresh Token
- Access Token 만료 시, 재발급에 대해 인가를 담당하는 Token이다.
아까 Token은 탈취 당하면 별다른 대처가 불가능하다고 했다.
그래서 우리는 Token을 2개로 분리해서 사용하는 전략을 사용한다.
Access Token은 탈취를 해도 사용할 수 없도록 만료 기한을 짧게 건다.
Refresh Token은 탈취가 되어선 안되도록 관리를 해야하는 재발급 인가 토큰이다.
Access Token이 만료되었을 때, Refresh Token과 함께 제시해서 일치하면, Access Token을 재발급 해주는 방식이다!
사용자가 로그아웃을 했을 시에는, Refresh Token을 파기하여 다시 로그인 할 때 발급을 새로 해준다.