CSRF란?
Cross-Site Request Forgery의 약어로, 공격자에 의해 사용자가 의도하지 않은 요청을 수행하는 공격이다. 사용자 정보 수정, 패스워드 변경, 회원 탈퇴, 게시글 작성/수정/삭제 등의 행위가 가능하다.
공격 원리 분석
예시 1) 서버 1개
- 공격자가 악성 스크립트를 게시글에 작성해 둔다.
- 인증된 사용자가 해당 게시글을 읽으면 악성 스크립트에 의해 패스워드 변경 요청이 자동으로 발생한다. 이때 스크립트는 Client-Side Script로 구성되어 있다. 따라서 클라이언트가 웹 서비스에 패스워드 변경 요청을 하게 된다.
예시 2) 서버 2개
- 공격자는 사용자에게 A라는 사이트의 회원 탈퇴를 요청하는 악성 스크립트를 게시글에 작성해 둔다.
- 인증된 사용자가 해당 게시글을 읽으면 악성 스크립트에 의해 회원 탈퇴 요청이 자동으로 발생한다.
XSS vs CSRF
XSS는 악성 스크립트를 읽은 뒤 정상적인 서버로 요청하는 것이 아니라 공격자가 의도한 서버로 이동하고 이후 다시 사용자가 타겟이 된다. 반면 CSRF는 정상적인 서버로 사용자가 의도하지 않은 요청을 하게 한다.
XSS는 최종 공격 대상이 사용자인 반면, CSRF의 최종 공격 대상은 취약한 웹 서비스다.
대응 방안
1. Referer 값 검증
래퍼 헤더의 값(origin url 등)을 검증한다.
2. CSRF TOKEN 사용
폼 페이지에서 발급한 난수화된 임의의 값(토큰)을 액션 페이지로 전달한다. 액션 페이지에서는 전달받은 토큰의 유효성을 검증한다.
- 폼 페이지에서 토큰을 발급받는다.
- 세션과 파라미터(사용자 입력값)에 토큰을 입력한다.
- 액션 페이지에서 세션으로부터 추출한 토큰과 파라미터에서 추출한 토큰을 비교한다.
- 두 토큰이 같을 경우 유효성 검증에 성공한다.
3. 인증 로직 사용
개인정보 수정/삭제 전에 기존의 패스워드를 입력받아 인증하는 로직을 추가한다.
4. CAPCHA 사용
기계는 인식할 수 없으나 사람은 쉽게 인식할 수 있는 텍스트, 이미지를 통해 사람과 기계를 구별하는 CAPCHA를 사용한다. 이는 게시글 작성에 주로 사용된다.
5. SameSite Cookie
도메인이 다른 두 사이트 사이에 쿠키가 전송되지 않도록 한다.
취약 환경 시큐어 코딩 적용 실습
실습 1) 게시글 작성 / 수정 / 삭제 기능에 대한 시큐어 코딩 적용
1. CSRF TOKEN 발급 & 세션과 input 태그에 CSRF TOKEN 추가
function csrf_token_create() {
if (!empty($_SESSION["id"])) {
$time = time();
$id = $_SESSION["id"];
$csrf_token = sha1($id.$time);
$_SESSION["csrf_token"] = $csrf_token;
} else {
$csrf_token = "";
}
return $csrf_token;
}
$csrf_token = csrf_token_create();
<form action="action.php" method="POST" enctype="multipart/form-data">
<div class="text-right">
<input type="hidden" name="csrf_token" value="<?=$csrf_token?>">
<input type="hidden" name="mode" value="write">
<button type="submit" class="btn btn-outline-secondary">Write</button>
<button type="button" class="btn btn-outline-danger" onclick="history.back(-1);">Back</button>
</div>
</form>
2. 토큰 유효성 검증
# CSRF Token 검증 로직
$csrf_token_session = $_SESSION["csrf_token"];
$csrf_token_param = $_REQUEST["csrf_token"];
unset($_SESSION["csrf_token"]); // 토큰 폐기
if (empty($csrf_token_session) && empty($csrf_token_param)) {
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
} else {
if ($csrf_token_session != $csrf_token_param) { // 두 토큰이 일치하지 않을 경우
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
}
}
실습 2) 회원 수정 / 패스워드 / 탈퇴 기능에 대한 시큐어 코딩 적용
- 회원 수정 / 패스워드회원 수정
- 인증 로직을 추가한다.
- 페이지 접속 전에 기존의 패스워드를 통한 인증 로직이 먼저 수행되고, 인증에 성공할 경우 회원 정보 수정이 가능하도록 로직을 변경한다.
- 회원 탈퇴
- CSRF TOKEN을 사용한다.
# CSRF Token 검증 로직
$csrf_token_session = $_SESSION["csrf_token"];
$csrf_token_param = $_REQUEST["csrf_token"];
unset($_SESSION["csrf_token"]); // 토큰 폐기
if (empty($csrf_token_session) && empty($csrf_token_param)) {
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
} else {
if ($csrf_token_session != $csrf_token_param) { // 두 토큰이 일치하지 않을 경우
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
}
}
<form action="index.php?page=mypage&id=<?=$id?>" method="POST">
<input type="hidden" name="gubun" value="action">
<div class="text-center">
<input type="submit" class="btn btn-info" value="수정하기">
<button type="button" class="btn btn-danger" onclick="if(confirm('탈퇴 하시겠습니까?')) location.href='withdrawal.php?csrf_token=<?=$csrf_token?>'">회원탈퇴하기</button>
</div>
</form>
'Security > Web Hacking' 카테고리의 다른 글
[WebHacking] 파일 업로드 취약점 (1) | 2024.05.15 |
---|---|
[WebHacking] 파일 다운로드 취약점 (0) | 2024.05.15 |
[WebHacking] XSS 공격 (1) | 2024.04.28 |
[WebHacking] XXE Injection 공격 (0) | 2024.04.28 |
[WebHacking] OS Command Injection 공격 (0) | 2024.04.28 |