안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

웹, 앱 (Web, Application)

[Web] XSS와 CSRF (Cross Site Scripting and Cross Site Request Forgery)

피그브라더 2020. 1. 10. 22:48

1. XSS (Cross Site Scripting)

 

1-1. 의미

웹사이트에 악의적 스크립트를 삽입하여 쿠키, 개인정보 등을 빼돌리는 해킹 기법이다. 간단한 예시로, 게시글을 작성할 때 <script>...</script>와 같은 JavaScript를 삽입하여 <script> 태그 안에 작성한 악의적 목적의 코드가 실행되게끔 하는 것을 들 수 있다. 코드를 어떻게 작성하느냐에 따라 쿠키나 개인정보 등을 빼돌릴 수도 있고, 특정 웹사이트로 이동하도록 할 수도 있고, 그 밖의 다른 동작을 수행하게끔 할 수도 있다. 주로 중요한 데이터를 다른 사이트로 빼돌리기 위해 사용하기 때문에 'Cross Site'라는 이름이 붙게 되었다.

 

1-2. 공격 과정 예시

① 스크립트 삽입에 취약한 웹사이트를 파악한다.

② 웹사이트에 방문자의 쿠키를 빼돌리는 악성 스크립트를 삽입한다.

③ 사용자가 그 웹사이트를 방문할 때마다 해당 사용자의 쿠키가 공격자에게로 전달된다.

 

1-3. 해결 방법

  • 이스케이프 (Escape) : 악의적인 스크립트를 작성할 수 있는 곳에 입력되는 내용이 렌더링 시 자동으로 이스케이프 되도록 한다. 예를 들어, 게시물 작성 페이지에서 <script> 태그로 시작하는 JavaScript 코드를 작성했을 때 그렇게 저장된 내용이 웹 페이지에 그대로 렌더링 되면 그 게시물을 보는 페이지에서 해당 스크립트가 자동으로 실행될 것이다. 이러한 문제는 웹 페이지에 게시물 내용을 렌더링 할 때 <script> 태그로 시작하는 내용을 실제로 눈에 보이는 문자의 형태로 이스케이프 처리해주면 해결할 수 있다. (실제로 Django의 템플릿 엔진은 문자열 변수 값을 렌더링 할 때 자동으로 이스케이프 처리를 해주며, React의 JSX 문법도 JavaScript 문자열 표현식을 렌더링 할 때 자동으로 이스케이프 처리를 해준다.)
  • HttpOnly 옵션 : 쿠키 설정 시 HttpOnly 옵션을 주는 것이다. 이 옵션이 설정된 쿠키는 브라우저에서 JavaScript를 통해 접근이 불가능하고 오로지 서버에 전송되는 것만 가능하다. 따라서 JavaScript를 통해 쿠키를 탈취하는 것을 막을 수 있다.

 

2. CSRF (Cross Site Request Forgery)

[Figure 2] CSRF 공격 과정

 

2-1. 의미

인증된(권한을 가진) 사용자가 자신의 의도와 무관하게 공격자가 의도한 어떤 행위(수정, 삭제)를 하도록 유도하는 해킹 기법을 말한다. 간단한 예시로, 권한을 가진 사용자(즉 로그인한 사용자)에게 특정 악성 링크에 접속하도록 유도하고, 그 링크에 접속하면 자동으로 권한을 가진 웹사이트에 특정 POST 요청을 보내도록 설계하는 것을 들 수 있다. 즉, 자기도 모르게 (권한이 있어야만 수행할 수 있는) 위험한 요청을 서버에 보내도록 하는 것이다. 그러면 서버 입장에서는 권한이 있는 요청이라고 판단하여 요청된 동작을 그대로 수행할 것이다.

 

2-2. 공격 과정 예시

① CSRF에 취약한 웹사이트를 파악한다.

② 웹사이트를 통해 자금을 이체하도록 하는 요청을 위조하고, 이를 하이퍼링크에 심어서 인증된 사용자에게 전송한다.

③ 사용자는 해당 하이퍼링크를 클릭하면 위조된 요청을 자기도 모르게 웹사이트의 서버에게 전송하게 된다.

④ 서버는 인증된 사용자의 유효한 요청이라 판단하고, 사용자의 계좌에서 특정 금액이 공격자에게 이체되도록 한다.

 

2-3. 해결 방법

  • Referrer 검증 : 요청 헤더의 Referrer 필드 값을 확인하여, 동일한 도메인으로부터 온 요청인지 확인하는 방법이다. 만약 악성 페이지로부터 온 요청이라면 동일한 도메인이 아닐 것이므로 CSRF 공격이라고 판단하여 요청을 거부하는 것이다. 하지만 동일한 도메인 내의의 페이지에 XSS 취약점이 있다면 이 방법으로는 방어할 수 없다.
  • CSRF 토큰 검증 : 사용자의 세션에 임의의 난수인 CSRF 토큰을 생성한 뒤, 클라이언트의 작업 페이지에 hidden 필드로 이 값을 설정해줌으로써 해당 POST 폼이 제출될 때 그 토큰 값도 함께 전송하도록 하여 인증하는 방식이다. 하지만 이것 역시 토큰 값이 hidden 필드로 설정된 페이지에 GET 요청을 먼저 보내고, 그 응답으로부터 토큰 값을 탈취한 뒤 이를 가지고 다시 악의적인 POST 요청을 보낼 수 있으므로 문제가 된다(참고).
  • Double Submit Cookie 검증 : 세션을 사용할 수 없는 환경에서 사용할 수 있는 방법으로, 브라우저가 JavaScript에서 다른 도메인의 쿠키를 설정하지 못하도록 하는 것을 이용한 것이다. 클라이언트는 요청을 보낼 때 임의의 난수 값을 생성하여 쿠키에도 저장하고 요청 파라미터에도 포함시킨다. 그러면 서버에서는 요청 헤더에 포함되어 있는 쿠키의 값과 요청 파라미터의 값을 비교하여 그 둘이 같은 경우에만 요청을 허용하게 된다. 만약 다른 도메인으로부터의 요청이라면 임의의 난수 값을 요청 파라미터에 포함시키는 건 가능하겠지만 쿠키에 설정하는 것이 불가능할 것이다. 이로 인해 서버에서 두 값을 비교 검증할 때 해당 요청이 유효하지 않음을 파악할 수 있게 된다. 하지만 이것 역시 동일한 도메인 내의의 페이지에 XSS 취약점이 있다면 문제가 된다.
Django를 공부하는 사람의 경우, Django에서 CSRF 공격을 어떻게 막는지 확인해보면 좋다. Django의 CSRF 방지 메커니즘에 관련해서는 이 포스팅을 읽어보자.

 

 

 

 

 

 

본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.

https://itstory.tk/entry/CSRF-%EA%B3%B5%EA%B2%A9%EC%9D%B4%EB%9E%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-CSRF-%EB%B0%A9%EC%96%B4-%EB%B0%A9%EB%B2%95