일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- MySQL
- Los
- 웹 해킹
- sql injection point
- CTF
- JS
- csrf
- sql injection
- php
- 로그인페이지
- file upload
- Python
- 세션
- 웹개발
- lord of sql injection
- Error based sql injection
- 게시판 만들기
- 로그인
- XSS
- css
- 보안 패치
- cookie 탈취
- 문제 풀이
- 과제
- union sql injection
- 모의해킹
- 보고서
- 증적 사진
- blind sql injection
- 웹 개발
- Today
- Total
Almon Dev
CSRF 보안 패치 본문
1. 개요
CSRF 이란?
CSRF(Cross-Site Request Forgery)는 사용자의 의도와는 무관하게 사용자의 권한으로 임의의 요청을 웹 애플리케이션에 전송하게 만드는 공격 기법입니다.
사용자가 로그인된 상태에서 악성 링크, 자동으로 폼을 전송하는 스크립트가 포함된 페이지(게시글, 이메일 등)를 방문하면, 해당 페이지는 사용자의 권한으로 원하지 않는 요청을 전송할 수 있습니다.
CSRF는 요청을 보낼 때, 사용자의 실제 의도인지 확인할 수 있는 일회성 인증(CSRF 토큰, CAPTCHA 등)이 없거나 검증 절차가 부족한 경우에 발생합니다. 이로 인해 서버는 공격자가 의도한 요청을 정상적인 사용자 요청으로 처리하게 됩니다.
CSRF 공격 흐름
1. 사용자가 로그인 상태로 웹 사이트에 접속해 있습니다.
2. 공격자가 악성 링크나, 폼을 자동으로 전송하는 스크립트가 포함된 페이지 등을 이용해 CSRF 공격 페이지로 접속하게 합니다.
3. 사용자가 해당 페이지에 접속하면 사용자의 권한을 이용해 공격자가 원하는 요청을 서버로 전송합니다.
4. 사용자의 권한으로 비밀번호 변경, 게시글 등록, 계정 탈퇴, 계좌 이체 등이 서버에서 처리될 수 있습니다.
보안 패치의 목적 및 중요성
사용자가 로그인 상태에서 악성 페이지를 방문하면, 공격자는 사용자의 권한을 이용해 중요한 요청(비밀번호 변경, 회원 탈퇴 등)을 수행할 수 있습니다.
이 취약점이 존재하는 경우, 공격자는 사용자 계정을 통해 개인 정보 탈취, 결제 요청, 비밀번호 변경 등 다양한 요청을 서버로 전송할 수 있습니다.
따라서 CSRF 취약점에 대한 보안 패치는 다음과 같은 목적을 가집니다.
1. 사용자 권한을 사칭한 비정상적인 요청을 차단합니다.
2. CSRF 토큰, Referer 체크 등을 통해 HTTP 요청의 출처를 검증합니다.
3. 정상적인 사용자 요청만 서버에서 처리되도록하여, 사용자 정보 보호 및 시스템의 무결성을 강화합니다.
2. 취약점 분석
CSRF 발생 원인
개인정보 변경 요청 시 CSRF 토큰, CAPTCHA 등의 확인 절차가 없어, 공격자가 사용자의 권한으로 요청을 위조할 수 있습니다.
mypage_update.php
....
<!-- 사용자가 의도한 요청이 맞는지 확인하는 일회설 인증(CSRF 토큰 등) 폼이 없습니다. -->
<form action="" class="mypage-form" enctype="multipart/form-data">
<p class="mypage-row update-mypage mypage profile">
<label for="profile_img">프로필 : </label>
<input type="file" id="profile_img_input" name="profile_img" style="display: none;" accept=".jpg, .png, .gif, .jpeg">
<img src="/upload/profile_img/<?=$img_path ?>" class="profile_img" id="profile_img" onclick="profileImgUpload()">
</p>
<p class="mypage-row update-mypage mypage name">
<label for="nickname">이름 : </label>
<input type="text" id="name" class="mypage update name" name="name" value=<?=$name?> required >
</p>
<p class="mypage-row update-mypage mypage nickname">
<label for="nickname">닉네임 : </label>
<input type="text" id="nickname" class="mypage update nickname" name="nickname" value=<?=$nickname?> required >
</p>
<p class="mypage-row update-mypage mypage email">
<label for="email">이메일 : </label>
<input type="email" id="email" class="mypage update email" name="email" value=<?=$email?> required>
</p>
<p class="mypage-row update-mypage mypage pass-btn">
<label for="pass">비밀번호 : </label>
<button id="pass" onclick="updatePass(event)">수정</button class="mypage update pass-btn">
</p>
<p class="mypage-row update-mypage mypage">
<button class="mypageset-btn on" onclick="updateSubmit(event)">수정완료</button>
</p>
</form>
....
mypage_update_proc.php
// 사용자가 의도한 요청이 맞는지 확인하는 절차가 없습니다.
if(isset($_POST['name']) or isset($_POST['email']) or isset($_POST['password']) or isset($_FILES['profile_img'])) {
if($token = Jwt_auth::auth()) {
....
$sql = "update users set";
$sql = $sql . " where user_id='$user_id'";
$result = runSQL($sql);
....
CSRF 예시
XSS 취약점이 존재할 경우, 공격자가 악성 스크립트를 통해 개인정보 변경 요청을 위조하여 사용자의 개인정보나 비밀번호를 임의로 변경할 수 있습니다.
1. 개인정보 수정 페이지로 이동합니다.
2. 프로필 이미지를 선택하고 변경 요청을 보냅니다.
3. 요청을 가로채서 파일 이름에 비밀번호를 설정한 input 태그를 삽입합니다.
4. 다시 개인정보 수정 페이지로 이동합니다.
5. 비밀번호를 설정하지 않고, 수정 요청을 보냅니다.
6. 프로필 이미지에 삽입한 HTML 태그로 인해 폼에 비밀번호 변경 input 태그가 삽입된 것을 확인합니다.
3. 보안 패치 적용
보안 조치 방법
사용자의 입력을 받는 form 태그에 랜덤하게 생성된 CSRF 토큰을 추가하고 서버에서 검증하는 것으로 CSRF 공격을 일부 방지할 수 있습니다.
PHP 예시)
// CSRF 토큰 생성
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// 토큰을 클라이언트로 전송하여 input 태그에 추가
echo json_encode(['csrf_token' => $_SESSION['csrf_token']]);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['csrf_token']) && $_POST['csrf_token'] === $_SESSION['csrf_token']) {
// CSRF 토큰 유효
echo "정상 처리 되었습니다.";
// CSRF 토큰 사용 후 삭제
unset($_SESSION['csrf_token']);
} else {
// CSRF 토큰 불일치 에러
echo "CSRF 공격 방지입니다.";
}
}
수정 코드
사용자가 요청 페이지(mypage_update.php)에 접속하면 서버는 CSRF 토큰을 생성하여 세션에 저장하고, 이를 HTML 폼 태그에 삽입합니다. 이후 사용자의 요청이 들어오면(mypage_update_proc.php), 서버는 요청에 포함된 CSRF 토큰과 세션에 저장된 토큰을 비교하여 일치한 경우에만 요청을 처리하도록 하였습니다.
mypage_update.php
<?php
session_set_cookie_params([
'lifetime' => 600,
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
session_start();
// CSRF 토큰 생성 및 세션에 저장
$csrf_token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $csrf_token;
?>
<form action="" class="mypage-form" enctype="multipart/form-data">
<!-- CSRF 토큰 삽입 -->
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<p class="mypage-row update-mypage mypage profile">
<label for="profile_img">프로필 : </label>
<input type="file" id="profile_img_input" name="profile_img" style="display: none;" accept=".jpg, .png, .gif, .jpeg">
<img src="/upload/profile_img/<?=$img_path ?>" class="profile_img" id="profile_img" onclick="profileImgUpload()">
</p>
<p class="mypage-row update-mypage mypage name">
<label for="nickname">이름 : </label>
<input type="text" id="name" class="mypage update name" name="name" value=<?=$name?> required >
</p>
<p class="mypage-row update-mypage mypage nickname">
<label for="nickname">닉네임 : </label>
<input type="text" id="nickname" class="mypage update nickname" name="nickname" value=<?=$nickname?> required >
</p>
<p class="mypage-row update-mypage mypage email">
<label for="email">이메일 : </label>
<input type="email" id="email" class="mypage update email" name="email" value=<?=$email?> required>
</p>
<p class="mypage-row update-mypage mypage pass-btn">
<label for="pass">비밀번호 : </label>
<button id="pass" onclick="updatePass(event)">수정</button class="mypage update pass-btn">
</p>
<p class="mypage-row update-mypage mypage">
<button class="mypageset-btn on" onclick="updateSubmit(event)">수정완료</button>
</p>
</form>
mypage_update_proc.php
// 사용자가 의도한 요청이 맞는지 확인하는 절차가 없습니다.
if(isset($_POST['name']) or isset($_POST['email']) or isset($_POST['password']) or isset($_FILES['profile_img'])) {
if($token = Jwt_auth::auth()) {
session_start();
$csrf_token = $_SESSION['csrf_token'];
$csrf_token_request = isset($_POST['csrf_token']) ? $_POST['csrf_token'] : 0;
// 클라이언트의 CSRF 토큰과, 세션의 CSRF 토큰 비교
if ($csrf_token !== $csrf_token_request) {
echo('사용자 요청 위조를 감지했습니다.');
header("Location: login2.php");
exit;
}
$user_id = $tok
....
$sql = "update users set";
$sql = $sql . " where user_id='$user_id'";
$result = runSQL($sql);
....
4. 보안 패치 결과
보안 패치 후 테스트
동일 페이지(mypage_update.php) 내에서 발생하는 XSS를 기반으로 테스트한 결과, 이번 CSRF 방지 패치만으로는 공격을 차단할 수 없었습니다. 해당 패치를 통해 CSRF를 방지하려 했으나, 동일 페이지의 XSS 취약점이 존재할 경우 CSRF 토큰이 노출되어 여전히 공격이 가능합니다.
다만, 지난번 패치를 통해 해당 페이지의 XSS 취약점은 이미 제거된 상태이므로, 현재는 CSRF 공격 역시 차단된 것으로 판단됩니다.
'웹 해킹 > 웹 개발' 카테고리의 다른 글
[Lord of SQL Injection] bugbear 문제 풀이 (1) | 2025.04.22 |
---|---|
불충분한 세션 만료 보안 패치 (0) | 2025.04.14 |
약한 문자열 강도 보안 패치 (0) | 2025.04.07 |
정보 누출 보안 패치 (0) | 2025.04.05 |
디렉터리 인덱싱 보안 패치 (0) | 2025.04.04 |