웹 보안, 웹 취약점을 간단한 설정으로 막아보자

<이미지 출처 :http://www.boannews.com/media/view.asp?idx=40955 >


이번 주제는 웹 보안에 관련된 내용입니다. 홈페이지에 웹 취약성점검 툴을 돌려 테스트 해본 결과 나온 몇 가지 점들에 대해서 이야기 해볼까 합니다.  지금 여기서 이야기하지 않은 내용들도 많이 있겠지만 간단한 설정만으로 큰 효과를 볼 수 있는 사항에 대해서 진행해 보도록 하겠습니다.


1. 불필요한 Method 지원

첫 번째 목록은 불필요한 Method지원에 관한 내용입니다. HTTP method는 다음과 같은 Method를 지원하고 있습니다.

 GET 

 일반적인 요청으로 요청 URI에 모든 요청정보를 포함 하여 전송합니다.

 POST

 GET이 URI에모든 요청정보를 포함하였다면 POST는 BODY에 요청정보를 숨겨 전송합니다.

 PUT

 POST와 같은 방식으로 전달되지만 BODY의 내용이 실제 URI에 저장됩니다.

 DELETE

 요청 URI에 해당하는 자원을 삭제합니다.

 TRACE

 클라이언트로부터 수신 받은 내용을 응답에 포함시킵니다.

 CONNECT

 SSL tunneling에서 사용됩니다.

 OPTIONS

 URI에 대해 어떤 메서드 기능을 제공하는지, 서버는 무언인지 등의 정보를 제공합니다.

 HEAD

 요청에 대한 BODY없이 HEAD정보만을 반환합니다. 유효성, 접근성 등을 확인할 때 사용됩니다.


위의 각 Method는 각 상황에 맞게 사용할 수 있도록 설계되었지만 취약성 점검 툴을 돌려 보면 GET과 POST이외의 모든 메서드는 제외 시키라고 권고합니다. PUT, DELETE등을 허용하는 것은 이를 통해 크로스 사이트 스크립팅 또는 페이지 위변조에 사용될 수 있기 때문입니다.  예를 들어 web서버의 WebDAV가 활성화 되어있고 PUT메서드가 허용된다면 공격자는 특정 파일을 삽입하여 홈페이지를 변조하거나 DELETE메서드를 통하여 특정위치의 파일들을 삭제 할 수 있습니다.

위 상황을 처리 하기 위해서는 서버에 몇 가지 간단한 설정만으로 처리 될 수 있습니다.  


대표적인 Web server이 Apache의 경우 설정파일(httpd.conf)에 다음을 추가해서 처리 할 수 있습니다. 아래 설정은 Directory별로 또는 Location별로 처리 할 수 있는데 모든 요청에 대해서 GET 과 POST를 제외하고 거부하라는 설정입니다.

