사용자 인증의 여러 방식들
1) 쿠키와 세션
HTTP는 Stateless, Connectionless 특징이 있기 때문에, 사용자 인증을 유지할 수 있는 기능이 필요했습니다. 그래서 클라이언트가 로그인 등으로 한 번 사용자 인증을 하면, 그 인증을 유지할 수 있도록 쿠키와 세션이라는 기술을 지금껏 사용해 왔습니다.
그러나 쿠키는 브라우저에 사용자 정보가 기록되기 때문에 위변조의 가능성이 높아 보안이 취약하며, 세션 또한 서버의 메모리를 차지하고 있기 때문에 동접자가 많은 웹 사이트일 경우 서버 과부하의 원인이 되며, 또한 세션 정보가 중간에 탈취당할 수 있기 때문에 보안에 완벽하다고 할 수가 없습니다.
쿠키와 세션의 문제점들을 보완하기 위해 토큰(Token)기반의 인증 방식이 도입되었습니다.토큰 기반의 인증방식의 핵심은 보호할 데이터를 토큰으로 치환하여 원본 데이터 대신 토큰을 사용하는 기술입니다.만약 토큰 전송과정에서 중간에 토큰이 탈취 당하더라도 데이터에 대한 정보가 암호화 되어있어 공격자가 본래 내용을 알 수 없게 됩니다.즉, 보안적으로 우수하다고 할 수 있습니다.
2) (OAuth)[https://parkhongbeen.github.io/2020/06/11/OAuth/]
토큰 방식을 사용하는 웹 서비스는 우리가 여러 웹 서비스를 이용하면서 쉽게 찾아볼 수 있습니다.”페이스북으로 로그인”, “네이버아이디로 로그인”, “구글 계정으로 로그인” 등 다른 웹 서비스의 계정으로 사용자 인증을 대신하는 기술을 OAuth라고 합니다.
OAuth는 토큰 기반의 사용자 인증 방식입니다. 구글,페이스북,네이버로부터 토큰을 발급 받아 구글,페이스북,네이버에 로그인 할 수 있도록 권한을 부여 받는 것입니다.여기서 권한이란 로그인 뿐만 아니라 API를 호출하는 권한도 의미합니다.
그런데 여기서 발급받은 토큰은 아무 의미 없는 문자열 형태입니다.때문에 구글,페북,네이버 서버에서는 토큰과 연관된 정보를 탐색한 후에 어떤 기능을 수행하게 됩니다.이와 달리 아래의 JWT는 서버의 탐색이 필요없습니다.
JWT(Json Web Token)
(JWT 공식문서를 참고하시면 좋을 것 같습니다.)
JWT는 이름에서 알 수 있듯이 Json으로 된 Token을 사용합니다. 즉, OAuth와 같이 Token기반의 인증 방식이라는 것입니다.
그런데 JWT는 토큰 자체가 의미를 갖는 Claim기반의 토큰 방식입니다.Claim은 사용자에 대한 속성을 의미합니다. JWT는 OAuth처럼 아무 의미없는 문자열로 된 토큰이 아니라는 뜻입니다.
Token을 생성하고 요청하는 프로세스는 다음과 같습니다.
- JSON 객체에 요구사항을 작성
- 어떠한 암호화 방식을 사용해서 문자열로 인코딩
- HTTP header에 추가함으로써 사용자 인증을 요청
- 서버에서는 Header에 추가된 Token을 디코딩하여 사용자를 인증
JWT 특징
- JWT는 그 자체가 암호화된 문자열 데이터입니다.
- 토큰은 HTTP header에 추가되기 때문에 서버에 따로 보관할 필요가 없으므로 서버에 부화를 일으키지 않습니다.
- 토큰을 생성할 때 암호화 과정을 거치므로 보안적으로 안전합니다.
- 그래도 누군가 탈취한다면 권한을 사용할 수 있기때문에 짧은 시간의 유효시간을 두는것을 권장함
JWT의 데이터 무결성 - HMAC
JWT는 토큰이 탈취 당하더라도 위변조의 위험을 벗어날 수 있도록 무결정을 보장하는 몇 가지 방법이 있습니다.
그 방법 중 하나는 데이터를 암호화하고, 해싱하는 HMAC(Hash-based Message Authentication)기법을 사용하는 것입니다. 해싱은 원문을 일정 길이의 byte로 변환하는데 그 결과가 유일하다는 특징이 있습니다. 즉, 원문이 조금이라도 바뀌면 해싱의 결과는 완전히 달라집니다. 그래서 토큰을 탈취해서 데이터를 수정하게 되면 해싱의 결과가 완전히 달리지므로 토큰이 위조되었다는 것을 알 수 있게 됩니다.
JWT 구조 및 생성
JWT 는 .
을 구분자로 3가지 문자열로 되어있습니다.
많은 프로그래밍 언어에서 JWT를 지원하는데, 각 언어의 라이브러리에서 자동으로 인코딩 및 해싱작업을 해줍니다.(조건은 헤더,내용,서명에 적절한 속성과 값들을 명시할 때)
위 사진은 JWT공식홈페이지에서 제공해주는 디버거 기능입니다. 사진을 보고 설명하겠습니다.
1) 헤더(header)
- typ
- 토큰의 타입을 명시합니다
- alg
- 해싱 알고리즘을 명시합니다
- 이 알고리즘은 서버에서 토큰을 검증할 때 signature에서 사용됩니다.
2) 내용(payload)
내용에는 토큰에 대한 정보를 작성합니다. 정보는 속성, 값으로 표현되며 이를 claim이라고 합니다. claim은 다음과 같이 3가지로 작성할 수 있습니다.
- registered claim
- 미리 정의된 claim으로써, 토큰에 대한 정보를 작성합니다
- iss
- 토큰 발급자
- sub
- 토큰 제목
- aud
- 토큰 대상자
- 그 밖에 여러 claim들이 있으며, 더 많은 정보는 JWT공식문서를 참고해주세요.
- public claim
- 공개적인 claim을 명시하는데, 충돌방지를 위해 URI형식으로 작성합니다.
- private claim
- 서버와 클라이언트가 협의한 claim을 명시합니다.
서명(signature)
서명에서는 헤더와 인코딩 값과 내용의 인코딩 값을 .
으로 연결하여 합친 후 비밀키로 해싱합니다.일종의 암호화하는 작업이라고 생각하시면 됩니다.
위의 header, payload,signature의 각 값들을 .
으로 합치면 하나의 JWT가 생성됩니다.이렇게 생성된 JWT를 HTTP header에 추가하여 서버에 요청을 하면 서버에서는 이를 디코딩하여 사용자 인증을 하게 됩니다.
JWT는 자체적으로 정보를 갖고 있는 토큰이기 때문에 서버에 저장될 필요가 없습니다. 즉, 서버로부터 독립적이라고 할 수 있으며, 서버의 부담을 덜어줄 수 있다는 장점이 있습니다.
JWT는 브라우저의 쿠키, local storage, session storage에 저장할 수 있지만, HTTP Only 옵션의 쿠키에 저장하는것이 좋습니다.
참고자료