이론 : Spring Security란, JWT Token, 세션, 쿠키 차이점 조사
= Spring Security는 Spring 기반의 어플리케이션의 보안(인증, 권한, 인가 등)을 담당하는 스프링 하위 프레임워크이다.
이 프레임워크를 사용하면 보안처리를 자체적으로 구현하지 않아도 필요한 기능을 쉽게 구현할 수 있다. 즉, 보안과 관련해서 체계적으로 많은 옵션을 제공해주기 때문에 일일이 보안관련 로직을 작성하지 않아도 된다.
➡ Spring Security는 인증과 권한에 대한 부분을 Filter 흐름에 따라 처리하고 있다.
인증
: 인증은 해당 사용자가 본인이 맞는지 확인하는 절차이다. 유저가 누구인지 확인하는 것, 회원가입과 같은 로그인을 하는 것을 말한다.
인가
: 인증된 사용자가 요청한 자원에 접근 가능한지를 결정하는 절차이다. 즉, 유저에 대한 권한을 확인, 허락하는 것을 말한다.

(1) 처음에 요청이 들어오면 Filter를 거친다.
(2) 요청에 따른 Token을 생성한다. (Authentication 인터페이스의 구현체이다.)
(3) AuthenticationManager에게 이 Token이 올바른 유저인지 물어본다.
(4) AuthenticationManager는 1개 이상의 AuthenticationProvider를 갖고 있는데, AuthenticationProvider는 Token 객체를 적절히 판단하여 인증처리를 시도한다.
(5) AuthenticationProvider가 우리가 직접 구현한 서비스(UserDetailsService 구현 클래스)에 해당 유저에게 인증요청을 보내 사용자 정보를 가져온다.
(6) UserDetailsService 구현 클래스는 사용자 정보를 가져와 UserDetails를 반환한다.
(7-10) Provider는 UserDetailsService에서 반환된 UserDetails와 클라이언트가 제공한 인증정보(Token)를 대조해서 이용자가 정당한 사용권한을 가지고 있는지 확인한다. 그리고 SecurityContext에 저장한다.
출처 ) Spring Security
= 클라이언트가 웹사이트에 접속할 때 그 사이트가 사용하게 되는 일련의 작은 기록 파일이라고 생각하면 된다.
서버가 클라이언트에 정보를 전달할 때 저장하고자 하는 정보를 응답 헤더(Cookie)에 저장하여 전달한다.
Key-Value 형식의 문자열 형태로 저장한다.
➡️ 쿠키란, 브라우저에 저장되어서 사용하는 작은 텍스트 파일로써 접속자 장치를 인식하거나 일부 데이터를 저장하는 역할을 한다.

쿠키는 간단하게 이야기하자면 아래와 같이 로그인을 했을 때 Set-Cookie의 형태로 반환을 받은 쿠키를 토대로 로그인이 필요한 요청을 할 때마다 받은 쿠키를 던져 요청을 하는 동작구조를 가진다.

