CSRF 란?
인터넷 사용자(희생자)가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 만드는 공격입니다.
쿠키 + 세션
해커가 CSRF 공격을 시도하기 위해선 전제조건이 필요합니다.
쿠키 세션은 전제조건에 해당되므로 이 내용을 이해하면 후의 글을 이해하는데 도움이 될 것 입니다.
사용자가 특정 서버에 로그인하면 일반적으로 다음과 같은 작업들이 수행됩니다.
- 서버는 로그인 시 인증된 사용자의 정보를 세션(session)에 저장하고, 이를 찾을 수 있는 sessionID를 만듭니다.
- 서버는 전달된 세션 정보를 클라이언트(브라우저)가 사용할 수 있도록 sessionID를 Set-Cookie 헤더에 담아서 전달합니다.
- 클라이언트(브라우저)는 전달된 sessionID를 쿠키에 저장합니다.
- 클라이언트(브라우저)는 해당 도메인을 가진 서버로 요청 시 쿠키에 저장된 sessionID를 자동으로 전달합니다.
- 서버는 쿠키에 담긴 sessionID를 통해 인증된 사용자인지 여부를 확인합니다.
CSRF 의 전제 조건과 공격 시나리오
전제 조건
- 사용자가 보안이 취약한 서버로 부터 이미 인증을 받은 상태여야 합니다.
- 쿠키 기반으로 서버 세션 정보를 획득할 수 있어야 합니다.
- 공격자는 서버에 요청에 방법에 대해 파악하고 있어야합니다.
CSRF 공격 시나리오
- 사용자는 보안이 취약한 서버에 로그인 합니다.
- 로그인 이후 서버에 저장된 세션 정보를 사용할 수 있는 sessionID 가 사용자 브라우저 쿠키에 저장됩니다.
- 공격자는 서버에 인증된 브라우저의 사용자가 악성 스크립트 페이지를 누르도록 유도합니다.
- 게시글 또는 링크를 만들어 관리자 혹은 사용자가 클릭을 하도록 유도합니다.
- 메일 등으로 악성 스크립트를 직접 전달하거나, 악성 스크립트가 포함된 페이지의 링크를 전달합니다.
- 사용자가 악성 스크립트가 작성된 페이지에 접근시 쿠키에 저장된 sessionID 는 브라우저에 의해 자동적으로 서버에 요청됩니다.
- 서버는 쿠키에 담긴 sessionID 를 통해 해당 요청이 인증된 사용자로부터 온 것이라고 판단하고 처리합니다.
CSRF 공격 시연
1. 사용자가 보안이 취약한 서버에 로그인 합니다. 로그인 이후 sessionID가 쿠키에 저장됩니다.
2. 사용자가 악성 스크립트가 포함된 사이트에 접속합니다. 동시에 500원 이던 계좌의 잔액이 CSRF 공격으로 인해 줄어든 것을 확인할 수 있습니다.
접속만으로 CSRF 공격이 시도될 수 있습니다.. 무서ㅝ
3. 이번에는 링크를 클릭함으로써 공격이 이루어지는 것을 시연해보겠습니다. 매우 누르고 싶은 click me 라는 버튼이 있습니다.
현재 잔액은 487원 입니다.
클릭한 이후 잔액은 480원 으로 줄어듭니다.
CSRF 공격에 사용된 코드
한번 공격에 사용된 코드에 대해 살펴보겠습니다.
접속만으로 공격이 시도된 코드 1
이미지 태그의 src 에 공격을 요청하는 URL 을 작성함으로써 공격을 시도하게 됩니다.
<div><img src="http://localhost:3000/transfer?to=alice&amount=4"></div>
왜 저런 URL로 공격이 요청되는 걸까? 이해가 잘 안되시면 더보기 클릭. (CSRF 공격 아님. ㅋㅋ)
흔히 사용하는 Form 태그를 사용해봅시다.
<form action="http://localhost:3000">
<p>아이디: <input type="text" name="id" /></p>
<p>비밀번호: <input type="password" name="pwd" /></p>
<p>주소: <input type="text" name="address" /></p>
<input type="submit" />
</form>
다음 form 태그를 사용하여 submit 을 하게 되면 어떻게 될까요?
아래와 같이 URI에 데이터가 포함되여 요청이 보내지게 됩니다.
즉, 위 예제에선 서버의 /transfer 로 해당 정보가 날아가게 되므로 공격이 시도되게 되는 것입니다.
접속만으로 공격이 시도된 코드 2
<div>
<iframe src="/malicious-form"></iframe>
</div>
DOMContentLoaded 에 의해 브라우저가 HTML 을 모두 읽고 DOM 트리를 완성하는 즉시 submit 이 동작하게 됩니다.
<form id="malicious-form" action="http://localhost:3000/transfer" method="POST">
<input type="text" name="to" value="alice">
<input type="text" name="amount" value="9">
<input type="submit" value="transfer">
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('malicious-form').submit();
});
</script>
클릭으로 공격이 시도된 코드
a 태그의 href를 통해 공격이 시도되게 됩니다.
<div>
<a href="http://localhost:3000/transfer?to=alice&amount=7">Click me!</a>
</div>
위 코드를 공부하면서 localhost:3000 의 쿠키에 세션 ID 가 저장되어있고, localhost:3001 에서 3000 으로 요청을 보내어도 그 쿠키 데이터가 자동으로 서버로 넘어간다는게 인상적이였습니다.
또한 인터넷 서칭을 하다보면 갑자기 다른 페이지로 리다이렉트되는 경우가 종종 있었는데 이런 경우에 CSRF 공격은 아닌지 경각심을 가질 수 있게 된 것 같습니다.
CSRF 공격을 방어하는 방법
그럼 어떻게 방어를 해야할까요?
Referer 검증
Referer 를 사용하면 어떤 URL 에서 요청을 보냈는지 확인할 수 있습니다. 따라서 request 의 Referrer 을 확인하여 예상되는 주소에서 온 요청인지 검증할 수 있게 됩니다.
일반적으로 Referer를 통해 대부분의 CSRF 공격을 방어할 수 있습니다.
실제 요청은 3000 포트로 가지만 , Referer 는 3001 에서 보낸 정보임을 알려주고 있습니다.
CSRF 토큰 사용
만약 Referrer 검증이 불가한 상황이라면 CSRF 토큰(Security Token)을 활용할 수 있습니다.
- Generate Token (server)
사용자가 페이지에 방문하면 서버에서 CSRF 토큰을 생성하고 해당 난수 값을 포함시켜 응답합니다. - Submit Token (client)
사용자가 양식을 제출하면 CSRF 토큰이 요청에 자동으로 포함됩니다. - Verify Token (server)
서버는 CSRF 토큰이 원래 사용자에게 보낸 토큰과 일치하는지 확인합니다.
사용자의 합법적인 요청은 다음과 같습니다.
위조된 요청은 다음과 같습니다.
그런데 CSRF 토큰이 있어도 결국에 쿠키에 저장되면 똑같지 않나? 라고 생각이 갑자기 들었는데,
우선 발급된 CSRF 토큰을 사용자의 요청에 포함된 것을 확인한 후 그 토큰은 다시 폐기 한다고 합니다. 그리고 새로운 토큰을 페이지에 방문하면 다시 주는 거죠. https://codevang.tistory.com/282
그럼 A 라는 사이트에 방문하지 않았을 경우에는 CSRF 공격으로 수행된 요청에는 토큰이 없을 것이니까. 공격이 방지가 될 것 같네요.
그럼 만약에 A 라는 사이트에 방문하고 바로 CSRF 공격이 수행되는 링크를 눌리면 어떡하지? 토큰에 만료시간이 있나? 어지럽네요.
이 궁금증은 성장한 제가 다시보고 답변해줄거라 믿습니다.
Double Submit Cookie 검증
Double Submit Cookie 검증은 Security Token 검증의 한 종류로 세션을 사용할 수 없는 환경에서 사용할 수 있는 방법이며,
웹 브라우저의 Same Origin 정책으로 인해 자바스크립트에서 타 도메인의 쿠키 값을 확인 수정하지 못한다는 것을 이용한 방어기법입니다. 스크립트 단에서 요청 시 난수 값을 생성하여 쿠키에 저장하고 동일한 난수 값을 요청 파라미터(혹은 헤더)에도 저장하여 서버로 전송합니다. 서버단에서는 쿠키의 토큰 값을 저장할 필요가 없어 위에서 살펴본 세션을 이용한 검증보다 개발 공수가 적은 편입니다.
피싱 사이트에서는 도메인이 달라 쿠키에 값을 저장하지 못하므로(SOP Same Origin Policy) 가능한 방어 기법입니다.
Test Code Repo
https://github.com/Learn-by-doing/csrf-examples
참고자료
3. https://victorzhou.com/blog/csrf/
4. https://codevang.tistory.com/282
'CS > 네트워크 & 웹' 카테고리의 다른 글
DOM 기반(DOM based) XSS(Cross-Site Scripting) 공격과 방어 (0) | 2023.04.22 |
---|---|
저장형(Stored) XSS(Cross-Site Scripting) 공격과 방어 (0) | 2023.04.14 |
반사형(Reflected) XSS(Cross-Site Scripting) 공격과 방어 (2) | 2023.04.13 |
토큰을 어디에 저장해야할까요? (4) | 2023.04.13 |
Transfer-Encoding: Chunked (0) | 2023.04.11 |