[CS] 초보 개발자도 이해할 수 있는 XSS, CSRF, CORS 보안 원리
[배경]
웹 애플리케이션은 인터넷을 통해 접근 가능하기 때문에 다양한 보안 위협에 노출됩니다. 웹 개발자는 이러한 위협을 인식하고 대응할 수 있어야 하며, XSS, CSRF, CORS는 그 중에서도 특히 흔하게 발생하는 공격 벡터입니다. 이러한 보안 취약점들은 사용자의 민감한 데이터에 접근하거나, 서버 리소스를 무단으로 조작하게 만들 수 있기 때문에 웹 애플리케이션의 신뢰성과 안전성을 심각하게 해칠 수 있습니다. 그래서 이번 글에서는 XSS, CSRF, CORS의 각각의 특징, 정의와 보안방안에 대해 알아보겠습니다.
[내용]
먼저 HTTP 요청은 기본적으로 Cross-Site HTTP Request가 가능합니다. 즉, <img> 태그로 다른 도메인의 이미지 파일을 가져오거나, <link> 태그로 다른 도메인의 CSS를 가져오거나 <script>태그로 다른 도메인의 JavaScript 라이브러리를 가져오는 것이 가능하게 되었습니다.
하지만 <script></script> 로 둘러 쌓여 있는 스크립트에서 생성된 Cross-Site HTTP Reques 는 Same Origin Policy를 적용 받기 때문에 Cross-Site HTTP Request가 불가능 합니다.
AJAX가 널리 사용되면서 <script></script> 로 둘러 쌓여 있는 스크립트에서 생성되는 XMLHttpRequest에 대해서도 Cross-Site HTTP Request가 가능해야 한다는 요구가 늘어나자 W3C에서 CORS라는 이름의 권고안이 나오게 된 것입니다.
1. CORS가 뭘까요?
CORS란 Cross-origin Resource Sharing의 줄임말로, HTTP 전반에서 추가 HTTP 헤더를 사용하여 한 출처에서 실행중인 웹 어플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에게 알려주는 체제입니다.
즉, Cross-Site HTTP Request를 가능하게 하는 표준 규약이라고 할 수 있습니다. CORS 요청은 Simple / Preflight가 있습니다.
* Simple Request
Simple Request 는 다음과 같은 3가지 조건을 모두 만족하면 Simple Request 라고 합니다.
- GET, HEAD, POST 중의 한 가지 방식을 사용해야 한다.
- POST 방식일 경우 Content-Type이 아래 셋 중의 하나여야 한다.
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain - 커스텀 헤더를 전송하지 말아야 한다.
Simple Request는 서버에 1번 요청하고 서버도 1번 응답하는 것으로 처리가 종료됩니다.
* Preflight Request
Simple Request 조건에 해당하지 않으면 브라우저는 Prefliget Request 방식으로 요청합니다.
따라서, Preflight Request는 GET, HEAD, POST 외의 다른 방식으로도 요청을 보낼 수 있고, application/xml 처럼 다른 Content-Type으로도 요청을 보낼 수 있습니다. 또한 커스텀 헤더도 사용이 가능합니다.
Preflight Request는 이름처럼 예비 요청과 본 요청으로 나뉘어 전송됩니다.
먼저 서버에 예비 요청( Preflight Request )을 보내고 서버는 예비 요청에 대해 응답하고, 그 다음에 본 요청( Actual Request )을 서버에 보내고, 서버도 본 요청에 응답합니다.
하지만 예비 요청과 본 요청에 대한 서버의 응답을 개발자가 직접 구분하여 처리하는 것은 아닙니다.
개발자가 Access-Control- 계열의 Response Header만 적절히 잘 정해주면 OPTIONS라는 메서드 요청으로 오는 예비 요청과 GET, POST, PUT, DELETE 등으로 오는 본 요청의 처리는 서버가 알아서 처리합니다.
여기서 OPTIONS 라는 메서드가 언급되었는데 OPTIONS 이란, CORS 에서 OPTIONS 메소드를 통해 Preflight Request 요청, 즉 사전 요청을 보내 서버가 해당 parameters를 포함한 요청을 보내도 되는지에 대한 응답을 줄 수 있게 하는 것입니다.
POST 메서드로 요청을 보내면 POST는 POST 요청만 하지않고 확인하고자 하는 주소의 OPTIONS 메서드를 먼저 요청하고 200번의 응답을 확인해야지만 POST 메서드를 정상적으로 호출할 수 있습니다. 이것이 Preflight Request 라고 하는 것입니다.
왜 POST 요청 전에 OPTIONS 메서드를 먼저 사용해야 하냐면 POST 메서드 같은 경우는 많은 양의 데이터를 전송할 수도 있는 메서드다보니 서버에 확인도 하지 않고 이 많은 양의 데이터를 전송하는 것이 낭비이기 때문에 OPTIONS 메서드를 통해 먼저 서버에서 지원하고 있는 메서드 (GET, PUT, DELETE 등..) 을 확인하기 위함입니다.
정리
앞에서 설명했듯이 CORS가 등장하기 전 까지는 보안상의 이유로 다른 출처는 악용의 우려가 있다고 판단하여 차단했기 때문에 한 오리진에만 접근할 수 있도록 설계 되어있었다고 했습니다. ( 위에서 언급한 Same Origin Policy 입니다)
CORS를 적용하게 되면서 다른 악용의 우려가 있는 출처를 막기 위해서 서버에서 허용 범위를 지정하고 ( 위의 코드에서 작성한 defaultCorsHeader 내용 ) 이 서버가 허용한 범위 내에서만 Cross Origin 요청을 허용하기 위해서 확인 차 사용하는 메서드가 바로 OPTIONS 메서드인 것입니다.
2. XSS가 뭘까요?
XSS 는 클라이언트가 서버를 신뢰해서 벌어지는 보안 이슈입니다. 서버에 요청하고 일방향으로 응답을 받는 점을 악용해 게시판이나 웹 메일 등에 자바스크립트와 같은 스크립트 코드를 삽입하여 개발자가 고려하지 않은 기능이 작동하게 하여 클라이언트를 공격하는 기법입니다.
위의 그림처럼 공격자가 미리 XSS 공격에 취약한 웹 사이트를 탐색하고, XSS 공격을 위한 스크립트를 포함한 URL 등을 사용자에게 노출시킵니다. 이런 사실을 모를 수 밖에 없는 사용자는 해당 URL을 클릭 할 경우, 취약한 웹 사이트의 서버에 스크립트가 포함된 URL을 통해 Request 를 전송하고, 웹 서버에서는 해당 스크립트를 포함한 Response를 전송하게 되는 것입니다.
XSS 를 방지할 수 있는 방법
XSS 공격은 IPS, IDS, 방화벽 등으로도 방지할 수가 없기 때문에 단순히 문자를 필터링 하는 등의 방법만이 존재합니다. XSS 공격은 입력값에 대한 검증이 제대로 이루어지지 않아 발생하는 취약점 입니다. 때문에 사용자의 모든 입력값에 대하여 주로 스크립트를 실행하기 위한 특수문자를 정규표현식으로 필터링하는 방법입니다.
3. CSRF가 뭘까요?
CSRF는 XSS와 반대로 서버가 클라이언트를 신뢰해서 벌어지는 보안 이슈입니다. XSS를 이용한 공격이 사용자가 특정 웹사이트를 신뢰하는 점을 노린 것이라면, CSRF는 특정 웹사이트가 사용자의 웹 브라우저를 신뢰하는 상태를 노린 것입니다. 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위( 수정, 삭제, 등록 등 )를 특정 웹 사이트에 요청하게 합니다.
공격과정
- 사용자는 웹 사이트에 로그인하여 정상적인 쿠키를 발급받습니다.
- 공격자는 공격용 링크를 이메일이나 게시판 등의 경로를 통해 이용자에게 전달합니다.
- 공격용 링크에 도착지를 변조합니다. 예를 들면 이메일을 클릭했을 때 정상적인 경우라면 읽고자 하는 이메일이 열릴테지만 공격용 링크는 도착지를 변경했기 때문에 공격자가 전달한 공격용 링크로 이동하게 되는 것입니다.
- 사용자가 공격용 페이지를 열면, 브라우저는 공격용 URL을 열게 됩니다.
- 사용자의 승인이나 인지 없이 출발지와 도착지가 등록됨으로써 공격이 완료됩니다.
CSRF 를 방지할 수 있는 방법
CSRF Token 을 사용하여 사용자가 요청할 때마다 서버에서 고유한 토큰을 발급하여 요청과 함께 검증할수 있습니다. SameSite 속성을 설정하면 다른 사이트에서 발생한 요청으로는 쿠키를 전송하지 않도록 설정할 수 있어 실제 같은 사이트에서만 발생한 요청을 구별할 수 있습니다. Referer 헤더 검사 웹사이트가 허용된 도메인에서 온 요청인지 확인해서, 다른 도메인에서 온 요청은 차단하게 설정할 수 있습니다.
[결론]
XSS, CSRF, CORS와 같은 보안 취약점은 개발 초기 단계에서 올바른 설계와 정책 설정으로 충분히 예방할 수 있습니다. 따라서 보안은 추가적인 기능이 아니라, 웹 애플리케이션 개발의 기본 요소로 고려되어야 합니다. 보안은 단순히 기술적인 문제만이 아니라 사용자 신뢰와도 연결되어 있습니다. 보안이 잘 적용된 웹 사이트는 사용자에게 신뢰를 주며, 이는 장기적으로 서비스의 성공에 중요한 요소가 될 수 있습니다.
[출처 및 참조]