서버 인증
정리 원본 링크 : 쉽게 알아보는 서버 인증 1편
인증이 필요한 이유
- 사용자 A와 사용자 B가 앱을 사용한다고 가정했을 때, 두 사용자는 기본적으로 정보가 다르고 보유하고 있는 컨텐츠도 다름
- 따라서 서버에서는 A와 B가 요청을 보냈을 때 누구의 요청인지를 정확히 알아야 함
- 만일 그렇지 못한다면, 사용자의 정보가 타인에게 유출되는 최악의 상황이 발생
- 그렇기에 앱(프론트엔드)에서는 자신이 누구인지를 알만한 단서를 서버에 보내야 하며, 서버는 그 단서를 파악해 각 요청에 맞는 데이터를 뿌려줘야 함
HTTP 요청
- 현재 모바일이나 웹 서비스에서 가장 많이 쓰이는 통신 방식은 HTTP 통신
- HTTP 통신은 응답 후 연결을 끊게 되며 과거에 대한 정보를 전혀 담고 있지 않음
- 이 말은 지금 보낼 HTTP 요청은 지난 번에 내 정보를 담아 보냈던 HTTP 요청과 전혀 관계가 없다는 뜻
- 따라서 각각의 HTTP 요청에는 주체가 누구인지에 대한 정보가 필수적
- 서버에 요청을 보내는 작업은 HTTP 메세지를 보내는 것
- HTTP 메세지의 구조는 일반적으로 헤더와 바디 두가지로 구성되며, 공백은 헤더와 바디를 구분짓는 역할을 함
- 여기서 헤더에는 기본적으로 요청에 대한 정보들이 들어가며, 바디에는 서버로 보내야할 데이터가 들어가게 됨
- 보통 모바일•웹 서비스의 인증은 HTTP 메세지의 헤더에 인증 수단을 넣어 요청을 보내게 됨
Tip! HTTP의 특징
- 클라이언트 서버 구조
- 클라이언트가 서버에 요청을 보내면 서버는 그에 대한 응답을 보내는 클라이언트 서버 구조
- 무상태 프로토콜 (Stateless)
- HTTP에서 서버가 클라이언트의 상태를 보존하지 않는 무상태 프로토콜
- 비 연결성 (Connectionless)
- HTTP 1.0 기준으로 HTTP는 연결을 유지하지 않는 모델
인증 방식
1. 계정 정보를 요청 헤더에 넣는 방식
- 가장 보안이 낮은 방식은 계정 정보를 요청에 담아 보내는 방식
- 위에서 언급한 HTTP 요청에 인증할 수단에 비밀번호를 넣는 방법
- 최악의 인증방식
- 데이터를 요청할 때마다 사용자의 프라이빗한 정보를 계속해서 보낸다는 건 보안에 상당히 좋지 않음
- 보통 앱에서는 서버로 HTTP 요청을 할 때 따로 암호화되지 않기 때문에 해커가 마음만 먹으면 HTTP 요청을 가로채서 사용자의 계정 정보를 알 수 있음
- 본 방식은 절대로 실제 서비스에서는 쓰이지 않음
- HTTP 요청을 암호화해서 보안을 높이는 방식으로 HTTPS가 있지만 그렇다고 해도 쓰이지 않음
- 단점
- ❶ 보안에 매우 취약
- ❷ 서버에서는 신호가 올 때마다 ID와 PW를 통해 유저가 맞는지 인증해야 하는데 이는 비효율적
2. 세션(Session) 쿠키(Cookie) 방식
- 계정 정보를 매번 요청에 넣어서 보내기엔 보안에 너무 취약하기 때문에 나온 인증 방법이 세션 쿠키 방식
- 순서
- ① 사용자가 로그인 함
- ② 서버에서는 계정 정보를 읽어 사용자를 확인한 후, 사용자의 고유한 ID값을 부여하여 세션 저장소에 저장하고 이와 연결되는 세션 ID를 발행
- ③ 사용자는 서버에서 해당 세션 ID를 받아 쿠키에 저장을 한 후, 인증이 필요한 요청마다 쿠키를 헤더에 실어 보냄
- ④ 서버에서는 쿠키를 받아 세션 저장소에서 대조를 한 후 대응되는 정보를 가져옴
- ⑤ 인증이 완료되고 서버는 사용자에 맞는 데이터를 보내줌
- 세션 쿠키 방식의 인증은 기본적으로 세션 저장소를 필요로 함
- 세션 저장소는 로그인을 했을 때 사용자의 정보를 저장하고 열쇠가 되는 세션 ID값을 생성하고 HTTP 헤더에 실어 사용자에게 돌려보냄
- 그러면 사용자는 받은 세션 ID값을 쿠키에 보관하고 있다가 인증이 필요한 요청에 쿠키를 넣어 보냄
- 웹 서버에서는 세션 저장소를 통해 받은 쿠키의 세션 ID값과 저장되어 있는 정보를 매칭시켜 인증을 완료
Tip!
- 세션 ID를 쿠키라고 봐도 동일
- 쿠키가 사용자 개념에서 더 큰 범주
- 세션 ID를 쿠키로 저장하는 셈
Tip!
- 세션은 서버에서 가지고 있는 정보이며 쿠키는 사용자에게 발급된 세션을 열기 위한 열쇠(세션 ID)를 의미
- 쿠키만으로 인증을 한다는 것은 서버의 자원은 사용하지 않는다는 뜻으로, 이 때는 클라이언트가 인증 정보를 책임지게 됨
- 그렇게 되면 위의 첫번째 방식처럼 HTTP 요청을 탈취당할 경우 다 털리게 됨
- 따라서 보안과는 상관 없는 단순한 장바구니나 자동 로그인 설정 같은 경우에만 쓰이고 있음
- 결과적으로 인증의 책임을 서버가 지도록 하기 위해 세션을 사용
- 사용자가 해킹당하는 것보단 서버가 해킹당하는게 훨씬 어렵기 때문
- 사용자(클라이언트)는 쿠키를 이용하고 서버에서는 쿠키를 받아 세션의 정보를 접근하는 방식으로 인증을 함
- 장점
- ❶ 세션 쿠키 방식은 기본적으로 쿠키를 매개로 인증을 거치는데 여기서 쿠키는 세션 저장소에 담긴 유저 정보를 얻기 위한 열쇠라고 보면 됨
- 따라서 쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 쿠키 자체(세션 ID)는 유의미한 값을 갖고 있지 않기 때문에 이는 위의 계정정보를 담아 인증을 거치는 것보단 안전
- 중요 정보는 서버 세션에 존재
- ❷ 사용자들은 각각 고유한 ID값을 발급받게 되는데 그렇게 되면 서버에서는 쿠키 값을 받았을 때 일일이 회원 정보를 확인할 필요 없이 바로 어떤 회원인지를 확인할 수 있어 서버의 자원에 접근하기 용이함
- 단점
- ❶ 쿠키를 탈취당하더라도 안전할 수 있다고 언급했지만 문제는 존재
- 만일 A 사용자의 HTTP 요청을 B 사용자(해커)가 가로챘다면 그 안에 들어있는 쿠키도 충분히 훔칠 수 있으며, B 사용자가 그 훔친 쿠키를 이용해 HTTP 요청을 보내면 서버의 세션 저장소에서는 A 사용자로 오인해 정보를 잘못 뿌려주게 됨
- 세션 하이재킹 공격이라고 함
- ❶ 해결책
- HTTPS를 사용해 요청 자체를 탈취해도 안의 정보를 읽기 어렵도록 만듬
- 세션에 유효시간을 넣어줌
- ❷ 서버에서 세션 저장소를 사용하기 때문에 추가적인 저장 공간을 필요로 하게 되고 자연스럽게 서버의 부하도 높아짐
3. 토큰 기반 인증 방식 (JWT)
- JWT는 세션 쿠키 방식과 함께 모바일과 웹의 인증을 책임지는 대표 주자
- JWT는 Json Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 뜻함
- 위의 세션 쿠키 방식과 유사하게 사용자는
Access Token
(JWT 토큰)을 HTTP 헤더에 실어 서버로 보내게 됨
- JWT 토큰을 만들기 위해서는
Header
, Payload
, Verify Signature
크게 3가지가 필요
Header
: 정보를 암호화할 방식(alg
), 타입(type
) 등이 들어감
Payload
: 서버에서 보낼 데이터가 들어가며 일반적으로 유저의 고유 ID값, 유효 기간이 들어감
Verify Signature
: Base64 방식으로 인코딩한 Header
, payload
그리고 SECRET KEY
를 더한 후 서명됨
- 최종적인 결과 :
Encoded Header
+ "." + Encoded Payload
+ "." + Verify Signature
Header
, Payload
는 16진수로 인코딩될 뿐 따로 암호화되지 않기 때문에 JWT 토큰에서 Header
, Payload
는 누구나 디코딩하여 확인할 수 있음
- 누구나 디코딩할 수 있다는 말은
Payload
에 유저의 중요한 정보가 들어가면 쉽게 노출될 수 있다는 말이 됨
- 하지만
Verify Signature
는 SECRET KEY
를 알지 못하면 복호화할 수 없음
- A 사용자가 토큰을 조작하여 B 사용자의 데이터를 훔쳐보고 싶다고 가정했을 때
Payload
에 있던 A의 ID를 B의 ID로 바꿔서 다시 인코딩한 후 토큰을 서버로 보냄
- 서버는 암호화된
Verify Signature
를 검사함
- 여기서
Payload
는 B 사용자의 정보가 들어가 있으나 Verify Signature
는 A의 Payload
를 기반으로 암호화되었기 때문에 유효하지 않는 토큰으로 간주하게 됨
- 여기서 A 사용자는
SECRET KEY
를 알지 못하는 이상 토큰을 조작할 수 없다는 걸 확인할 수 있음
- 순서
- ① 사용자가 로그인 함
- ② 서버에서는 계정 정보를 읽어 사용자를 확인 후, 사용자의 고유한 ID값을 부여하여 기타 정보와 함께
Payload
에 넣음
- ③ JWT 토큰의 유효 기간을 설정
- ④ 암호화할
SECRET KEY
를 이용해 Access Token
을 발급
- ⑤ 사용자는
Access Token
을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 실어 보냄
- ⑥ 서버에서는 해당 토큰의
Verify Signature
를 SECRET KEY
로 복호화한 후, 조작 여부와 유효기간을 확인
- ⑦ 검증이 완료되면
Payload
를 디코딩하여 사용자의 ID에 맞는 데이터를 가져옴
- 세션 쿠키 방식과 가장 큰 차이점은 세션 쿠키 방식은 세션 저장소에 유저의 정보를 넣는 반면, JWT는 토큰 안에 유저의 정보를 넣는다는 점
- 물론 클라이언트 입장에서는 HTTP 헤더에 세션 ID 또는 토큰을 실어서 보내준다는 점에서는 동일하나, 서버 측에서는 인증을 위해 암호화를 하는 점과 별도의 저장소를 이용한다는 점에서 차이가 발생
- 장점
- ❶ 간편함
- 세션 쿠키 방식은 별도의 저장소의 관리가 필요하지만 JWT는 발급한 후 검증만 하면 되기 때문에 추가 저장소가 필요 없음
- 이는 Stateless한 서버를 만드는 입장에서는 큰 강점
- 여기서 Stateless는 어떠한 별도의 저장소도 사용하지 않는, 즉 상태를 저장하지 않는 것을 의미하므로 이는 서버를 확장하거나 유지 보수하는데 유리
- ❷ 확장성이 뛰어남
- 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능
- 예를 들어 Facebook 로그인, Google 로그인 등은 모두 토큰을 기반으로 인증을 하기 때문에 이를 이용하여 선택적으로 이름이나 이메일 등을 받을 수 있는 권한도 받을 수 있음
- 단점
- ❶ 이미 발급된 JWT에 대해서는 돌이킬 수 없음
- 세션 쿠키 방식의 경우 만일 쿠키가 악의적으로 이용된다면 해당하는 세션을 지워버리면 됨
- 하지만 JWT는 한 번 발급되면 유효기간이 완료될 때 까지는 계속 사용이 가능하기 때문에 악의적인 사용자는 유효기간이 지나기 전까지 신나게 정보들을 털어갈 수 있음
- ❶ 해결책
- 기존의
Access Token
의 유효기간을 짧게 하고 Refresh Token
이라는 새로운 토큰을 발급
- 그렇게 되면
Access Token
을 탈취당해도 상대적으로 피해를 줄일 수 있음
- ❷
Payload
정보가 제한적
Payload
는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있음
- 반면 세션 쿠키 방식에서는 유저의 정보가 전부 서버의 저장소에 안전하게 보관됨
- 따라서 유저의 중요한 정보들은
Payload
에 넣을 수 없음
- ❸ JWT의 길이
- 세션 쿠키 방식에 비해 JWT의 길이는 길기 때문에 인증이 필요한 요청이 많아질 수록 서버의 자원 낭비가 발생하게 됨