HTTP는 인터넷 상에서 데이터를 주고 받기 위한 서버/클라이언트 모델을 따르는 프로토콜이다.
비연결성,무상태성이라는 특징을 가지고 있는데 이것은 HTTP는 요청에 대한 응답을 처리하게 되면 연결을 끊어 버린다.
->이전의 상태 정보 및 현재의 통신 상태가 남아있지 않는다.
->불필요한 자원 낭비를 줄일 수 있다.(서버가 다수의 클라이언트와 연결을 계속 유지한다면 이에 따른 자원 낭비가 심해지기 때문에)
->쉽게 얘기하면 클라에서 서버에게 데이터 보내고 서버가 응답하면 클라이언트와 연결을 끊어버린다.
하지만 서버가 클라이언트를 식별할 수 없다는 단점 또한 존재한다. 로그인을 하더라도 다음 요청에서 해당 클라이언트를 기억하지 못해, 또 로그인을 해야하는 문제가 발생한다.(HTTP 요청은 지난 번에 내 정보를 담았던 HTTP 요청과 전혀 관계가 없다 -> 인증의 필요성) -> 즉 새로고침 할때마다 로그인????
서버에게 요청을 보내는 작업은 HTTP 메세지를 보내는 것이다.
일반적으로 헤더와 바디 두가지로 구성되며, 공백은 헤더와 바디를 구분짓는 역할을 한다.
헤더에는 기본적으로 요청에 대한 정보가 들어간다.
바디에는 서버로 보내야할 데이터가 들어간다.
보통 HTTP 메세지의 헤더에 인증 수단을 넣어 요청을 보낸다.
하지만 우리가 사용하고 있는 웹 사이트의 경우 한 번 로그인을 하면 다시 로그인할 필요 없이 여러 페이지를 돌아다니며 다양한 기능들을 이용할 수 있다. -> 브라우저를 껐다 켜도 로그인이 유지된다. -> Cookie와 Session 이라는 것 때문에
가장 보안이 낮은 방식이다. 즉 HTTP 요청에 인증할 수단에 비밀번호를 넣는다. 데이터를 요청할 때마다 사용자의 정보를 계속해서 보내는건 상당히 보안에 좋지 않다.
장점
-> 인증을 테스트 할 때 빠르게 시도해볼 수 있다.
단점
-> 보안에 매우 취약하다.
-> 서버에서는 신호가 올때마다 Id,Pw를 통해 유저가 맞는지 인증해야한다. (비효율적이다.)
쿠키란 클라이언트가 어떤 웹 사이트를 방문할 경우, 그 사이트가 사용하고 있는 서버를 통해 클라이언트의 브라우저에 설치되는 작은 기록 정보 파일이다.
MockHttpServletResponse:
Status = 200
Headers = [Set-Cookie:"userName=kevin", "password=abc123"]
1.서버는 클라이언트의 로그인 요청에 대한 응답을 작성할 때,클라이언트 측에 저장하고 싶은 정보를 응답 헤더의 Set-Cookie에 담는다.
->Cookie는 Key-Value 형식의 문자열이다.
MockHttpServletRequest:
HTTP Method = GET
Request URI = /user/my/edit
Headers = [Cookie:"userName=kevin"; "password=abc123"]
3.이후 해당 클라이언트는 요청을 보낼 때마다, 매번 저장된 쿠키를 요청 헤더의 Cookie에 담아 보낸다.
4.서버는 쿠키에 담긴 정보를 바탕으로 해당 요청의 클라이언트가 누군지 식별할 수 있다.
1.보안에 취약하다.
-> 요청 시 쿠키의 값을 그대로 보낸다.
-> 유출 및 조작 당할 위험이 존재한다.
2.쿠키에는 용량 제한이 있어 많은 정보를 담을 수 없다.
3.웹 브라우저마다 쿠키에 대한 지원 형태가 다르기 때문에 브라우저간 공유가 불가능하다.
4.쿠키의 사이즈가 커질수록 네트워크에 부하가 심해진다.
쿠키의 가장 큰 단점은 쿠키가 유출 및 조작 당할 위험이 존재한다는 것이다. 즉 개인 정보를 HTTP로 주고받는것은 (Headers로) 상당히 위험하다.
세션은 비밀번호 등 클라이언트의 정보를 쿠키가 아닌 서버측에서 저장하고 관리한다.
HTTP/1.1 200
Set-Cookie: JSESSIONID=FDB5E30BF20045E8A9AAFC788383680C;
서버는 클라이언트의 로그인 요청에 대한 응답을 작성할 때, 인증 정보는 서버에 저장하고 클라이언트 식별자인 JSESSIONID를 쿠키에 담는다.
이후 클라이언트는 요청을 보낼 때마다,JSESSIONID 쿠키를 함께 보낸다.
서버는 JSESSIONID 유효성을 판별해 클라이언트를 식별한다.
쿠키를 포함한 요청이 외부에 노출되더라도 세션 ID 자체는 유의미한 개인정보를 담고 있지 않는다. -> 해커가 탈취하여 클라이언트인척 위장 할 수 있다는 한계가 존재한다.
각 사용자마다 고유한 세션 ID가 발급되기 때문에,요청이 들어올 때마다 회원정보를 확인할 필요가 없다.
서버에서 세션 저장소를 사용하므로 요청이 많아지면 서버에 부하가 심해진다.
JWT(JSON WEB TOKEN)이란 인증에 필요한 정보들을 암호화시킨 토큰을 의미한다. JWT 기반 인증은 쿠키/세션 방식과 유사하게 JWT토큰(Access Token)을 HTTP헤더에 실어 서버가 클라이언트를 식별한다.
JWT는 .을 구분자로 나누어지는 세가지 문자열의 조합이다.
이것을 디코딩하면 아래와 같은 구조로 이루어진다.
Header
alg -> 암호화할 해싱 알고리즘
typ -> 토큰의 타입
Payload
토큰에 담을 정보를 지니고 있다.
주로 클라이언트의 고유 ID값 및 유효 기간 등이 포함된다.
key-value 형식으로 이루어진 한 쌍의 정보(Claim)
Signature
인코딩된 Header와 Payload를 더한 뒤 비밀키로 해싱하여 생성한다.
Header와 Payload는 단순히 인코딩된 값이기 때문에 제 3자가 복호화 및 조작할 수 있지만, Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없다.
->토큰의 위변조 여부를 확인하는데 사용한다.
{
Authorization: <type> <access-token>
1.클라이언트 로그인 요청이 들어오면 , 서버는 검증 후 클라이언트 고유 ID등의 정보를 Payload에 담는다.
2.암호화할 비밀키를 사용해 Access Token(JWT)를 발급한다.
3.클라이언트는 전달받은 토큰을 저장해두고, 서버에 요청할 때 마다 토큰을 요청 헤더(Authorization)에 포함시켜 함께 전달한다.
4.서버는 토큰의 Signature를 비밀키로 복호화하고, 위변조 여부 및 유효 기간 등을 확인한다.
5.유효한 토큰이라면 요청에 응답한다.
1.Header와 Payload를 가지고 Signature를 생성하므로 데이터 위변조를 막을 수 있다.
2.인증 정보에 대한 별도의 저장소가 필요없다.
3.JWT는 토큰에 대한 기본 정보와 전달할 정보 및 토큰이 검증됬음을 증명하는 서명 등 필요한 모든 정보를 자체적으로 지니고 있다.
4.클라이언트 인증 정보를 저장하는 세션과 다르게, 서버는 무상태가 된다.
5.확장성이 우수하다.
6.토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다.
7.OAuth의 경우 Facebook,Google 등 소셜 계정을 이용하여 다른 웹서비스에서도 로그인을 할 수 있다.
8.모바일 어플리케이션 환경에서도 잘 동작한다.
쿠키/세션과 다르게 JWT는 토큰의 길이가 길어,인증 요청이 많아질수록 네트워크 부하가 심해진다.
Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보는 담을 수 없다.
토큰을 탈취당하면 대처하기 어렵다.
토큰은 한 번 발급되면 유효기간이 만료될 때 까지 계속 사용이 가능하기 때문이다.
특정 사용자의 접속을 강제로 만료하기 어렵지만, 쿠키/세션 기반 인증은 서버 쪽에서 쉽게 세션을 삭제할 수 있다.
JWT 사용시 단점을 극복하기 위해 다양한 전략을 채택할 수 있다.
토큰의 만료 시간을 짧게 설정하는 방법
-> 토큰이 탈취되더라도 빠르게 만료된다.
-> 사용자가 자주 로그인 해야한다.
글을 작성하는 도중 토큰이 만료된다면 작업이 정상처리되지 않고 이전의 작업들이 날아갈 수 있다. Sliding Session은 서비스를 지속적으로 이용하는 클라이언트에게 자동으로 토큰 만료 기한을 늘려주는 방법이다. 글 작성 혹은 결제 등을 시작할 때 새로운 토큰을 발급해줄 수 있다. -> 사용자가 로그인을 자주 할 필요가 없어진다.
클라이언트가 로그인 요청을 보내면 서버는 Access Token 및 그보다 긴 만료 기간을 가진 Refresh Token을 발급하는 전략이다.
클라이언트는 Access Token이 만료 되었을 때 Refresh Token을 사용하여 Access Token의 재발급을 요청한다. 서버는 DB에 저장된 Refresh Token과 비교하여 유효한 경우 새로운 Access Token을 발급하고, 만료된 경우 사용자에게 로그인을 요구한다.
Access Token의 만료 기한을 짧게 설정할 수 있으며, 사용자가 자주 로그인할 필요가 없다. 또한 서버가 강제로 Refresh Token을 만료시킬 수 있다.
하지만 검정을 위해 서버는 Refresh Token을 별도의 storage에 저장해야 하기때문에 이는 추가적인 I/O 작업이 발생함을 의미한다.
-> JWT의 장점(I/O 작업이 필요 없는 빠른 인증 처리)을 완벽하게 누릴 수 없다.
-> 클라이언트도 탈취 방지를 위해 Refresh Token을 보안이 유지되는 공간에 저장해야 한다.
참고자료