🤔로그인 인증 왜 하는 거지?
맨 처음 로그인 기능을 구현했었을 때 단순히 사용자가 정보를 입력하고 이를 서버에서만 확인하는 것이라고만 생각했었다. 하지만 프론트 개발을 점차 공부하면서 어떻게 사용자 세션을 유지할 것인지가 중요하다는 것을 알았다. 왜냐 HTTP 통신으로 요청하면 응답이 한 후 종료되는 stateless 특징때문에 연결이 끊어어지므로 누가 로그인 중인지를 기억해야 하기 때문이다. 개발 공부 초반에 정리하지 못했던 이 방식들에 대해 정리하고자 한다.
- Cookie
- Session
- JWT (Access Token + Refresh Token)
- OAuth 2.0
1. Cookie
- Key/Value 쌍으로 이루어진 문자열.
- 사용자 브라우저에 저장.
- 4KB 이하의 한정적인 저장 공간으로 용량이 제한됨.
- 브라우저마다 쿠키 지원 형태가 달라 브라우저간 공유가 불가능.
- 보안에 취약하다는 단점(요청시 쿠키의 값을 그대로 보내기 때문).
- httpOnly flag로 클라이언트 단에서의 접근으로부터는 보호 가능.
- 요청마다 쿠키를 담아 보내므로 쿠키 사이즈가 커지면 네트워크 부하가 심해짐.
📍 쿠키 인증 방식
- 맨 처음에 클라이언트는 쿠키없이 요청을 보낸다.
- 서버는 이에 대한 응답을 할 때 클라이언트에 저장하고 싶은 정보를 응답 헤더의 Set-Cookie에 담는다.
- 이후 클라이언트는 요청을 보낼 때마다 요청 헤더의 Cookie에 저장된 쿠키를 담아 보낸다.
- 서버는 쿠키에 담긴 정보를 통해 클라인언트가 누군지 식별하거나 정보를 바탕으로 광고를 띄운다.
2. 세션
- Key/Value 쌍으로 이루어짐.
- 쿠키가 보안에 취약하기에 비밀번호같은 민감한 인증 정보를 브라우저가 아닌 서버 측에 저장하고 관리하는 것.
- 서버 메모리나 서버 로컬 파일 또는 데이터 베이스에 저장(세션 저장소에 저장, 추가적인 저장 공간이 필요).
- 사용자 식별자인 session id를 저장과 정보를 저장.
- 사용자가 많아지면 정보를 찾는 데이터 매칭에 오랜 시간이 걸리면서 부하가 가해짐.
- 쿠키에 session id를 저장.
- 위의 쿠키가 노출되더라도 session id가 개인정보를 가지지 않아 1번째 쿠키 인증보다는 안전하지만 해커가 세션 ID 자체를 탈취하여 위장하여 접근할 수 있다는 한계가 있다.(하이재킹 공격)
📍 세션 인증 방식
- 사용자가 로그인한다.
- 서버는 회원 확인 후 세션 저장소에 Session ID를 저장한다.
- 로그인에 대한 응답으로 Cookie에 Session ID를 담아 전달한다.
- 사용자가 요청할 때마다 Session ID가 담긴 Cookie와 함께 보낸다.
- 서버는 세션 저장소에 Session ID와 일치하는 지 확인한다.
- Session ID가 일치하면 응답을 보낸다.
3. JWT(JSON Web Token)란?
- 사용자를 인증하고 식별하기 위한 정보들을 암호화시킨 토큰.
- JSON 데이터를 URL로 이용할 수 있는 문자(Base64 URL-safe Encode)로 인코딩하여 직렬화한 것.
- 전자 서명도 있어 JSON의 변조를 체크할 수 있음.
- 쿠키를 통해 클라이언트에 저장.
- 단순히 HTTP 요청시 헤더에 토큰을 첨부하는 것만으로 데이터를 요청하고 응답을 받아올 수 있음.
- '.'을 기준으로 Header, Payload, Signature 나누어짐.
파트 | 설명 |
---|
Header | 토큰의 타입과 해시 암호화알고리즘 구성. 첫째는 토큰의 유형(JWT)를 나타내고 두번째는 HMAC, SHA256 or RSA와 같은 해시 알고리즘을 나타냄. |
Payload | 토큰에 담을 클레임 정보를 포함함. payload에 담는 정보의 한 조각을 클레임. 이는 name/value의 한 쌍으로 이루어짐. 토큰에는 여러 개의 클레임을 넣을 수 있음. 클레임 정보는 등록된 클레임, 공개 클레임, 비공개 클레임으로 세 종류가 있음. - iss (Issuer) : 토큰 발급자 - sub (Subject) : 토큰 제목, 토큰에서 사용자에 대한 식별값이 됨 - aud(Audience) : 토큰 대상자 - exp (Expiration Time) : 토큰 만료 시간 - nbf (Not Before) : 토큰 활성 날짜 (이 날짜 이전의 토큰은 활성화 되지 않음을 보장) - iat (Issued At) : 토큰 발급 시간 - ti (JWT Id) : JWT 토큰 식별자 (issuer가 여러명일 때 이를 구분하기 위한 값) |
Signature | secret key를 포함하여 암호화. signature는 사용자 정보를 기반으로 암호화되었기 때문에 해커가 payload 값을 변경하여 요청해도 유효하지 않은 토큰으로 인식한다. |
📍 JWT 인증 방식.
JWT는 Access Token만으로도 인증 방식을 구현할 수 있다. 하지만 한 번 발급되면 유효기간이 만료될 때까지 삭제를 할 수 없어 만료 전에 해커에게 정보가 털린다면 대처할 방법이 없다. 그렇다고 유효기간을 짧게 하면 자주 인증해야된 불편함이 생긴다. 이에 Refresh Token을 같이 발급하여 이 문제를 해결하고 있다.
- Refresh Token : Access Token보다 긴 유효기간을 가지고 Access Token이 만료됐을 때 새로 발급해주는 열쇠이다.
🧐 Refresh Token이 탈취될 수도 있지 않을까??
Access Token처럼 똑같이 탈취당할 때의 취약점이 있다. 하지만 다른 점이 있다면 매 요청마다 HTTP 통신으로 노출이되는 Access Token과 달리, Access Token이 만료됐을 경우에만 네트워크 통신으로 Refresh Token을 서버로 보내기 때문에 탈취될 위험이 적다는 보안의 이점이 있다.
- 진행 순서
- 사용자가 로그인한다.
- 서버는 회원 확인 후 서명된 JWT 생성하여 클라이언트에 응답한다.
이때 Access Token과 Refresh Token을 같이 전달한다.
- 사용자가 요청할 때마다 Access Token와 함께 보낸다.
- 서버에서 Access Token을 검증한다.
- 검증이 완료되면 응답을 보낸다.
- 🚨 Access Token 만료되었다.
- 사용자가 Access Token과 함께 데이터를 요청한다.
- 서버에서 Access Token이 만료된 것을 확인한다.
- 만료되었다는 것을 알려주는 응답을 보낸다.
- 사용자는 만료 응답을 받고 Access Token과 Refresh Token을 같이 담아 발급 요청을 보낸다.
- Refresh Token을 확인한 후 Access Token을 발급한다.
- Access Token과 함께 응답을 보낸다.
4. OAuth(Open Authorization)란?
- 별도의 회원가입 없이 외부 서비스에서도 인증을 가능하게 하고 해당 서비스의 API를 이용하게 해주는 프로토콜로 현재는 2.0.이다.
- 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준.
- OAuth는 여러 곳에 개인정보를 제공하고 싶지 않은 점으로 생긴 이유가 큼. 여러 곳에 제공하게 되면 피싱에 둔감해지고 무엇보다 안전하다는 보장이 없기 때문.
OAuth 1.0 vs 2.0?
- 기능의 단순화, 기능과 규모의 확장성 등을 지원하기 위해 만들어짐.
- 1.0는 만들어진 다음 표준이 된 반면 2.0은 처음부터 표준 프로세스로 만들어짐.
- https가 필수여서 간단해짐.
- 암호화는 https에 맡김.
- 1.0는 인증방식이 한 가지였지만 2는 다양한 인증방식을 지원.
- api서버에서 인증서버를 분리 할 수 있도록 해 놓았다.
| OAuth 1.0 | OAuth 2.0 |
---|
참여자 | 이용자, 소비자, 서비스 제공자 | 자원 소유자, 클라이언트, 권한 서버, 자원 서버 |
토큰 | 요청 토큰(Request Token), 접근 토큰(Access Token) | 접근 토큰(Access Token), 재발급 토큰(Refresh Token) |
유효기간 | 접근 토큰의 유효기간 없음 | 접근 토큰 유효기간 부여, 만료시 재발급 토큰 이용 |
클라이언트 | 웹 서비스 | 웹, 앱 등 |
OAuth 2.0에 대해 자세히 알아보자
- 자원 서버(Resource Server) : Client가 제어하고자 하는 자원 보유하고 있는 서버
- 자원 소유자(Resource Owner) : 자원의 소유자 (로그인하는 실제 사용자)
- 클라이언트(Client): 자원 서버에 접속해서 정보를 가져오고자 하는 클라이언트.(웹 어플리케이션)
- 권한 서버(Authorization Server) : 클라이언트가 자원 서버의 서비스를 이용할 수 있게 인증하고 토큰을 발생해주는 서버(인증 서버)
ex. 구글, 페이스북 등
- Access Token: 자원 서버에 자원을 요청할 수 있는 토큰
- Refresh Token : 권한 서버에 접근 토큰을 요청할 수 있는 토큰
📍 OAuth 인증 방식
먼저 클라이언트가 자원 서버를 이용하기 위해 사전 승인을 받아야한다. 보통 자원 서버 홈페이지에 도메인을 등록하면 된다. 등록 절차를 완료하면 자원 서버와 연결하기 위한 정보를 얻을 수 있다. 구글을 기준으로 살펴보면 클라이언트 ID와 클라이언트 보안 비밀번호를 알 수 있고 이를 통해 OAuth에 접근할 수 있다.
- 자원 소유자(사용자)가 구글 로그인을 요청한다.
- 클라이언트는 인증 서버에 로그인 페이지를 요청한다.
- 인증 서버가 로그인 페이지를 제공한다.
- 제공받은 로그인 페이지에 ID와 비밀번호를 입력한다.
- 입력받은 값으로 인증 서버에 요청한다.
- 인증 서버에 Authorization code를 발급한다.
- 이 code로 인증 서버에 Access Token를 요청한다.
- 인증 서버에서 Access Token을 발급해준다.
- 인증이 완료되었다.
- 자원 서버에 Access Token을 담아 데이터를 요청한다.
- Access Token을 검증 후 응답을 준다.
- 만일 Access Token이 만료됐거나 위조되었다면, Client는 Authorization Server에 Refresh Token을 보내 Access Token을 재발급 받습니다.
참고 자료
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/@gusdnr814/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%9D%B8%EC%A6%9D-4%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95
https://pronist.dev/143
https://showerbugs.github.io/2017-11-16/OAuth-%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C
https://tecoble.techcourse.co.kr/post/2021-07-10-understanding-oauth/
https://doqtqu.tistory.com/295
덕분에 좋은 내용 잘 보고 갑니다
감사합니다.