현재까지 해온 프로젝트에서는 Spring Security & (Session & Cookie) 방식으로 전개했다.
그래서 경험하지못한 JWT의 개념을 정리하면서 여러가지를 연관지어 정리해보려고 한다.
이 글에서는 Spring Security & JWT 뿐만아니라 연관이 있는 모든 면에서 바라 보기때문에
특정 개념을 찾으러 왔다면, 필요한 부분을 찾아가기 바란다.
HTTP의 자세한 정보는 HTTP(HyperText Transfer Protocol) 를 참고하면 된다.
이 글에서 모든 과정은 HTTP 를 기반으로 데이터를 주고받는 통신을 하기 때문에 두가지 특성은 알고 있어야한다.
첫번째 "HTTP는 연결을 유지하지 않는다."
서버와 클라이언트는 한번의 통신을 하고나면 연결은 끊어진다.
두번째 "HTTP는 상태를 유지하지 않는다."
처음 통신을 하고나면 두번째 통신때에 이전 정보를 가지고 있지않기 때문에 새롭게 갱신해주어야한다.
대표적으로 사용자의 로그인 정보를 어디에서 유지,저장 하는가에 따라 방식을 나눈다.
세션 방식은 서버의 메모리, DB와 같은 서버의 자원들을 사용해서 사용자의 정보를 유지시키는 방식이다.
여기서 위 사진을 보면 쿠키(Cookie)도 등장한다
쿠키(Cookie)란? 주로 세션 관리( 서버에서 관리하는 로그인 등의 정보를 의미한다. ), 개인 설정유지, 사용자 트래킹( 사용자의 행동을 기록하고 분석하는 것 ) 용도로 사용된다.
ex) 로그인정보유지, 방문기록
캐시(Cache)란? 특정데이터(주로 쓰는)를 임시저장소에 넣어두고 빠르게 로딩할 수 있도록하는 용도로 사용된다.
ex) 오디오, 비디오
토큰 방식보다는 보안에 강하다는 장점이 있지만,
서버의 확장성이 떨어지고, 서버의 자원(세션을 저장, 유지할 공간)이 많이 필요하며, 세션이 서버에 저장되고, 트래픽 분산을 위해서 여러 대의 서버를 사용할 때 사용자가 로그인을 하면 만들어진 세션을 참조해야하기 때문에 처음 로그인한 그 서버에서만 요청을 보내야한다는 단점이 있다.
이를 보안하기위해 !
토큰 방식은 사용자가 로그인을 하면 서버에서 발행해주는 토큰을 가지고 브라우저의 저장소에 토큰을 유지시키는 방법이다.
이게 바로 흔히 말하는 JWT이다.
서버에 저장하지 않아서 서버에 확장성이 있다.
로그인을 했을때 해당 서버에만 요청을 보내는 것이 아닌 요청이 들어왔을 때 해당 토큰이 유효한지만 체크하면 되기 때문에 어떤 서버로 요청을 보내도 상관없다는 뜻이다.
위에서 말했듯이 토큰 방식은 사용자가 로그인을 하면 서버에서 발행해주는 토큰을 가지고 브라우저의 저장소에 토큰을 유지시키는 방법이다.
인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미한다.
그리고 JWT 기반 인증은 JWT 토큰을 HTTP 헤더에 실어 서버가 클라이언트를 식별하는 방식이다.
조금 더 살펴보면, JWT는 JSON 데이터를 Base64 URL-safe Encode 를 통해 인코딩하여 직렬화한 것이며, 토큰 내부에는 위변조 방지를 위해 개인키를 통한 전자서명도 들어있다.
따라서 사용자가 JWT 를 서버로 전송하면 서버는 서명을 검증하는 과정을 거치게 되며 검증이 완료되면 요청한 응답을 돌려준다.
JWT는 .을 구분자로 나누어 세 가지 문자열의 조합이다.
.을 기준으로 좌측부터 헤더(Header), 페이로드(Payload), 시그니처(Signature)를 의미한다
Header 에는 JWT 에서 사용할 타입과 해시 알고리즘의 종류가 담겨있다.
Payload 는 서버에서 첨부한 사용자 권한 정보와 데이터가 담겨있다.
Signature 에는 Header, Payload 를 Base64 URL-safe Encode 를 한 이후 Header 에 명시된 해시함수를 적용하고, 개인키(Private Key)로 서명한 전자서명이 담겨있다.
전자서명에는 비대칭 암호화 알고리즘을 사용하므로 암호화를 위한 키와 복호화를 위한 키가 다르다. 암호화(전자서명)에는 개인키를, 복호화(검증)에는 공개키를 사용한다.
인코딩? 사람이 인지하지 못하고 컴퓨터가 이해할 수 있도록 바꿔주는 것을 의미한다.
디코딩? 디코딩은 인코딩의 반대로서 사람이 이해 할 수 있도록 바꿔주는 것을 의미한다.
JWT 토큰을 생성해 확인할때는, 아래 공식사이트에서 JWT 토큰을 인코딩(생성) 하거나 디코딩 할 수 있다.
JWT.IO
Session & Cookie : 쿠키만 사용하는 방식보다 보안 향상되고 서버 쪽에서 세션을 통제 가능하고 네트워크 부하가 낮다는 장점이 있지만 세션 저장소의 사용으로 인한 서버부하 우려가 있다.
JWT : 인증을 위한 별도의 저장소가 필요없다, 별도의 입출력(I/O) 작업 없는 빠른 인증 처리와 확장성이 우수하다는 장점이 있지만 토큰의 길이가 늘어날수록 네트워크 부하우려와 특정 토큰을 강제로 만료시키기 어렵다
인증(Authentication): 로그인, 아이디와 패스워드 등을 통해 특정 서비스에 일정권한이 주어진 사용자임을 검증을 받는 것.
인가(Authorization): 사용자가 인증(로그인)을 받은 후 그 사용자가 특정 리소스에 액세스할 수 있는지 여부를 결정하는 프로세스이다.
Spring 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레이워크이다.
Spring Security는 보안과 관련해서 체계적으로 많은 옵션을 제공해주기 때문에 개발자 입장에서는 일일이 보안관련 로직을 작성하지 않아도 된다는 장점이 있다.
또한 다양한 필터(Filter)를 사용하여 커스터마이징이 가능하다
구동원리를 간단히 살펴보면,
Spring Security는 '인증'과 '권한'에 대한 부분을 Filter 흐름에 따라 처리한다.
Filter는 Dispatcher Servlet으로 가기 전에 적용되므로 가장 먼저 URL 요청을 받지만, Interceptor는 Dispatcher와 Controller사이에 위치한다는 점에서 적용 시기의 차이가 있다
위 사진은 현재 사용중인 부분이다 이러한식으로 Filter chain 을 커스터마이징하여 사용한다.
Spring Security 는 기본적으로 인증 절차를 거친 후에 인가 절차를 진행하게 되며, 인가 과정에서 해당 리소스에 대한 접근 권한이 있는지 확인을 하게 된다. Spring Security 에서는 이러한 인증과 인가를 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 Credential 기반의 인증 방식을 사용한다.
References (참고 자료)
- 토비의 스프링 3.1
- https://ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4
- https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-JWTjson-web-token-%EB%9E%80-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC
- https://velog.io/@junghyeonsu/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%90%EC%84%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95