이런 쿠키를 쓰는 이유는 특정 정보를 저장하기 위함으로, 예를 들면 로그인의 사용자 정보 저장이 있다.
하지만 현재는 아래의 단점들 때문에 쿠키만을 온전히 인증에 사용하지는 않는다.
= 무언가에 대한 특정 인증 정보를 서버가 가지고 있고, 그 값을 클라이언트에게 전달하여 마치 키를 주고 자물쇠를 여는 방식으로 인증을 한다.
➡️ 세션 ID를 특정 저장소에 저장하여 사용한다.
개인 민감정보를 그대로 노출했을 때의 단점을 막아내기 위해서 나온 것이 바로 Session이다.
쿠키와 같은 매개체를 주고받음으로써 "매번 로그인 시 id와 pw를 작성해서 전달해야 한다"에 대한 단점을 보완하려는 것이다.
여기서 id와 pw를 주고 받지말고 인증 정보 자체를 특정 세션 저장소에 저장하여 해당 값을 쿠키에 담아 클라이언트가 쿠키를 요청할 때마다 세션 저장소에 있는 정보랑 동일한지로 로그인을 통해 확인하자는 것이 주요 핵심이다.
➡️ 클라이언트로부터 오는 일련의 요청을 하나의 상태로 보고 그 상태를 일정하게 유지하는 기술이며 클라이언트가 웹 서버에 접속해있는 상태가 하나의 단위
🌟 나는 여기서 쿠키를 하나의 매개체(포장지)이고, id와 Pw을 통한 인증정보(내용물)를 쿠키(포장지)에 담아 보내는 방식을 "세션"이라고 부른다. 라고 이해한다.
(1) 클라이언트 요청
(2) Request-Header 필드의 Cookie 에서 세션ID를 보냈는지 확인
(3) 세션ID가 없을 경우, 서버에서 생성하여 클라이언트에게 전송
(4) 쿠키를 사용해 세션ID를 서버에 저장
(5) 클라이언트 재접속 시, 쿠키를 이용하여 세션ID 값을 서버에 전달
| 구분 | 쿠키(Cookie) | 세션(Session) |
|---|---|---|
| 저장위치 | 클라이언트 | 서버 |
| 라이프 사이클(만료시점) | 쿠키 저장시 설정 | 브라우저 종료 시 삭제 |
| 보안 | 비교적 취약 | 안전 |
| 속도 | 빠름 | 비교적 느림 |
➡️ 하지만 세션은 제공받은 세션Id를 통해서 서버에서 다시 데이터를 참조해야 하므로 쿠키에 비해 느리다.
이 단점을 해결하기 위해서 나온 것이 바로 JWT이다.
= JWT 토큰은 JSON 객체에 인증에 필요한 정보들을 담은 후 비밀키로 서명한 토큰으로, 인터넷 표준 인증 방식이다. 공식적으로 인증&권한허가 방식으로 사용된다.
여기서 일반 로그인 과정과 인증 방식을 헷갈릴 수 있기 때문에 JWT 프로세스를 살펴보도록 하겠다.

➡️ 여기까지가 JWT를 발급받기까지의 (로그인 전)과정이다. 로그인 이후는 다음과 같다.
➡️ 그런데 로그인 후에도 왜 매번 JWT를 헤더에 넣어서 보내는 걸까?
그 이유는 바로 HTTP의 특성 때문이다.

Connectionless : 한 번 통신이 이뤄지고 난 후에 연결이 바로 끊어짐.
Stateless : 이전 상태를 유지/기억하지 않음.
인터넷을 사용할 때는 HTTP 프로토콜을 사용해서 통신을 한다. 인터넷과 관련된 모든 활동을 할 때 HTTP 통신으로 서버와 클라이언트가 데이터를 주고 받는다.
그런데 이 HTTP의 특징은 connectionless하고 stateless하다는 특성이 있다.
즉 화면을 이동하며 새로운 API를 요청하면 다시 신뢰할만한 사용자인지 인증하는 과정을 거쳐야 하는 것이다.
매번 사용자가 인증하는 과정은 귀찮을 뿐만 아니라 통신이 느려지는 문제가 될 수 있다. 따라서 인증된 사용자가 어느 정도 기간동안 재인증하지 않아도 되도록(로그인 유지) 만든 것이 Access Token이다
= JWT는 Header, Payload, Signature 3개로 구성되어 있다.

= Signature에서 사용하는 알고리즘은 대표적으로 RS256(공개키/개인키)와 HS256(비밀키/대칭키)가 있다.
= 사용자 정보의 한 조각인 클레임(claim)이 들어있다.
= Signature는 헤더와 페이로드의 문자열을 합친 후에, 헤더에서 선언한 알고리즘과 key를 이용해 암호한 값이다
Header와 Payload는 단순히 Base64url로 인코딩되어 있어 누구나 쉽게 복호화할 수 있지만, Signature는 key가 없으면 복호화할 수 없다. 이를 통해 보안상 안전하다는 특성을 가질 수 있게 되었다.
위에서 언급한 것처럼 header에서 선언한 알고리즘에 따라 key는 개인키가 될 수도 있고 비밀키가 될 수도 있다.
개인키로 서명했다면 공개키로 유효성 검사가 가능하고, 비밀키로 서명했다면 비밀키를 가지고 있는 사람만이 암호화/복호화, 유효성 검사가 가능하다.
출처
https://auth0.com/docs/secure/tokens/json-web-tokens
https://brunch.co.kr/@jinyoungchoi95/1
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
https://velog.io/@beneficial/Session%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80
https://brunch.co.kr/@jinyoungchoi95/1
https://ji5485.github.io/post/2020-08-01/what-is-cookie-and-session/#%EC%84%B8%EC%85%98-%EC%88%98%EB%A6%BD-%EA%B3%BC%EC%A0%95