술담화 프로젝트에서 로그인 기능을 구현하며 로그인이 성공적으로 이루어지는 것 이후에 사용자 세션을 유지할 것 또한 중요하다는 것을 알았다.
HTTP 통신으로 요청하면 응답이 한 후 종료되는 stateless 특징때문에 연결이 끊어어지므로 누가 로그인 중인지를 기억해야 하기 때문이다.
대표적 로그인 방식인 cookie, session, jwt에 대한 특징과 장단점에 대해 정리하려고 한다.
클라이언트는 쿠키없이 요청을 보낸다.
서버는 이에 대한 응답을 할 때 클라이언트에 저장하고 싶은 정보를 응답 헤더의 Set-Cookie에 담는다.
이후 클라이언트는 요청을 보낼 때마다 요청 헤더의 Cookie에 저장된 쿠키를 담아 보낸다.
서버는 쿠키에 담긴 정보를 통해 클라인언트가 누군지 식별하거나 정보를 바탕으로 광고를 띄운다.
Key/Value 쌍으로 이루어짐.
쿠키가 보안에 취약하기에 비밀번호같은 민감한 인증 정보를 브라우저가 아닌 서버 측에 저장하고 관리하는 것.
서버 메모리나 서버 로컬 파일 또는 데이터 베이스에 저장(세션 저장소에 저장, 추가적인 저장 공간이 필요).
사용자가 많아지면 정보를 찾는 데이터 매칭에 오랜 시간이 걸리면서 부하가 가해짐.
쿠키에 session id를 저장.
사용자당 고유 ID를 발급받게 되므로 그 ID값에 따라 회원 정보를 확인할 수 있다. 일일이 확인할 필요가 없어서 서버 자원 접근이 용이하다.
단점 : 위의 쿠키가 노출되더라도 session id가 개인정보를 가지지 않아 1번째 쿠키 인증보다는 안전하지만 해커가 세션 ID 자체를 탈취하여 위장하여 접근할 수 있다는 한계가 있다.(하이재킹 공격)
HTTPS를 사용하거나, 세션 유효시간을 지정하여 문제 해결
사용자 로그인
서버에서 계정 정보를 읽어 사용자를 확인한 후, 사용자의 고유한 ID값을 부여하여 세션 저장소에 저장. 그 후 이와 연결되는 세션 ID(쿠키) 발급한다.
사용자는 서버에서 2. 의 세션ID를 받아 쿠키에 저장한 후, 인증이 필요한 요청마다 쿠키를 헤더에 실어 보낸다.
서버에서 쿠키를 받아 세션 저장소의 그것과 대조한 후 대응되는 정보를 가져온다.
인증이 완료되고 서버는 사용자에 맞는 데이터를 보내줌
JWT를 만들기 위해 필요한 세 가지: Header, Payload, Verify Signature
사진 : https://velopert.com/2389
Header: Header, Payload, Verify Signature를 암호화할 방식(alg), 타입(typ) 등이 들어감
Payload: 서버에서 보낼 데이터가 들어감. 일반적으로 유저 별 고유 ID값, 유효기간이 들어감
Verify Signature: Base64 방식으로 인코딩한 Header, Payload 그리고 SECRET KEY를 더한 후 서명됨
📍 최종적인 결과로 Encoded Header + "." + Encoded Payload + "." + Verify Signature의 형태가 된다. (위 그림)
Header와 Payload는 따로 암호화되지 않고 인코딩만 되기 때문에, 누구나 디코딩을 할 수 있다. 이는 즉 데이터가 들어가는 Payload에 비밀번호와 같은 중요 정보가 들어갈 경우 쉽게 노출될 수 있다는 뜻과 같다.
📍 그러나 Verify Signature은 SECRET KEY를 알지 못하면 복호화할 수 없다.
ex) 만약 A 사용자의 데이터에 대해 B가 이 토큰을 조작해서 정보를 캐낸다고 해 보자. 이 때에 조작을 한 B는 A의 Payload에서 ID를 자신의(B) ID로 바꾼 후 토큰을 서버로 보낸다. 이를 받은 서버는 Verify Signature 검사를 하게 되는데, 이 때 Verify Signature은 A 사용자의 Payload를 기반으로 암호화되었기 때문에, SECRET KEY를 알지 못하는 이상 토큰을 조작할 수 없게 된다. 이러한 방식으로 토큰의 조작을 방지할 수 있다.
3. 장점
1) 별도의 세션 저장소 관리를 필요로 하는 세션/쿠키 방식에 비해 간편하다. JWT는 발급 후 Verify Signature로 검증만 하면 되기 때문에 추가 저장소가 필요가 없다. 추가 저장소가 필요하지 않기 때문에, 유지 보수 및 서버 확장에 훨씬 유리하다. (상태를 따로 저장하지 않으므로)
2) 확장성이 뛰어나다. 토큰을 기반으로 인증을 하는 Google 로그인, Facebook 로그인 등 다른 인증 시스템에 접근이 가능하다. 이에 선택적으로 이름이나 이메일 등을 받을 수 있는 권한도 받을 수 있다.
4. 단점
1) 이미 발급된 JWT에 대해서는 돌이킬 수 없다. 세션/쿠키의 경우 악의적으로 활용될 경우 그냥 그 세션을 지워버리면 된다. 하지만, JWT의 경우 한 번 발급되면, 유효기간이 다 될 때까지 사용할 수 있다. 따라서, 악의적으로 활용될 경우 유효기간이 지나기 전까지 정보를 전부 제약 없이 가져갈 수 있는 것이다.
이는, 기존 Access Token의 유효기간을 짧게 하고, Refresh Token이라는 새로운 토큰을 발급함으로써 해결할 수 있다. 이렇게 될 경우 Access Token을 탈취당하더라도 상대적으로 피해를 줄일 수 있다. 이는 OAuth와 깊은 관련이 있다.
2) Payload의 정보가 제한적이다. Payload는 따로 암호화되지 않으므로 디코딩이 자유롭고, 디코딩을 할 경우 누구나 정보를 확인할 수 있다. 이는 유저의 정보가 전부 서버 저장소에 안전하게 보관되는 세션/쿠키 방식과 비교했을 때 크나큰 단점이다. 그래서, Payload에는 중요한 정보들을 넣을 수 없다.
3) JWT의 길이가 세션/쿠키 방식에 비해 길다. 그래서, 인증에 필요한 요청이 많아질수록 서버의 자원낭비가 발생한다.
사용자가 로그인을 한다.
서버에서 계정정보를 읽어 사용자를 확인한 후, 사용자의 고유한 ID값을 부여. 이후 기타 정보와 함께 Payload에 넣음
JWT 토큰의 유효기간을 설정
암호화할 SECRET KEY를 이용해 ACCESS TOKEN을 발급
사용자는 Access Token을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 실어서 보냄
서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후 조작 여부 및 유효기간을 확인
검증이 완료된다면 Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져옴
https://tansfil.tistory.com/58
https://velog.io/@dee0518/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D