CSRF : Cross Site Request Forgery

DATE : 2024/1/18

What is CSRF?

CSRF란 사용자가 의도하지 않은 요청을 자신도 모르게 서버로 보내도록 만드는 공격을 말한다.

이때 중요한 포인트는 서버로 요청을 보내도록 만든다는 것이다.

"서버로 요청을 보내도록 만든다"는 표현을 통해 사용자의 의지와는 무관하다는 뉘앙스를 느낄 수 있는데

그렇다고 해서 서버에게 요청을 보내는 거니까 서버가 공격 대상이라고 받아들이면 안 된다.

CSRF도 XSS와 마찬가지로 Client를 대상으로 삼는 공격으로

XSS는 사용자의 브라우저에서 실행되는 스크립트를 삽입하는 공격이라면

CSRF는 사용자가 어떤 요청을 보내도록 만드는 공격이다.

"사용자 브라우저에서 실행되는" 스크립트라는 말 때문에 XSS는 Client 측 공격임을 쉽게 이해할 수 있지만

"서버로 요청을 보낸다"라는 문구 때문에 CSRF는 서버 측 공격이라 느껴질 수 있다.

CSRF는 사용자 본인도 모르게 요청을 보내도록 만들어 요청을 처리해주는 역할로 서버가 개입되는 것이지,

요청이 처리됨으로써 사실 상 피해를 입는 건 Client라는 걸 알아야 한다.

WHERE?

다음으로 알아볼 키워드는 WHERE! CSRF는 어디에서 발생할 수 있는 공격인지 알아보자.

위에서 CSRF는 사용자가 서버로 요청을 보내게 만드는 공격이라 정의했다.

따라서 CSRF는 요청을 보내는 모든 곳에서 발생할 수 있는 가능성이 있다..!

(하지만 CSRF 공격으로 이어졌을 때, 위험성이 있다고 판단되는 요청을 구분 지을 필요가 있다.) 💡

예를 들어, 사용자가 비밀번호를 수정하기 위해 PASSWORD를 입력하고 변경 버튼을 눌렀다고 해보자.

PASSWORD : 1019

이때 서버에게 비밀번호 수정을 요청하기 위해 전달된 URL이 다음과 같다고 한다.

http://password-change.com/?info=&password_new=1019

현재 URL로 전달 되는 파라미터는 총 2개로

  • info parameter : 사용자에 관한 간단한 설명

  • password_new : 변경할 비밀번호

어렵지 않게 각 파라미터가 가지는 값이 무엇인지 유추해볼 수 있다.

CSRF를 수행하려는 공격자는 이 URL을 보고

사용자 모르게 그들의 비밀번호를 수정하는 요청을 보내고 싶어졌다..!

이때 공격자는 사용자에게 비밀번호를 입력하고 수정 버튼을 클릭하도록 유도하는 방법도 있지만,

이는 사용자가 직접 비밀번호를 입력하고 전송하는 행동을 취해야 한다.

공격자 입장에선 사용자가 그런 행동을 할 것이라 보장할 수 없는 상태에서 마냥 기다릴 순 없을 것..!

그래서 고민을 해본 결과, 방법을 조금 바꾸기로 했다.

http://password-change.com/?info=&password_new=1019

비밀번호를 수정한다는 건, 서버 측 입장에서 위에 적힌 URL을 전달 받는 것으로

사용자가 password-change.com에 들어가 수정할 비밀번호를 입력하고, 수정 버튼을 누를 필요 없이

그냥 URL을 서버로 보내기만 해도 비밀번호를 수정할 수 있다.

즉, 서버로 보낼 요청을 만들어 피해자가 이 요청을 서버로 보내도록 하면 된다는 것이다.

그래서 공격자는 위와 같은 URL을 사용자가 클릭하도록 유도하기로 했다.

이렇게 되면 사용자가 비밀번호를 입력하고 수정 버튼을 누를 과정 없이

URL을 클릭하기만 하면! 사용자 자신도 모르는 사이에 비밀번호를 수정하게 되는 것이다.

이와 같이 공격자 입장에서 만들어 낼 수 있는 요청이라면 CSRF 공격 포인트로 활용될 수 있다!

WHY!

앞서 우리는 CSRF가 어디에서 발생할 수 있는 지에 대해 알아보았다.

CSRF는 모든 요청에 대해 일어날 수 있다고 했는데

본질적으로 CSRF 공격이 왜 일어날 수 있었는지 잠시 생각해보자.

위에서 공격자가 사용자에게 클릭을 유도하려고 한 URL은 누가 봐도

(1) 파라미터가 어떤 데이터를 의미하는 지 유추가 가능했으며

(2) 파라미터에 데이터를 임의대로 넣어 완성할 수 있는 요청이었다.

이 말은 공격자가 비밀번호를 수정하기 위한 요청을 완벽하게 만들 수 있는 상황이라는 뜻으로

인증과 관련된 그 어떤 정보도 들어있지 않았기 때문에 URL을 완성할 수 있었던 것이다. 💡

만약 공격자가 알지 못하는 값을 URL에서 포함한다면 어떻게 될까?

http://password-change.com/?user=hanhxx&info=&password_new=1019&password_old=1018

위에서 봤던 URL과 달리 이번에는 비밀번호를 수정하기 위해서

이전에 사용하던 비밀번호를 입력해야 하는 상황이다.

서버에서는 아마 password_old parameter를 가져다가 요청을 보낸 사용자의 비밀번호가 맞는지 확인한 후

일치한다면 password_new parameter 값으로 비밀번호를 수정하고

일치하지 않는다면 비밀번호를 수정하지 않을 것이다.

이처럼 비밀번호를 수정하기 위해선 인증 목적으로 이전 비밀번호가 필요하지만

이 값은 사용자만 알기 때문에 공격자가 이 값을 임의대로 넣을 수 없다.

따라서 예시에서 본 password_old parameter와 같이 공격자가 모르는 파라미터가 포함되는 경우에는

URL을 완성할 수 없기 때문에 이 요청으로는 CSRF 공격을 수행할 수 없게 된다.

HOW

지금까지 살펴본 내용을 토대로 보면 CSRF는 어떤 요청을 서버로 보내게 만듦으로써 수행하는 공격인데

앞서 살펴본 예시에서는 URL을 사용했다.

즉, GET method를 통해 이루어진 CSRF 을 알아본 것이다. 만약!

링크를 사용했던 게 문제야! 라고 생각해서 GET method를 금지 시킨다면 CSRF 공격을 예방할 수 있을까?

정답은 🔺 세모다.

링크를 활용하지 못한다면 우리는 반대로 POST method를 통한 CSRF 공격을 수행할 수 있다.

다만, CSRF 공격을 POST 방식으로 수행하기 위해서는 form tag를 활용해야 하는데

이때 form tag를 작성한다는 건 스크립트를 작성한다는 뜻이기 때문에 XSS 취약점이 존재해야 한다.

만약 XSS 취약점이 존재하지 않는다면 운 좋게 다행이지만,

그렇지 않다면 CSRF를 수행할 수 있기 때문에 GET method를 금지한다! 는 안전한 방법은 못 된다.

여기서 헷갈려서는 안 되는 포인트!

CSRF를 수행하기 위해 XSS 공격을 하는 것이지,

XSS 공격을 하지 못한다고 해서 CSRF도 불가능하지는 않다.

CSRF에 XSS라는 날개를 달아주면 그 시너지가 확 올라가다 보니 같이 다루는 내용이 많지만

CSRF와 XSS는 서로 다른 공격이기 때문에 이 둘을 정확히 구분할 필요가 있다.

Last updated