STAGE 3 Cookie & Session
-Background: Cookie & Session
HTTP 프로토콜 특징
Connectionless : 하나의 요청에 하나의 응답을 한 후 연결을 종료하는 것을 의미
특정 요청에 대한 연결은 이후의 요청과 이어지지 않고 새 요청이 있을 때 마다 항상 새로운 연결을 맺는다.
Stateless : 통신이 끝난 후 상태 정보를 저장하지 않는 것을 의미
이전 연결에서 사용한 데이터를 다른 연결에서 요구할 수 없다.
클라이언트의 IP 주소와 User-Agent는 매번 변경될 수 있는 고유하지 않은 정보일 뿐만 아니라, Connectionless와 Stateless 특징 때문에 HTTP 웹 서버는 클라이언트를 기억할 수 없다.
쿠키(Cookie) : HTTP에서 상태를 유지하기 위해 사용하는 Key-Value 형태의 값
클라이언트의 정보 기록과 상태 정보를 표현하는 용도로 사용한다.
서버가 클라이언트에게 쿠키를 발급하면, 클라이언트는 서버에 요청을 보낼 때마다 쿠키를 같이 전송한다.
서버는 클라이언트의 요청에 포함된 쿠키를 확인해 클라이언트를 구분할 수 있다.
쿠키는 클라이언트의 브라우저에 저장되고 요청에 포함되는 정보이기 때문에 서버가 별다른 검증 없이 쿠키를 통해 이용자의 인증 정보를 식별한다면 공격자가 쿠키 정보를 변조, 타 이용자를 사칭해 정보를 탈취할 수 있다.
세션(Session) : 쿠키에 포함된 Session ID를 사용해 서버에 저장된 세션 데이터에 접근하는 방식
쿠키에 인증 상태를 저장하지만 클라이언트가 인증 정보를 변조할 수 없게 하기 위해 사용한다.
인증 정보를 서버에 저장하고 해당 데이터에 접근할 수 있는 키(유추할 수 없는 랜덤한 문자열-Session ID)를 만들어 클라이언트에 전달하는 방식으로 작동한다.
브라우저는 해당 키를 쿠키에 저장하고 이후에 HTTP 요청을 보낼 때 사용
서버는 요청에 포함된 키에 해당하는 데이터를 가져와 인증 상태를 확인
쿠키는 데이터 자체를 이용자가 저장하며, 세션은 서버가 저장한다.
쿠키 설정하는 방법
서버
HTTP 응답 중 헤더에 쿠키 설정 헤더 (Set-Cookie)를 추가하면 클라이언트의 브라우저가 쿠키를 설정
HTTP/1.1 200 OK
Server: Apache/2.4.29 (Ubuntu)
Set-Cookie: name=test;
Set-Cookie: age=30; Expires=Fri, 30 Sep 2022 14:54:50 GMT;
...
클라이언트
자바스크립트를 사용해 쿠키를 설정
document.cookie = "name=test;"
document.cookie = "age=30; Expires=Fri, 30 Sep 2022 14:54:50 GMT;"
클라이언트에서 쿠키를 다루는 방법
크롬 Console을 활용하는 법
크롬 페이지에서 우클릭했을 때 표시되는 검사 버튼을 누른 후 Console 탭을 누른다.
document.cookie를 입력하면 쿠키 정보를 확인할 수 있다.
쿠키 옵션(HttpOnly)에 따라 자바스크립트에서 쿠키 확인이 불가능 할 수 있다.
크롬 Application을 활용하는 법
크롬 페이지에서 우클릭했을 때 표시되는 검사 버튼을 누른 후 Application 탭을 누른다.
좌측에 나열된 목록에서 Cookies를 펼치면 Origin 목록을 확인할 수 있다.
Origin(https://dreamhack.io)을 누르면 설정 된 쿠키 정보를 확인 / 수정할 수 있다.
세션 하이재킹 (Session Hijacking) : 타 이용자의 쿠키를 훔쳐 인증 정보를 획득하는 공격
쿠키에는 이용자의 세션 정보가 저장되어 있고 서버는 이를 통해 이용자를 식별하고 인증을 처리한다.
공격자가 이용자의 쿠키를 훔칠 수 있으면 세션에 해당하는 이용자의 인증 상태를 훔칠 수 있다.
-Mitigation: Same Origin Policy
브라우저는 웹 리소스를 통해 간접적으로 타 사이트에 접근할 때도 인증 정보인 쿠키를 함께 전송하기 때문에 악의적인 페이지가 클라이언트의 권한을 이용해 대상 사이트에 HTTP 요청을 보내고, HTTP 응답 정보를 획득 하는 코드를 실행할 수 있다.
이는 정보 유출과 같은 보안 위협이 생길 수 있는 요소가 되기 때문에 클라이언트 입장에서는 가져온 데이터를 악의적인 페이지에서 읽을 수 없도록 해야 한다.
동일 출처 정책 (Same Origin Policy, SOP) : 현재 페이지의 출처가 아닌 다른 출처로부터 온 데이터를 읽지 못하게 하는 브라우저의 보안 메커니즘
Same Origin Policy의 오리진 (Origin) 구분 방법
오리진 (Origin) : 브라우저가 가져온 정보의 출처
프로토콜 (Protocol, Scheme), 포트 (Port), 호스트 (Host) 로 구성
구성 요소가 모두 일치해야 동일한 오리진
https://same-origin.com/라는 오리진과 아래 URL을 비교했을 때 결과
SOP는 Cross Origin이 아닌 Same Origin일 때만 정보를 읽을 수 있도록 해준다.
*Same Origin: 현재 페이지와 동일한 출처
*Cross Origin: 현재 페이지와 다른 출처
웹 서비스에서 동일 출처 정책인 SOP를 완화하여 다른 출처의 데이터를 처리 해야 하는 경우
특정 포털 사이트가 카페, 블로그, 메일 서비스를 아래의 주소로 운영하고 있을 때,
각 서비스의 Host가 다르기 때문에 브라우저는 각 사이트의 오리진이 다르다고 인식
블로그: https://blog.dreamhack.io
이러한 환경에서 이용자가 수신한 메일의 개수를 메인 페이지에 출력하려면, 개발자는 메인 페이지에서 메일 서비스에 관련된 리소스를 요청해야 한다. 이 때, 두 사이트는 오리진이 다르므로 SOP를 적용받지 않고 리소스를 공유할 방법이 필요하다.
교차 출처 리소스 공유 (Cross Origin Resource Sharing, CORS) : SOP의 제한을 받지 않고 Cross Origin의 데이터를 처리 할 수 있도록 해주는 메커니즘
교차 출처의 자원을 공유하는 방법은 CORS와 관련된 HTTP 헤더를 추가하여 전송하는 방법을 사용한다.
발신측에서 CORS 헤더를 설정해 요청하면, 수신측에서 헤더를 구분해 정해진 규칙에 맞게 데이터를 가져갈 수 있도록 설정한다.
웹 리소스 요청 코드
/*
XMLHttpRequest 객체를 생성합니다.
XMLHttpRequest는 웹 브라우저와 웹 서버 간에 데이터 전송을
도와주는 객체 입니다. 이를 통해 HTTP 요청을 보낼 수 있습니다.
*/
xhr = new XMLHttpRequest();
/* https://theori.io/whoami 페이지에 POST 요청을 보내도록 합니다. */
xhr.open('POST', 'https://theori.io/whoami');
/* HTTP 요청을 보낼 때, 쿠키 정보도 함께 사용하도록 해줍니다. */
xhr.withCredentials = true;
/* HTTP Body를 JSON 형태로 보낼 것이라고 수신측에 알려줍니다. */
xhr.setRequestHeader('Content-Type', 'application/json');
/* xhr 객체를 통해 HTTP 요청을 실행합니다. */
xhr.send("{'data':'WhoAmI'}");
발신측의 HTTP 요청
OPTIONS /whoami HTTP/1.1
Host: theori.io
Connection: keep-alive
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: https://dreamhack.io
Accept: */*
Referer: https://dreamhack.io/
발신측에서 POST 방식으로 HTTP 요청을 보냈으나, OPTIONS 메소드를 가진 HTTP 요청이 전달된 것을 확인할 수 있다. 이를 CORS preflight라고 하며, 수신측에 웹 리소스를 요청해도 되는지 질의하는 과정이다.
"Access-Control-Request"로 시작하는 헤더 뒤에 따라오는 Method와 Headers는 각각 메소드와 헤더를 추가적으로 사용할 수 있는지 질의
서버의 응답
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://dreamhack.io
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type
위처럼 질의하면 서버는 이와 같이 응답한다.
위 과정을 마치면 브라우저는 수신측의 응답이 발신측의 요청과 상응하는지 확인하고, 그때야 비로소 POST 요청을 보내 수신측의 웹 리소스를 요청하는 HTTP 요청을 보낸다.
'빡공팟(P4C)' 카테고리의 다른 글
웹해킹트랙 4주차 과제 - 드림핵 웹해킹1 #SQL Injection (0) | 2022.10.19 |
---|---|
웹해킹트랙 4주차 과제 - 드림핵 웹해킹1 #Cross-Site-Request-Forgery(CSRF) (0) | 2022.10.19 |
웹해킹트랙 4주차 과제 - 드림핵 웹해킹1 #Cross-Site-Scripting(XSS) (0) | 2022.10.19 |
웹해킹트랙 4주차 과제 - 드림핵 웹해킹1 #Background - Web (0) | 2022.10.19 |
웹해킹트랙 1~3주차 과제 - 코드업 파이썬 기초 100제 (0) | 2022.10.09 |