Cross-Site Request and Its Problems
만약 한 사이트 내부에서 다른 사이트로 요청을 보낸다면 이를 cross site request라고 부른다.
예를 들어 페이스북이 아닌 사이트에서 페이스북이 포함된 링크를 눌러서 페이스북으로 요청이 가는 것

만약 example.com에서 요청을 보내면 브라우저는 example.com의 쿠키를 붙여서 요청을 보낸다.
만약 example.com 말고 다른 사이트로 요청해도 거기에도 브라우저가 쿠키를 붙일 것이다.
서버는 이러한 브라우저의 특성때문에 해당 요청이 same-site요청인지 cross-site요청인지 구분이 어렵다.
따라서 서버는 cross-site 요청을 정상적인 요청이라고 판단할수도 있다. → 이걸 CSRF라고 부른다.
CSRF
공격자는 cross-site request를 보낼 웹페이지를 만든다
공격자는 피해자가 위조 사이트에 접속하도록 한다
피해자는 공격할 웹사이트에 로그인하여 세션을 가지고 있어야한다.

http 메세지는 위와 같이 생겼다.
get 요청은 url속 쿼리 문에 데이터를 넣고, post요청은 body에 데이터를 넣는다.
CSRF에서 GET Request
www.bank32.com이 있고, 피해자는 이 은행어플에 로그인되어 있어 세션쿠키를 가지고 있는다

공격자가 이러한 위조된 요청을 만들고, 사용자가 이를 클릭해서 브라우저에서 이러한 요청을 보낸다면, 계좌번호 3220으로 500만원이 이체된다.
공격자는 저 코드를 자바스크립트 코드 내부에 삽입할 수 있다.
img 또는 iframe와 같은 HTML 태그 내부에 넣어서 get 요청을 보낼 수 있다.

ADD Friend 공격
목표 : 피해자의 계정에 자기를 친구로 추가
- 다른 사람 계정으로 자신을 친구추가함 → 이 때 Http 캡쳐를 함

1번 : 친구추가 url, 공격자는 자신의 번호가 42번임을 알 수 있다.
2번 : CSRF 방지 토큰 (여기서는 disable됨)
3번 : 쿠키, 이는 브라우저가 자동으로 붙여줌 → 웹페이지는 공격자가 보냈어도 피해자가 보낸걸로 착각
- 웹페이지 코드에 심어둠

악성 웹페이지 코드
이 이미지 태그는 get url 코드를 보낸다
이 때 이미지는 1픽셀이니까 사용자는 눈치채지 못한다. 공격자는 이 페이지를 만들어서 배포한다.
공격자는 악성 웹페이지를 피해자한테 보낸다. → 피해자가 이를 클릭하면 image 태그가 실행된다.
→ 피해자는 공격자를 친구추가한 것이 되어버린다
CSRF POST로 공격
post는 html Forms를 사용해서 공격한다.
유저가 submit 버튼을 클릭하면 post request가 실행된다.


이는 자바스크립트를 활용한 요청이다.
1번에서는 post를 전송하기 위한 폼을 만든다.
2번에서는 폼을 페이지에 넣는다. 이 때 폼은 hidden으로 선언되어 눈에 보이지 않는다.
3번에서는 이를 submit하고, 4번에서는 페이지가 동작하면 forge_post가 자동으로 실행되도록 한다.
상대방 프로필 바꾸기 공격
위와 마찬가지로 http를 캡쳐한다.

1번은 url, 2번은 쿠키,
3번은 csrf 방지토큰(여기서는 무효)
4번은 프로필 내부에 들어갈 내용, 5번은 모두에게 공개하도록 권한 설정, 6번은 피해자의 id이다.
이 id는 피해자의 프로필 페이지 소스를 통해서 얻었다.

자바스크립트 함수는 hidden form을 생성한다.
그리고 피해자의 페이지에서 폼이 자동으로 전송된다. → 피해자의 프로필이 변경된다.
CSRF의 근본적인 문제
서버가 요청이 같은 사이트에서 왔는지 다른 사이트에서 왔는지 구별을 할 수 없다.
브라우저도 이들이 다른지 모른다.
CSRF 해결법(Countmeasures)
Referer Header
요청 발생 주소 포함하는 http Header이다.
서버는 이걸로 원래 페이지에서 온건지 아닌지 판단할 수 있다.
하지만 이는 브라우징 히스토리가 노출됨으로 인한 개인정보 위험이 있음
Same-site Cookies
서버가 브라우저에게 same-site일때만 보내도록 설정할 수 있다.
samesite 속성에 따라 cross site에 보낼지 말지 정해진다.

Secret Token
서버가 각 웹페이지마다 랜덤한 값들을 넣어둔다
만약 이 페이지에서 요청이 가면 이 값은 요청에 포함된다.
그러면 서버는 이게 cross-site요청인지 판단한다
다른 도메인을 가진 페이지는 이 secret value를 모른다.
→ 이 값은 브라우저가 관리하는게 아니라 웹페이지 내 코드가 관리
이 때 이 토큰들은 HTTP 요청이 갈 때 그 안에 들어간다.

이 세션 아이디는 site secret value, timestamp, user session id, randomly generated session string에 의해서 만들어진다.
Bypassing Secret Token
secret token은 우회 가능하다
이 때 타겟 페이지는 X-FRAME-OPTIONS헤더를 설정하지 말아야한다.

헤더를 deny로 설정하면 iframe으로 아예 못뜨고
sameorigin으로 하면 같은 오리진에 해당되는 것만 iframe으로 뜰 수 있다.

일단 해당 페이지에 secret 토큰 부분은 비워서 보낸다.(이 때 응답으로 원래 페이지를 얻을 수 있음)
그럼 이 때 유효하지 않은 토큰입니다와 같은 경고창이 뜨면서 원래 페이지가 함께 랜더링 된다.
그럼 이 피해 페이지는 투명하게 프레임에 뜨게 되어, 유저가 이를 클릭하면 공격에 성공하게된다.
JSON 처리하기

이런 json 타입은 AJAX가 필요하다. 이 때 브라우저가 cors를 체크한다.
이를 방지하기 위해 json 말고 plain이나 form형태를 사용할수도 있다.(얘내는 cors 체크 안함)
또한

이렇게 cors 설정이 잘못되어있는 경우도 고려해야한다.
만약 그렇다면 그냥 json으로 보내도 된다.
- Cross-site 요청 vs Same-site 요청
- 왜 cross-site 요청은 다르게 다뤄야 하는가
- CSRF 공격을 수행하는 방법
- CSRF 취약점의 근본적인 원인
- CSRF 공격을 막는 방법
'CSE > 네트워크 및 웹보안' 카테고리의 다른 글
[웹보안] 네트워크와 웹보안 (0) | 2025.04.28 |
---|