쿠키와 세션 - 서버에서 정보 자체를 갖고있다. 쿠키의 세션ID 매칭을 확인
JWT - 서버에서 정보의 위조만 검사한다.
쿠키와 세션
로그인 유지를 위해선 세션과 쿠키를 활용해야 한다.
하지만 HTTP는 기본적으로 stateless하다.
Stateful
채팅과 같이 지속적으로 연결되어있는 상태를 stateful (지속적 연결)이라고 하고,
HTTP에서 이러한 stateful과 같은 효과를 주는 것이 쿠키와 세션
기존에는 쿠키만 사용했는데, 로그아웃을 안 하면 브라우저가 종료돼도 남아있기 때문에 문제가 되었다.
세션을 도입하여 브라우저가 종료되면 자동 로그아웃되게 했다. (기간 지정 가능)
서버에 중요 데이터를 보관하는 것이 보안적으로도 우수
{세션 ID : Session}으로 서버에 저장하고, 쿠키에 세션 ID를 담아서 브라우저에게 응답
브라우저는 다음부터 쿠키와 함께 서버에 요청.
서버는 쿠키를 열어보고 세션 ID를 확인, 매칭 되는 Session을 사용한다.
톰캣의 SESSION 구조
{ 세션Id : {key : value} }
한번 더 감싸 져 있기 때문에 key:value는 여러 개가 가능하다. 여러 값을 저장할 수 있다.
JSESSION은 쿠키 이름 (세션 ID를 갖고 있다.)
세션id |
KEY |
VALUE |
BK291823LAK |
USERNAME |
CHA |
92J1K20D892 |
USERNAME |
PARK |
FKDJ209DJF3 |
USERNAME |
SOO |
F92JD93H1KD |
USERNAME |
MYOUNG |
서버상에서는 세션 ID로 이미 분리된 상태이기 때문에, KEY가 똑같아도 전부 구분된다.
JWT
Http 헤더에 JSON 토큰을 넣은 후 서버는 헤더에 포함되어 있는 JWT 정보를 통해 인증.
서버는 유저 정보를 갖고 있지 않고, 비밀키만 갖고 있기 때문에 부담이 적다. (stateless)
세 부분으로 구성
(1) Header
토큰 유형: JWT
암호방식: (HS256 또는 RSA)
(2) Payload (Map 형태)
유저 정보,
만료 시간
(3) Signature
해시알고리즘(
Header +
Payload +
Secret key
) = 시그니처 값
주의점
기본적으로 토큰은 공개되어지면 안된다. (HTTPS)
토큰으로 악용할 가능성이 있다.
JWT의 중점은 위변조 관점, 탈취될 가능성이 있으므로 시간 제한이 있는 Access Token 사용
(1)Header, (2)Payload 는 암호화가 아니다. (Base 64 encoder)
인가에 사용되는 부분은 (3)Signature
HTTPS덕에 정보를 보긴 어렵다.
그래도 중요한 정보는 저장하지 말자. (비밀번호가 있다면 토큰이 만료되도 접근할 가능성 존재)
인증 방식
Header + Payload + SecretKey가 (3) Signature이 나오나 확인한다.
인증 흐름
(1) + (2) + Secret key 이용해 해시 암호화해서 Signature를 만들고, 유저에게 전달한다.
토큰이 다시 왔을 때는 (1) + (2)와 서버의 Secret Key로 Signature를 만들어 본다.
유저가 보내온 Signature 값과 같은지 확인한다.
일치한다면 서버에서 만들어낸 토큰이고, 위조가 없는 것이니 사용한다.
- 유저는 Secret Key를 모르기 때문에 Payload를 위조해도 서버와 일치하는 Signature를 만들 수 없다.
- JWT의 인가 과정은 서버에서 만든 토큰이 맞는지, 데이터가 위조되지 않았는지를 확인하는 것이다.
RSA를 사용하면,
Header + Payload를 개인 키로 암호화하여 Signature를 생성, 토큰을 유저에게 준다.
유저가 다시 서버에게 토큰을 주면, 서버는 공개 키로 Signature를 복호화를 한다.
복호화된 Signature(Header + Payload)를 전달받은 Header, Payload와 일치하는지 확인한다.
두 값이 일치하면 서버의 개인 키로 서명한 위조가 안된 토큰이 맞다.
- 유저는 개인 키를 모르므로 Header, Payload가 일치하는 암호화 Signature를 만들 수 없다.
Refresh Token, Access Token
로그인 시 JWT 토큰을 두개를 생성해서 사용자에게 주는 방식EXP 기간이 다르기 때문에 해시 값은 완전히 다르다.
기존에는 Access Token만 사용
- 토큰은 유효 시간이 짧으면 재 로그인으로 불편하고, 유효 시간이 길면 탈취의 위험이 있다.
- 토큰 요청시마다 새로 발급하면, 서버에 부담을 준다.
Refresh Token을 추가로 사용
- Refresh Token은 유효기간이 길다. Access Token 만료 시 새로운 Access Token의 발급으로 사용된다.
- 클라이언트는 브라우저 스토리지에 저장한다.
서버에서는 Access Token이 만료된 것이 확인되면,
Refresh Token을 달라고 응답을 내려준다.
클라이언트는 Access Token이 만료되면 Refresh Token도 같이 줘야 한다.
두개의 Token을 전부 갖고 있음을 증명해야하기 때문.
Refresh Token이 만료되지 않았다면, Access Token을 재발급해준다.
둘다 만료라면 재로그인 필요.
Spring Security
JWT
권한 관리가 필요없다면 SecurityContext에 Authentication 객체를 안넣어도 된다.
Security Context에 Authentication을 넣는 이유는, 스프링 시큐리티의 권한 관리 사용을 위해
인증 시 DB 접근 -> 토큰 생성 -> 토큰 반환
인가 시 토큰 검증 -> 토큰 Signature 정상 -> Security Context에 Authentication 객체 담는다.
세션
세션 안에 있는 Security Context에서 꺼내와서 SecurityContextHolder에 담는다.
https://www.inflearn.com/questions/558844