<Location /*>

    <LimitExcept GET POST>

        Order deny,allow

        Deny from all

    </LimitExcept>

</Location>


WAS서버의 경우는 web.xml에 다음과 같은 설정을 추가 합니다. url-pattern /* 에 대해서 HEAD, DELETE등 목록에 명시된 method를 제외한 나머지(GET, POST)만 허용하라는 의미 입니다.

<security-constraint>

    <web-resource-collection>

    <web-resource-name></web-resource-name>

    <url-pattern>/*</url-pattern>

    <http-method>HEAD</http-method>

    <http-method>DELETE</http-method>

    <http-method>PUT</http-method>

    <http-method>OPTIONS</http-method>

    <http-method>TRACE</http-method>

    </web-resource-collection>

</security-constraint>



2. 보안에 필요한 필수 헤더의 누락

브라우저는 응답에 포함된 헤더를 통해 자체적으로 컨텐츠를 차단 또는 변경 하는 기능이 구현되어 있습니다. 설정의 종류는 다음과 같습니다.


1. Content-Security-Policy

브라우저에 XSS와 관련된 공격을 막아주는 헤더입니다. 브라우저는 기본적으로 페이지에서 요청하는 모든 코드를 다운로드하여 실행합니다. 하지만 CSP를 설정함으로써 브라우저게 어떠한 조건의 리소스만 실행하거나 렌더링 하라고 지시를 내릴 수 있습니다. 지시문의 종류는 default-src, script-src, child-src등 다양하게 존재 합니다. 

또한 각 지시문에는 다음 4개의 키워드를 선택 적용할 수 있습니다.

    1. 'none' 어떤 것도 허용하지 않습니다.

    2. 'self'   현재 출처에서는 허용하지만 하위 도메인에서는 허용되지 않습니다.

    3. 'unsafe-inline' 인라인 자바스크립트 <script> ...  </script>, 인라인 스타일 <style> .... </style> 을 허용합니다.

    4. 'unsafe-eval'  eval과 같은 텍스트 - 자바스크립트 메커니즘을 허용합니다.


위 옵션 등을 적용하여 몇 가지 예를 들어보도록 하겠습니다.

Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'

    1. default-src 'none' 

    기본적으로 모든 리소스를 차단합니다. 이것만 설정된 경우 사이트는 아무것도 동작하지 않을 것입니다.

    2. script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net;

          script, stylesheet, img 는 cdn.mybank.net을 통해 다운로드 되는 리소스만 허용됩니다. 

    3. connect-src https://api.mybank.com;  

          외부로의 데이터 요청(xhr)등은 api.mybank.com 에서 응답 받은 내용만 가능합니다.

    4. child-src 'self'

           iframe등의 하위요소는 동일 도메인( 서브 도메인조차 허용되지 않음)만 가능합니다.


위와 같이 설정된 경우 보안적으로 강력하게 대응할 수 있습니다. 하지만 저렇게 설정하여 바로 적용한다면 어떤 일이 벌어질까요? 일단 페이지 내부에 정의한 <script></script> 안의 내용은 모두 실행되지가 않습니다. 모든 script는 외부의 js 파일에 담겨 있어야 비로소 동작을 하게 됩니다. <style></style> 안에 적용한 css도 물론 처리되지 않습니다.


Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline' 'unsafe-eval'; style-src https: 'unsafe-inline'

위 예제는 약간은 느슨하게 처리된 옵션입니다. 

    1. default-src https:

           https: 로 시작하는 모든 요청을 허용합니다.

    2. script-src https: 'unsafe-inline' unsafe-eval'

           https: 로 시작하는 script를 허용하며 페이지 내에 선언된 <script> .... </script>와 element에 추가된 onclick과 같은                 script가 허용됩니다. default-src에 https: 를 선언했지만 script-src를 재 정의했기 때문에 https: 를적어야 합니다. 


Content-Security-Policy-Report-Only: 설정들 report-uri /my_amazing_csp_report_parser;

처음 CSP를 홈페이지에 적용하기는 생각보다 쉽지 않습니다. 모든 페이지를 알고 있지 않는 한 어디에 무슨 코드가 숨어있을지 알 수 없기 때문인데요. 실제 해당 내용을 바로 적용하는 것이 아니라 위반 사항이 발견될 경우 Report만 받는 것으로 설정을 할 수도 있습니다. 


2. X-Frame-Option

이 헤더는 사용자의 눈에 보이지 않는 영역을 추가 하여 사용자는 의도한대로 버튼을 누르지만 실제로는 다른 곳을 클릭하게 만드는 ClickJacking을 방지 할 수 있는 옵션입니다. 페이지 내부에 심어질 수 있는 iframe과 같은 곳에 접근을 제어하는 옵션으로 설정 할 수 있습니다.

X-Frame-Options : DENY             모든 표시를 거부합니다.

X-Frame-Options : SAMEORIGIN   동일한 출처에 대한 것만 표시 합니다. 

X-Frame-Options : ALLOW FROM http://www.webponent.com      http:www.webponent.com에 대해서만 허용합니다.


3. X-Content-Type-Option

이 헤더는 리소스를 다운로드 할때 해당 리소스의 MIMETYPE이 일치하지 않는 경우 차단을 할 수 있습니다. 

X-Content-Type-Options: nosniff

위 처럼 설정하는 경우 styleSheet는 MIMETYPE이 text/css와 일치할 때까지 styleSheet를 로드하지 않습니다. 또한 공격자가 다른 확장자(jpg)로 서버에 파일을 업로드 한 후 script태그등의 src의 경로를 변경하여 script를 로드 하는 등의 공격을 막아줍니다.


4. Strict-Transport-Security

이 헤더는 한번 https로 접속 하는 경우 이후의 모든 요청을 http로 요청하더라도 브라우저가 자동으로 https로 요청합니다. 

Strict-Transport-Security: max-age=31536000;includeSubDomains;preload

https로 전송한 요청을 중간자가 가로채어 내용을 볼 수 있는(MIMT)기법을 클라이언트 레벨(브라우저)에서 차단할 수 있습니다. 또한 2014년 블랙햇 아시아 컨퍼런스에서 "Leonard Nve Egea"가 sslStrip+ 를 공개하면서 서브도메인을 통해 우회할 수 있는 방법에 대해 includeSubDomains 를 추가하여 차단할수 있습니다.


5. X-XSS-Protection

이 헤더는 공격자가 XSS공격을 시도할 때 브라우저의 내장 XSS Filter를 통해 공격을 방지할 수 있는 헤더입니다.

X-XSS-Protection: 1;mode=block

위 처럼 설정한 경우 브라우저가 XSS공격을 감지하면 자동으로 내용을 치환합니다. mode=block 유무에 따라 내용만 치환

하고 사용자화면에 보여주거나 페이지 로드 자체를 block할 수 있습니다. 

위 헤더는 브라우저의 내장 XSS Filter에 의해 처리 되므로 각 브라우저마다 처리 방식이 다를 수 있습니다. 모든 공격을 막을 수는 없기 때문에 추가적으로 Filter를 설정하여 방어해야 합니다.



6.Cache-Control, Pragma 

공격자가 브라우저의 히스토리를 통한 공격을 진행 할 수 있기 때문에 cache를 적용하지 않는다는 헤더 입니다.



위 설정에 대한 Apache 설정은 다음과 같이 처리 할 수 있습니다.

<FilesMatch "\.(html|htm|js|json)$">

    <IfModule mod_headers.c>

        Header set Content-Security-Policy  "script-src * 'self' 'unsafe-inline' 'unsafe-eval' "

        Header set X-Content-Type-Options "nosniff"

        Header set X-XSS-Protection "1;mode=block"

        Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;"

        Header set Cache-Control "no-store"

        Header set Pragma "no-cache"

    </IfModule>

</FilesMatch>


WAS는 필터 등을 이용하여 response에 해당 해더들을 동일하게 내려 보내면 됩니다.

response.setHeader("X-Content-Type-Options","nosniff");




New Multi-Channel Dynamic CMS