보안 취약점과 정보보안의 3요소

웹 애플리케이션을 포함한 각종 소프트웨어를 개발하는 과정에서는 설계 단계나 구현 단계에서 유발된 버그가 발생할 수 있습니다. 이러한 버그중에는 단순히 어떠한 기능이 동작하지 않거나, 오작동을 유발하는 버그가 있는가 하면, 소프트웨어의 보안성에 영향을 주는 버그도 있습니다. 또한 이렇게 개발된 소프트웨어가 서비스되어 운영될 때에는 설정 문제로 인해 보안성에 문제가 생기기도 합니다.

소프트웨어 버그나 설정 문제점과 같이 보안성에 영향을 주는 문제점을 보안 취약점이라고 합니다. 보안성에 영향을 준다는 의미는 정보보안의 3요소 중 최소 한 가지 이상에 영향을 미친다는 뜻으로, 정보보안의 3요소는 기밀성, 무결성, 가용성입니다.

  • 기밀성(confidentiality)

    특정 정보가 오직 접근 권한이 있는 사용자에게만 열람되어야 하며, 허가되지 않은 사용자에게 절대로 노출되지 않아야 한다. 기밀성에 영향을 주는 대표적인 예로는 패스워드, 주민등록번호, 신용카드 등의 개인정보가 노출되는 것이다. 파일의 경우 읽기 권한이 기밀성을 위해 사용된다.

  • 무결성(integrity)

    허가되지 않은 사용자가 정보를 수정할 수 없어야 한다. 무결성이 영향을 받는 경우로는 웹사이트의 내용을 변경시키는 웹사이트 변조 공격, 랜섬웨어나 각종 악성 코드에 의해 파일의 내용이 변경되는 것이 해당한다.

  • 가용성(availability)

    서비스가 문제 없이 운용되어 허가된 사용자는 항상 정보에 접근할 수 있어야 한다. 가용성에 영향을 주는 대표적인 예로는 DOS(Denial Of Service) 라고 하는 서비스거부 공격이 있다. 공격 대상 시스템이 감당하지 못할 정도로 유발된 네트워크 트래픽으로 인해 서비스거부 공격이 발생하기도 하지만 소프트웨어 실행에 필수적인 파일이 삭제되거나, 호스트가 종료되거나 리부팅되도록 만들어 서비스거부 공격이 발생 할 수도 있다.

보안 취약점이 존재하면, 공격자는 이러한 보안 취약점을 이용하여 공격을 시도하는데, 이런 공격을 익스플로잇이라고 합니다. 예를 들어, SQL 인젝션과 같은 웹 공격의 경우도 SQL 인젝션 취약점이 있을 때 이를 이용해서 공격하는 것입니다. SQL 인젝션 공격이 이루어지기 위해서는 다음과 같은 과정이 필요합니다.

  1. 웹 애플리케이션 개발자가 SQL 쿼리문에 사용자 입력값을 직접 대입시키도록 코드를 추가함으로써 SQL 인젝션 취약점을 유발한다.
  2. 공격자가 웹 애플리케이션을 분석하여 특정 파라미터에서 SQL 인젝선 취약점을 발견한다.
  3. 공격자가 SQL 인젝션 취약점이 있는 해당 파라미터를 통해 SQL 인젝션 공격을 수행한다.

참고로, SQL 인젝션 취약점은 정보보안 3요소 모두에 영향을 줄 수 있는 취약점입니다. SQL 인젝션 공격은 주로 데이터베이스에 저장되어 있는 개인정보를 탈취할 때 사용하는데 이때에는 기밀성에만 영향을 준다고 볼 수 있습니다. 하지만 DBMS에 따라서 SQL 인젝션 공격을 이용하여 시스템 명령어 실행이 가능한 경우 (예. 마이크로소프트 SQL 서버의 xp_cmdshell)도 있습니다. 이 경우 공격자가 마음대로 시스템 내의 파일을 읽고(기밀성), 변경하고(무결성), 삭제하는(가용성) 것이 가능하기 때문에, 정보보안 3요소 모두에 영향을 줄 수 있습니다. 당연히 더 많은 정보보안 3요소에 영향을 줄 수 있는 취약점일수록 더욱 심각한 취약점이라고 할 수 있습니다.

보안 취약점이 새롭게 발견되어 신고되면 MITRE라는 외국 단체에서 관리하는 CVE라는 공개된 보안 취약점 데이터베이스에 등록될 수 있습니다. CVE에 등록하기 위해서는 CNA(CVE Numbering Authorities)라는 CVE ID 발급자를 통해 보안 취약점을 신고해야 합니다. CNA는 대부분이 잘 알려진 소프트웨어 제품의 제조사로, 각 CNA는 자사 제품의 보안 취약점에 대해서만 CVE ID를 발급 할 수 있습니다. 오픈소스 보안 취약점을 발급하기 위한 CNA도 존재합니다. CNA 리스트는 다음 링크에서 확인할 수 있습니다.

http://cve.mitre.org/cve/request_id.html#cna_participants

CVE ID는 CVE-[발견연도]-[일련번호]로 구성된 유일한 값을 가지기 때문에, 특정 보안 취약점을 추적하고 패치 및 관리하는데 용이합니다. 유명한 취약점인 하트블리드의 경우 CVE-2014-0160이라는 CVE-ID를 가지고 있습니다. CVE ID 로부터 해당 취약점이 2014년에 발견된 것을 알 수 있습니다.

공격자 역시 CVE를 검색하여 특정 소프트웨어 버전의 보안 취약점을 알 수 있으며, CVE ID를 이용하여 특정 보안 취약점과 관련된 익스플로잇 등과 같은 정보를 얻을 수 있습니다. 이렇게 수집한 정보를 이용하여 알려진 취약점을 이용한 공격을 수행하기도 합니다.

해킹 단계

그림 1-1해킹 단계

해킹 단계
  • 첫 번째 단계는 정찰 단계입니다. 공격 대상에 대한 각종 정보를 수집하는 단계로 우선 공격 대상에 접근하지 않고 검색 사이트나 인터넷에 공개되어 있는 정보를 수집합니다. 공격 대상에 직접 접근하지 않기 때문에 이 과정을 패시브 스캐닝(passive scanning)이라고도 합니다. 공격 대상이 어떤 서비스를 하는지, 웹 서버 등 외부에서 접근가능한 서버의 IP 주소가 무엇인지 등을 알아냅니다.
  • 두 번째 단계는 스캐닝을 하고 취약점을 분석하는 단계로 서버의 운영체제가 무엇인지, 사용하는 소프트웨어 버전이 무엇인지 등을 알아내고, nmap과 같은 스캐닝 프로그램을 이용하여 열려 있는 네트워크 포트를 점검하고, 종합 취약점 스캐닝 프로그램으로 각종 보안 취약점 정보를 수집합니다. 이 과정에서 공격 대상이 실제로 접근하게 되기 때문에 액티브 스캐닝(active scnning) 단계라고도 합니다.
  • 세 번째 단계는 침투 단계입니다. 이전에 정찰과 스캐닝 단계에서 입수한 각종 정보를 토대로 공격을 수행합니다. 예를 들어, 정보 수집 과정에서 사용자 계정 정보를 알아냈다면 이 정보로 호스트에 침투하기도 하고, 보안 취약점의 존재를 확인했다면 이것을 익스플로잇하여 호스트로 침투하기도 합니다. 주로 웹사이트가 최초 타깃이 되는 경우가 많습니다.
  • 네 번째 단계부터 여섯 번째 단계를 포스트 익스플로잇(post-exploit) 단계라고 합니다. 포스트는 '이후의, 사후의' 라는 의미로 공격자가 공격, 즉 익스플로잇을 하고 난 다음, 시도하는 공격을 말합니다.
  • 네 번째 단계는 권한 상승 단계입니다. 공격자가 침투에 성공했는데 이때 획득한 권한이 일반 사용자 권한이라면 호스트 내부의 리소스에 접근하는데 제한이 생깁니다. 그렇기 때문에 권한 상승을 통해 호스트 전체에 접근할 수 있는 관리자 권한을 획득하는 단계입니다.
  • 관리자 권한까지 얻어내고 나면 다섯 번째 단계에는 사용자를 추가하거나 백도어를 설치하여 언제든지 공격자가 원할 때 다시 해당 호스트에 접속할 수 있도록 만들어 둡니다. 이러한 과정을 퍼시스턴스라고 합니다.
  • 마지막 단계에는 공격자가 해킹 흔적을 지우는 시도를 합니다. 해킹 사고가 발생하고 나면 호스트 관리자나 보안 담당자는 각종 로그, 메모리, 디스크 등에 있는 데이터로부터 디지털 포렌식을 수행하여 해킹을 추적하는데, 이러한 해킹 흔적을 지움으로써 해킹 시도를 알아채기 어렵게 만들고 자신이 추적을 당하지 않도록 합니다.

이와 같은 해킹 단계를 총 여섯 단계로 구분할 수 있습니다. 다만 이 단계는 한 개의 공격 대상을 공격하는 과정을 정리한 것입니다. 만약 기업의 내부에 또 다른 네트워크나 호스트가 존재하는 경우 ( 실제로 많은 기업들이 보안을 위해 내부 네트워크를 별도로 구성하여 외부에서는 접근이 불가능하게 하고 있습니다. ) 공격자는 첫 공격 대상 호스트를 해킹하는 과정에서 새롭게 얻은 정보를 이용하여, 또 다른 호스트로 계속해서 해킹을 진행해나갈 수도 있습니다. 일단 내부 네트워크로 진입하게 되면 외부에서 접근 불가능한 호스트들을 추가로 접근할 수 있게 되는데, 이와 같이 공격한 호스트를 거점으로 삼고 추가로 다른 호스트에 접근하는 것을 피버팅이라고 합니다. 공격자는 피버팅으로 공격을 확장해 나가면서 위 해킹 단계 과정을 반복하게 됩니다.

웹 공격 단계

웹 애플리케이션은 그 자체로 완전히 독립적인 소프트웨어이기 때문에, 웹을 공격하는 것 역시 하나의 호스트를 공격하는 것과 유사한 과정을 거칩니다. 웹 공격 과정은 다음과 같은 단계로 이루어집니다.

  • 정보 수집

    웹 공격을 위한 준비 단계로 웹 서버, 웹 프레임워크 등의 버전이나 설정 오류로 인한 취약점을 찾고, 크롤링과 웹 애플리케이션 매핑을 통해 웹 애플리케이션의 구조를 분석하는 단계이다.

  • 공격

    정보 수집 단계에서 수집한 정보를 바탕으로 웹 공격을 수행한다. 공격의 결과는 웹사이트 회원정보 등 민감한 데이터 획득, 웹 애플리케이션 사용자 시스템 접근, 웹 서버 호스트 침투 등까지 공격에 따라 다양하나 나타날 수 있다. 웹 공격은 크게 웹 애플리케이션 대상 공격과 웹 서버 및 웹 프레임워크 등의 구성요소의 알려진 취약점을 이용하여 이것들을 대상으로 수행하는 공격으로 나눌 수 있다.

  • 포스트 익스플로잇

    주로 쉘을 획득하여 내부의 정보를 탈취하고, 호스트로 침투한 경우 다른 호스트나 네트워크에 대한 공격을 이어가는 단계이다. 일반적으로 웹 애플리케이션은 일반 사용자 권한으로 실행되기 때문에 관리자 권한을 읻기 위한 권한 상승 공격으로 이어지게 되며, 그 밖에도 앞의 해킹 단계 섹션의 포스트 익플로잇 단계를 수행한다.

웹 보안을 위한 공통 고려사항

인증(Authentication)

인증은 사용자의 신원을 확인하는 과정입니다. 우리 일상에서도 인증과 관련된 사례를 쉽게 찾아볼 수 있는데 몇 가지 사례는 다음과 같습니다.

  • 본인의 카드키를 사용하여 건물을 출입한다.
  • 본인임을 확인하기 위해 신분증을 확인한다.
  • 스마트폰, SMS를 이용하여 인증번호를 보내 본인 확인을 한다.

웹 애플리케이션에서의 인증 과정은 주로 로그인 가능을 통해 구현합니다. 사용자가 사용자 아이디와 패스워드 등을 입력하고, 웹 애플리케이션에서 이를 확인하는 과정이 인증 과정입니다. 인증 과정이 아주 중요한 사이트에는 다중 인증(또는 멀티 팩터 인증, multifactor authentication) 과정을 적용하기도 합니다. 브루트 포스공격과 같은 자동화된 공격을 차단하고자 하는 경우에는 캡차(CAPTCHA)등을 추가로 입력하기도 합니다.

인가(Authorization) 및 접근 통제(Access Control)

인가는 특정 사용자가 어떤 리소스에 접근 권한을 가지고 있는지 확인하는 과정입니다. 주변 건물의 내부를 들여다보면 '관리자 보호 구역', '관계자 외 출입금지' 등으로 구분되어 있는 구역을 볼 수 있는데, 이러한 구역에 대한 접근을 위해 사용자가 관리자나 관계자인지 확인하는 과정을 인가 과정에 비유할 수 있습니다. 인증 과정을 거쳐 들어온 사람이라고 하더라도, 적절한 권한이 없으면 인가 과정에 의해 특정 구역에는 들어갈 수 없도록 한 것입니다. 바로 여기에 인증과 인가의 차이가 있습니다. 인증은 신원을 확인하는 과정이고, 인가는 앞서 신원이 확인된 사용자의 권한을 확인하는 것입니다. 이와 더불어 접근 통제는 인증과 인가 과정을 거친 후 리소스에 대한 접근을 허용하거나 차단하는 과정을 의마합니다. 실제로는 약간의 의미 차이가 있긴 하지만 종종 실무에서는 인가와 접근 통제를 동일한 개념으로 사용하기도 합니다.

웹에서의 인가도 마찬가지입니다. 웹사이트 내의 각종 데이터에 접근하고 각종 기능을 관리할 수 있는 관리자 메뉴에는 관리자 권한을 가진 사용자만 접근 가능해야 합니다. 모든 사용자가 로그인에 성공하더라도(인증), 오직 해당 사용자가 관리자인지 확인(인가)한 후 특정 관리 메뉴에 접근(접근 통제) 하도록 하는 것입니다.

어떤 웹 애플리케이션의 경우에는 다양한 권한의 사용자를 구분하기도 합니다. 모든 관리 권한을 실행할 수 있는 관리자, 정보를 열람할 수만 있는 읽기전용(모니터링) 사용자, 특정 게시판에만 접근할 수 있는 사용자 등, 필요에 따라서 사용자를 구분합니다. 이와 같이 역할에 따라 사용자를 구분하여 접근을 통제하는 것을 역할 기반의 접근 통제(RBAC, role-based access control)라고 합니다. 네이버 카페나 다음 카페 등을 이용해본 사람들은 알겠지만, 대부분의 카페에서는 카페 회원의 등급을 나누고, 특정 등급의 회원들만 접근할 수 있는 게시판의 별도로 만듭니다. 특정 등급의 회원만 특정 게시판에 접근할 수 있도록 구현한 것 역시 인가 및 접근 통제 과정으로 볼 수 있습니다.

입력값 검증(Input validation)

공격자가 웹 공격을 시도할 때에는 대부분의 경우 웹 요청 메시지에 전달되는 파라미터, 쿠키, 헤더 등의 값을 조작하여 이루어집니다. 일부 웹 공격을 위해서는 이러한 값을 조작할 때 특정한 문자열의 입력이 필요합니다. 몇 가지 예를 들면 다음과 같습니다.

공격종류 입력 문자열
SQL 인젝션 공격 ', OR, UNION, ORDER BY 등 SQL 쿼리문에 사용되는 키워드
커맨드 인젝션 공격 ;, |, && 등의 특수문자
디렉터리 트래버설 공격 ../ 등의 문자열
쉘쇼크 공격 () { :;}; 문자열
XXE 공격 XML <!ENTITY 태그
크로스 사이트 스크립팅 공격 <script>와 같은 자바스크립트 태그

입력값 검증이란 파라미터, 쿠키, 헤더 등 사용자가 외부에서 제어할 수 있는 값이 공격에 사용되는 특정 문자열을 포함하고 있는지, 또는 웹 애플리케이션이 필요로 하는 값의 형식인지 검사하는 과정입니다. 적절한 입력값 검증을 통해 상당수의 공격을 무력화할 수 있습니다.

입력값 검증 방법은 크게 두 가지로 나눌 수 있습니다.

  • 블랙리스트 검증

    각종 문자열들을 차단하는 방법이다. 일부 공격을 간단하게 막을 수 있는 장점이 있지만, 알려지지 않은 공격은 차단할 수 없다. 공격자가 인코딩 등의 방법으로 차단 방법을 우회하는 것도 종종 가능하다. 정상적인 문자열인데 공격으로 판단하는 오탐(false-positive)의 가능성도 있다.(예. ' 작은 따옴표 특수문자를 차단하는 룰을 적용할 때 It's와 같은 일반 문자열도 차단.)

  • 화이트리스트 검증

    입력값이 웹 애플리케이션이 필요로 하는 데이터의 형식과 일치할 때만 허용하고 그 외의 모든 입력값을 차단하는 방법이다. 오직 필요로 하는 값만 허용하여 처리하게 되므로 알려지지 않은 공격으로부터도 안전하며 우회 기법을 찾기가 어려워 보안성이 높다.

화이트리스트 검증의 몇 가지 예는 다음과 같습니다.

  • 숫자를 입력받는 폼에서는 입력된 데이터가 숫자 형태인지 검증하여 허용 한다.
  • 알파벳 문자를 입력받아야 되는 경우라면, 알파벳 문자 범위의 입력만 허용한다.
  • 특수문자를 입력받아야 하는 경우에는, 꼭 필요한 특수문자만 허용하도록 한다.
  • 그 밖에도 날짜, IP 주소, 전화번호 등과 같이 특정한 형태의 데이터가 입력되는 파라미터에 대해서는, 정규식 검사 등의 방법을 통하여, 적합한 형태의 데이터인지 검증한다.

대부분의 경우 화이트리스트 검증 방식의 입력값 검증을 구현하는 것이 편의성이나 기능 면에 있어서는 까다로울 때가 많으나, 보안 측면에서는 보안성이 높아 권장됩니다.

암호화

공격자에게 노출되지 않아야 하는 중요한 데이터는 암호화 과정을 통해 보호할 수 있습니다. 데이터는 다음과 같이 전송 중인 데이터와 저장된 데이터 두 종류로 구분 할 수 있습니다.

  • 전송 중인 데이터(data in transit)

    인증에 사용되는 사용자의 패스워드나 세션 토큰 등은 네트워크를 통해 전송됩니다. 웹을 통해 전송되는 데이터를 암호화하기 위해서는 SSL/TLS(HTTPS) 프로토콜을 사용합니다. 이렇게 하여 중요한 데이터가 네트워크 스니핑에 의해 노출되는 것으로부터 보호할 수 있습니다. 따라서 로그인 과정은 반드시 HTTPS 프로토콜로 구현해야 합니다. Oauth나 REST API를 이용한 웹 서비스와 같이 세션 토큰을 이용해서 인증을 하는 경우에는, 세션 토큰이 전달되는 모든 구간에 암호화를 적용하여 세션 토큰이 노출되지 않도록 해야 합니다.

  • 저장된 데이터(data at rest)

    패스워드를 비롯한 중요한 데이터를 디스크에 저장해야 하는 경우에도 데이터를 암호화하여 저장해야 합니다. 호스트나 데이터베이스가 공격자에 의해 접근되더라도 암호화를 통해 쉽게 데이터의 내용을 알아낼 수 없도록 보호할 수 있습니다. 암호화를 할 때에는 검증된 표준 알고리즘, 프로토콜, 암호 키를 사용해야 합니다. 암호화를 할 때에는 검증된 표준 알고리즘, 프로토콜, 암호 키를 사용해야 합니다. 암호화에 사용되는 매커니즘은 수많은 전문가들에 의해 수학적으로 검증된 메커니즘이어야 합니다. 만일 개발자가 자체적으로 암호화를 수행할 경우, 쉽게 복호화될 수 있음을 명심하기 바랍니다. 또한 잘 알려져 있는 해시 알고리즘 중에서 md5와 SHA-1 알고리즘은 더 이상 안전하지 않습니다. 최소한 SHA-256이나 SHA-3 계열 이상의 알고리즘을 사용해야 합니다.

로깅과 모니터링

일부 공격은 공격 과정에서 비정상적인 로그를 기록하거나 네트워크 트래픽의 변화를 가져오기도 합니다. 로깅과 모니터링을 적절하게 수행한다면 이러한 비정상적인 변화를 감지하여 스캐닝과 같은 자동화 공격이나, APT 공격과 같은 공격 시도를 사전에 탐지하고 절절한 대책을 마련할 수 있습니다.

OWASP Top 10

OWASP TOP 10의 OWASP(Open Web Application Security Project, 오픈 웹 애플리케이션 보안 프로젝트)는 소프트웨어의 보안성을 높이기 위해 설립된 단체이며 다양한 프로젝트 형태로 특히 웹과 애플리케이션 보안과 관련하여 많은 참고 문서와 툴을 제공합니다.

OWASP는 프로젝트의 규모와 가치가 높은 순으로, 크게 플래그십 프로젝트, 랩 프로젝트, 인큐베이터 프로젝트로 나누어 분류하는데, OWASP의 전체 프로젝트는 OWASP 홈페이지에서 확인할 수 있습니다.

https://www.owasp.org

OWASP Top 10 개요

OWASP의 많은 프로젝트 중에서 OWASP Top 10 프로젝트는 플래그십 프로젝트중의 하나입니다. OWASP Top 10 프로젝트는 웹 애플리케이션의 가장 심각한 보안 리스크 10개를 정리하여 공유하는 프로젝트입니다. 이 리스크들은 전 세계의 다양한 보안 전문가가 참여하여 3~4년 주기로 선정됩니다.

OWASP Top 10에 선정된 리스크는 선정 시점에 가장 많이 발생한 리스크일 수도 있고, 공격의 영향력이 가장 큰 리스크일 수도 있습니다. 이 두 가지 요소를 조합하여 가장 심각하다고 판단되는 리스크를 선정하게 됩니다. 즉 리스크 모델은 다음과 같이 공격의 발생가능성과 영향력의 조합으로 표현할 수 있습니다.

리스크(risk) = 발생가능성(likelihood) * 영향력(impact)

발생가능성과 영향력을 더 세분화하여 OWASP Top 10은 공격가능성, 확산 정도, 탐지가능성, 영향력 이 네 가지의 기준을 정하여 평가합니다. 각각의 평가된 점수를 이용하여 최종 리스크 점수를 산정하고 점수가 높은 순으로 10개의 리스크를 선정합니다.

OWASP은 웹 애플리케이션을 개발하는 모든 기업이 웹 보안을 위해 OWASP Top 10을 고려하여 개발할 것을 권장하고 있는데, 실제로도 웹 애플리케이션을 개발하는 많은 기업들이 그렇게 하고 있습니다. 보안 전문 기업에서도 물론 OWASP Top 10을 실무에 적용하고 활용하고 있습니다. 예를 들면 보안컨설팅 회사들은 웹 애플리케이션을 대상으로 모의해킹 등의 보안컨설팅 서비스를 수행할 때 OWASP Top 10에 선정된 리스크를 중요하게 점검하며, 웹 방화벽을 개발하여 판매하는 웹 보안 회사는 OWASP Top 10과 관련된 웹 보안 기능을 따로 분류하여 제공하기도 합니다.

참고 OWASP Top 10의 리스크에 포함되지 않았다고 하더라도, 보안에 위협을 줄 수 있는 취약점은 여전히 많습니다. OWASP Top 10 2013 버전까지는 포함되어 있다가 2017에서 순위 밖으로 밀려난 CSRF 취약점 같은 것이 대표적인 예입니다. 파일 업로드 취약점 등도 여전히 실무에서 중요하게 다루어지는 취약점 입니다. 웹 애플리케이션들 중에는 수년 전부터 개발되어 현재까지 운영되는 애플리케이션들도 많이 있는데, 이 경우 과거에 심각하게 다루어졌던 취약점들이 여전히 존재할 수 있습니다. 따라서 OWASP Top 10은 트렌드를 파악하는데 참고자료로 활용하고, 보안을 위해서는 OWASP Top 10 항목 이외에도 여러 가지 다양한 취약점들의 존재 가능성을 숙지하고 이에 대한 보호 대책을 종합적으로 수립해야 합니다.

OWASP Top 10은 보안 종사자 외에도, 개발자와 관리자 등 웹과 관련된 모든 사람들이 필수적으로 고려해야 하는 중요한 내용입니다. OWASP Top 10 문서의 후반부를 보면, 각 담당자들이 OWASP Top 10을 숙지한 이후 지속적인 보안을 위해 고려해야 할 내용이 다음과 같이 정리되어 있습니다.

담당자별 OWASP Top 10 숙지 후 역할
담당자 지속적인 보안을 위한 역할
개발자 반복적인 보안 프로세스와 표준 보안 통제 사용 및 구축
보안 테스터 지속적인 애플리케이션 보안 테스트
조직 즉각적인 애플리케이션 보안 프로그램 구축
애플리케이션 관리자 전체 애플리케이션 라이프사이클 관리
OWASP Top 10 2013과 OWASP Top 10 2017의 비교

OWASP Top 10 2017은 OWASP Top 10 2013이 공개된 후 4년 만에 새롭게 공개되었는데, 이전 버전은 2013년 버전과의 비교를 통해 웹 보안의 최신 트렌드를 관찰해볼 수 있습니다. 다음 표는 두 버전의 내용을 간단하게 정리하여 보여주고 있습니다.

OWASP Top 10 2013과 2017 비교 - OWASP Top 10 2017 한글 문서에서 발췌

OWASP Top 10 2013 OWASP Top 10 2017
A1 - 인젝션 A1:2017 - 인젝션
A2 - 취약한 인증과 세션 관리 A2:2017 - 취약한 인증
A3 - 크로스 사이트 스크립팅(XSS) A3:2017 - 민감한 데이터 노출
A4 - 안전하지 않은 직업 객체 참조 A4:2017 - XML 외부 객체(XXE)
A5 - 잘못된 보안 구성 A5:2017 - 취약한 접근 통제
A6 - 민감한 데이터 노출 A6:2017 - 잘못된 보안 구성
A7 - 기능 수준의 접근 통제 누락 A7:2017 - 크로스 사이트 스크립팅(XSS)
A8 - 크로스 사이트 요청 변조(CSRF) A8:2017 - 안전하지 않은 역직렬화
A9 - 알려진 취약점이 있는 구성요소 사용 A9:2017 - 알려진 취약점이 있는 구성요소 사용
A10 - 검증되지 않은 리다이렉트 및 포워드 A10:2017 - 불충분한 로깅 및 모니터링

2013년에 선정된 리스크 중에서 A1 인젝션, A2 취약한 인증, A3 크로스 사이트 스크립팅, A5 잘못된 보안 구성, A6 민감한 데이터 노출, A9 알려진 취약점이 있는 구성요소 사용 항목은 다소 순위의 변동은 있지만 여전히 2017년에도 선정되어 있습니다.

2013년 리스크중 A4 알려지지 않은 직접 객체 참조 항목과, A7 기능 수준의 접근 통제 누락 항목은 2017년에서는 A5 취약한 접근 통제 항목으로 병합되었습니다. 큰 범위에서 두 리스크는 모두 접근 통제와 관련이 있기 때문입니다.

다음 세 개의 리스크는 2017년 버전에서 신규로 추가된 리스크 입니다.

  • A4 XML 외부 객체(XXE)
  • A8 안전하지 않은 역직렬화
  • A10 불충분한 로깅 및 모니터링

최근에 자바 언어로 개발된 웹 애플리케이션이 실무에서 많이 사용되고 있습니다. A4 와 A8 리스크는 반드시 자바 프레임워크에서만 발생하는 것은 아니지만 특히 자바 프레임워크에서 많이 발견되는 XXE 취약점과 자바 역직렬화 취약점에 의한 리스크 입니다. 최근의 트렌드가 반영된 것으로 볼 수 있습니다.

2013년 버전에 있었던 두 개의 리스크, A8 크로스 사이트 요청 변조 리스크와 A10 검증되지 않은 리다이렉트 및 포워드 리스크는 2017년 버전에는 더 이상 포함되지 않았습니다. 그러나 더 이상 OWASP Top 10에 포함되지 않았다고 해서 무시해도 되는 것은 아닙니다. 새로운 리스크들이 최근 많은 조명을 받았기 때문에 상대적으로 순위가 밀린 것도 있지만, 실제 운영되는 웹 애플리케이션에는 여전히 해당 리스크가 존재할 수 있다는 사실을 기억해야 합니다.

불필요한 정보 노출 삭제

반드시 필요한 경우가 아니라면, 서버 헤더에 제공되는 정보를 삭제하여 전송하는 것이 좋습니다. 웹 서버 및 웹 프레임워크 중에는 자체적으로 헤더를 삭제하는 기능을 제공하는 경우가 있으니 매뉴얼을 참고하기 바랍니다. 웹 방화벽과 같은 보안 장비를 이용하여 일괄적으로 헤더를 삭제하는 것도 가능합니다.

마찬가지로, 불필요한 기본 설치 파일들과 백업 파일, 테스트 파일은 모두 실제 서비스가 운용되는 환경에는 존재하지 않도록 하여 외부에 노출되는 일이 없도록 점검해야 합니다. 또한 필요에 의해 사용해야 하는 설정 파일 역시 웹을 통해 외부에 공개되지 않도록 주의를 기울여야 합니다.

스캐너/크롤러 차단

스캐너나 크롤러와 같은 자동화된 프로그램으로부터 완전하게 방어하는 것은 불가능합니다. 하지만 적절한 로깅과 모니터링을 통해 어느 정도 공격 시도를 탐지하고 차단할 수 있습니다.

침입 탐지 시스템/침입 방지 시스템(IDS/IPS)이나 웹 방화벽 등의 보안장비를 사용해서도 자동화된 공격을 탐지하고 차단할 수 있습니다. 모니터링과 관련해서 OWASP Top 10 2017 문서의 A10 항목의 내용도 참고하기 바랍니다.

디렉터리 인덱싱 설정 제거

디렉터리 인덱싱은 웹 서버의 설정을 변경하여 대응할 수 있습니다. 아파치의 경우 아파치 설정 파일의 Indexs 옵션을 제거하여 디렉터리 인덱싱으로부터 보호할 수 있습니다. 칼리 리눅스에도 아파치 웹 서버가 설치되어 있는데, /etc/apache2/apache2.conf 파일의 내용을 확인해보면 다음과 같이 표시되는 부분이 있습니다.

그림 2-3-1아파치 디렉터리 인덱싱 관련 설정

171번 줄에 Indexes 옵션이 있습니다. 이 옵션을 제거함으로서 디렉터리 인덱싱이 되지 않도록 설정할 수 있습니다.

IIS 서버의 경우에도 '디렉터리 검색' 옵션을 비활성화함으로써 디렉터리 인덱싱이 되지 않도록 설정할 수 있습니다.

참고임시방편이지만 일부 디렉터리의 디릭터리 인덱싱을 긴급히 차단하고자 한다면, 해당 디렉터리에 임의의 index.html 파일을 생성해주는 방법도 고려할 수 있습니다. 물론 그 이후 제대로 된 설정을 확인한 후 적용해야 합니다.

브루트 포스(brute force) 공격 대응

브루트 포스 공격에는 짧은 시간 내에 일정 횟수 이상 로그인 시도에 실패하면 정해진 시간 동안 로그인하지 못하게 하는 방법으로 대응할 수 있습니다.

참고스마트폰 잠금 화면에서 이러한 방법을 사용합니다. 패턴이나 패스워드를 여러 번 틀리게 입력 하면 일정 시간 동안 기다려야만 다시 입력할 수 있게 되는데, 틀릴 때마다 기다려야 하는 시간이 점점 더 길어집니다.

이와 같이 일정 시간 동안 로그인 시도를 제한하는 방법을 락킹(locking)이라고 합니다. 틀릴 때마다 기다려야 하는 시간이 점점 더 길어집니다. 이 방법을 사용하면 로그인 시도 간격이 길어져서 패스워드를 찾는 데 걸리는 시간이 거의 무한하게 늘어나기 때문에 브루트 포스 공격을 차단할 수 있습니다. 한편 락킹의 부작용도 있습니다. 공격자가 오히려 이 점을 노리고 특정 사용자의 아이디를 사용하여 일부러 틀린 패스워드로 로그인을 여러 번 시도함으로써 그 사용자가 웹사이트를 사용하지 못하게 만들 수도 있습니다. 따라서 락킹을 적용할 때는 신중을 기해야 합니다.

다른 대응 방법으로는 캡챠(CAPTCHA)를 이용하여 흘려쓴 글자나 그림 문자를 로그인 시도 시 입력하도록 하는 방법이 있습니다. 자동화된 프로그램은 알아내기 불가능하지만 사람은 식별할 수 있는 문자나 그림을 이용함으로써 실제 로그인 시도가 사람이 시도하는 것임을 확인하는 것입니다.

이 방법은 실제로도 많이 사용되고 있는데, 일례로 구글 지메일의 경우 처음에는 편의상 캡챠가 포함되지 않은 포그인 기능을 제공하지만 잘못된 로그인 시도가 몇 번 발생하면 프로그램에 의한 브루트 포스 공격인지 확인하기 위해 캡챠 기능이 동작하기 시작합니다. 이 방법을 이용하면 편의성과 보안성이라는 두 마리 토끼를 모두 잡을 수 있습니다.

세션 ID 보호 대책

세션 ID를 보호하기 위해서는 다음과 같은 방법을 고려해야 합니다. 세션 토큰 등 세션 하이재킹이 가능한 정보는 모두 적용됩니다.

  • 세션 ID가 URI를 통해 노출되지 않아야 한다.
  • 세션 ID는 HTTPS 암호화 채널을 통해 전달되어야 한다.
  • 세션 ID를 쿠키로 전달할 경우에는 Secure, HttpOnly와 같은 쿠키 속성을 추가한다.
  • 세션 ID에 유효시간을 적용하여 일정 시간을 지나면 세션 ID를 파기해야 한다. 상황에 따라 세션이 사용되지 않고 일정 시간이 지났을 때 파기하는 방법(idle timeout)과 생성된 후 일정 시간이 지나면 무조건 파기하는 방법(absolute timeout)을 선택 적용한다.
  • 로그아웃이 된 세션 ID는 즉시 파기되어야 한다.
  • 웹 브라우저를 종료하면 자동으로 로그아웃되도록 한다.
  • 세션 ID는 랜덤으로 생성되어야 하며 절대 추측할 수 없는 값이어야 한다.

SQL 인젝션 공격 대응

SQL 인젝션 공격과 같은 모든 파라미터 입력값 조작으로 이루어지는 공격은 입력값 검증을 통해 대응할 수 있습니다. 특히 화이트리스트 검증을 사용하는 것이 더욱 좋습니다. 웹 보안 - 웹 보안을 위한 공통 고려사항의 입력값 검증 섹션을 참고하기 바랍니다.

이와 더불어 SQL 인젝션 공격은 시큐어 코딩을 통해 좀 더 구체적으로 대응할 수 있습니다. 목적은 사용자가 입력한 값은 SQL 쿼리문에서 오직 데이터로만 사용되어야 하지 SQL 쿼리문의 구조에 영향을 줄 수 없도록 해야 합니다. 다음과 같은 형태의 쿼리문은 $id의 입력값이 SQL 쿼리문을 조작할 수 있기 때문에 SQL 인젝션에 취약합니다.

$query = "SELECT first_name, last_name FORM users WHERE user_id = '$id';"

예방책은 쿼리문을 구성하고 실행하는 방법을 파라미터 쿼리(parameterized query)로 변경하는 것입니다. PHP 언어에서의 파라미터 쿼리 구현 예는 다음과 같습니다.

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

// Get input
$id = $_GET[ 'id' ];

// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
미리 실행할 쿼리문의 형태를 작성해두고 있습니다. 이것을 프리페어도 스테이트먼트(prepared statement)라고도 합니다.
$data->bindParam( ':id', $id, PDO::PARAM_INT );
사용자 입력값이 들어갈 id 부분은 bindParam()에서 설정되도록 하고 있습니다. 이 경우 사용자가 입력한 값이 쿼리문의 일부가 될 수가 없고 온전히 데이터로만 처리 되기 때문에 or이나 UNION 등과 같은 키워드가 입력되어도 무의미한 문자열이 됩니다. 결과적으로 사용자가 SQL 쿼리문을 조작할 방법이 없어 SQL 인젝션 공격을 효과적으로 방지할 수 있습니다.
$data->execute(); $row = $data->fetch(); ... 이하 생략 ...

자바의 prepareStatement() 함수나 닷넷의 SqlCommand() 함수 등 다른 프로그래밍 언어에서도 파라미터 쿼리와 관련하여 제공하는 함수가 있으니 참고하기 바랍니다.

커맨드 인젝션 공격 대응

커맨드 인젝션 공격 대응 방안으로 가장 좋은 방법은 직접적으로 시스템 명령어를 호출하지 않는 것입니다. 소스코드 레벨에서는 exec()이나 system()과 같은 직접적으로 명령어를 실행하는 함수를 사용하지 않고, 대신 프로그래밍 언어 및 라이브러리에서 자체적으로 제공하는 함수를 사용하는 것을 권장합니다. 예를 들면 디렉터리 이름을 사용자로부터 입력받아 그 이름으로 디렉터리를 생성해야 할 필요가 있는 경우, system("mkdir $dir_name")으로 구현하는 것이 아니라 mkdir($dir_name)과 같이 구현하는 것입니다. 이렇게 하면 위의 특수문자와 함께 악의적인 명령어가 입력되더라도 실행되지 않게 됩니다.

시스템 명령어를 사용할 수밖에 없는 경우에는 사용자 입력값이 명령어에서 사용될 수 없도록 확실히 점검해야 합니다. 소스코드 리뷰 과정에서 exec()이나 system()같은 함수들을 검색하여 커맨드 인젝션 취약점을 미리 발견하여 조치를 취할 수 있습니다.

또한 적절한 입력값 검증으로도 커맨드 인젝션 공격으로부터 보호할 수 있습니다. (웹 보안 - 웹 보안을 위한 공통 고려사항의 입력값 검증 섹션을 참고하기 바랍니다.) 블랙리스트 검증으로도 어느 정도 차단이 가능하지만 가급적 화이트리스트 검증 방식을 사용할 것을 권장합니다.

크로스 사이트 스크립팅 공격 대응

웹 해킹에서 스토어 크로스 사이트 스크립팅 공격을 실습한 후, 스토어드 크로스 사이트 스크립팅 실습 페이지의 방명록을 다시 접속해보면, 이전 상황처럼 스크립트 코드가 실행되는 것이 아니라 스크립트 태그를 비롯한 입력 내용이 웹 페이지에 제대로 보입니다.

그림 6-1-1스크립트가 실행되지 않고 화면에 표시만 된다.

크로스 사이트 스크립팅 공격에 대응하기 위해서는, 지금처럼 스크립트가 입력되어도 그것이 실행되지 않도록 하고 단순히 문자열로 표시하도록 만드는 것이 가장 좋은 방법입니다.

소스코드 레벨에서 어떻게 구현되어 있는지 확인해 보겠습니다.

그림 6-1-2스토어드 크로스 사이트 스크립팅 임파서블 단계의 소스코드

소스코드의 내용 중에서 다음 부분을 주목합니다.

$message = htmlspecialchars( $message );

htmlspecialchars() 함수는 &, ", ', <, >와 같은 특수문자들을 HTML 엔티티로 변환해주는 함수입니다. 예를 들어 < 를 로, > 를 로 변환해 줍니다. <script> 태그의 경우 script로 변환이 됩니다. 이렇게 변환된 문자열은 웹 브라우저가 읽더라도 더 이상 스크립트로 처리하지 않게 됩니다. 그러나 비록 스크립트로처리하지 않더라도, 화면에 표시할 때에는 웹 브라우저가 원래의 특수문자로 보여주기 때문에 사용자는 <script>와 같이 원래 문자열대로 읽을 수 있게 됩니다.

참고htmlspecialchars()이 그밖의 다른 특수문자를 어떻게 HTML 엔티티로 변환하는지에 대해서는 다음 php 사이트 공식 설명을 참조하세요.

마찬가지로 리플렉티드 크로스 사이트 스크립팅 공격 역시 이와 같은 방법으로 대응할 수 있습니다. 이렇게 크로스 사이트 스크립팅 공격을 막기 위해서는 사용자 입력값을 웹 페이지에 출력할 때 지금처럼 특수문자들을 제대로 변환시켜 주어야 합니다. 대부분의 웹 프로그래밍 언어가 이름은 다르지만 htmlspecialchars() 함수와 동일학 역할을 하는 빌트인 라이브러리나 함수를 제공합니다.

입력값 검증을 통해 파라미터의 입력값에 불필요한 문자열이 포함되지 않도록 하는 것 역시 공격을 차단할 수 있으므로 권장됩니다.

크로스 사이트 요청 변조(CSRF) 공격 대응

참고인터넷을 사용하는 개인 입장에서 CSRF 공격을 당하지 않으려면, 피싱 공격의 위험에 항상 주의를 기울여야 합니다. 모르는 사용자가 보낸 이메일을 함부로 열지 않거나, 이메일의 내용이나 게시판 등에서 링크를 누르기 전에 항상 URL을 확인하는 습관을 갖는 것이 좋습니다. 리플렉티드 크로스 사이트 스크립팅 공격이나, 바이러스 등의 악성 코드로부터도 안전해질 수 있는 좋은 습관입니다.

그림 6-3-4패스워드를 hacker로 변경하는 요청이 전송된다.

CSRF 공격에 대응하기 위해서는 일반적으로 다음의 두 가지 방법을 사용합니다.

  1. 요청 메시지의 레퍼러(Referer) 헤더를 검사하여, 웹 메일이나 타 사이트에서 피싱을 당해 전송되는 요청을 실행하지 않는다. 레퍼러 헤더는 해당 요청을 링크하고 있던 이전 웹 페이지의 주소를 알려주는 헤더이다. 예를 들어, 그림 10-7 요청의 레퍼러 헤더의 값이 http://localhost/csrf.html 이라고 되어 있다. 우리가 실습할 때 해당 경로의 파일로부터 링크를 클릭했기 때문이다. 만일 피싱에 의한 것이 아니라 정상적인 경로로 패스워드 변경 요청이 되었다면 레퍼러 헤더에는 DVWA 사이트 내부의 URL이 표시되었을 것이다. 따라서 레퍼러 헤더를 확인하여 요청을 전송시킨 출처 페이지를 확인한 후 정상적인 요청인지를 판별할 수 있게 된다.
  2. CSRF 토큰을 사용한다. 쿠키 외에 공격자가 추측할 수 없는 값이 요청 메시지의 파라미터 등에 포함되어 있다면 공격자는 CSRF 공격을 성공시키기 어려워진다. 이때 CSRF 공격 대응을 위해 포함시키는 랜덤한 값을 CSRF 토큰이라고 한다. CSRF 토큰을 이용한 대응 방식은 다음과 같이 구현할 수 있다.
    • 먼저 웹 애플리케이션이 CSRF 토큰을 매 응답마다 랜덤하게 생성하여 히든 폼 필드 등을 통해 클라이언트로 보낸다.
    • 클라이언트는 이전 응답 메시지에 포함된 토큰 값을 다음 요청 시 포함 시켜 전송한다.
    • 웹 애플리케이션이 CSRF 토큰 값을 검사하면, 정상적인 과정을 통해 전달된 요청인지 확인할 수 있다.

보안 레벨을 하이 단계로 설정하면 CSRF 토큰이 어떻게 사용되는지 직접 확인할 수 있습니다. 하이 단계의 실습 페이지에 접속한 후 소스코드를 보면 user_token이라는 히든 타입의 폼 필드가 있습니다.

view-source:http://192.168.75.131/dvwa/vulnerabilities/csrf/
<div class="body_padded"> 
	<h1>Vulnerability: Cross Site Request Forgery (CSRF)</h1> 
	
	<div class="vulnerable_code_area"> 
		<h3>Change your admin password:</h3> <br />

		<form action="#" method="GET"> 
			New password:<br /> 
			<input type="password" AUTOCOMPLETE="off" name="password_new"><br /> 
			Confirm new password:<br /> 
			<input type="password" AUTOCOMPLETE="off" name="password_conf"><br /> 
			<br /> 
			<input type="submit" value="Change" name="Change"> 
			<input type='hidden' name='user_token' value='b5c064e69d2762d8199dd4a01ff7fa32' /> 
		</form> 
	</div>

14번째 줄을 보면 user_token이 표시됩니다. value로 지정된 문자열이 웹 애플리케이션이 랜덤하게 생성한 CSRF 토큰 역할을 합니다. 이제 패스워드 변경 요청을 보내면 CSRF 토큰이 user_token 파라미터를 통해 전달되게 됩니다.

그림 6-3-5웹 페이지에서 전달받은 CSRF 토큰 값이 user_token 파라미터로 전송된다.

웹 애플리케이션은 CSRF 토큰이 자기가 생성한 문자열이 맞는지 확인하여 정상적인 요청인지 아니면 CSRF 공격에 의한 요청인지 구별할 수 있습니다. 이 방법을 이용하여 CSRF 공격에 대응할 수 있습니다.

그런데 만일 동일한 웹사이트에 크로스 사이트 스크립팅 취약점이 존재하면 CSRF 공격과 크로스 사이트 스크립팅 공격을 조합하여 위 두 가지 대응 방법을 모두 무용지물로 만들 수도 있습니다.

POC 코드에는 자바스크립트가 사용되었는데, 임의의 자바스크립트를 실행할 수 있는 크로스 사이트 스크립팅 공격을 이용하여 POC 코드와 같이 요청을 전송시키면 이때의 레퍼러 헤더는 크로스 사이트 스크립팅 취약점이 있는 DVWA가 되기 때문에 레퍼러 헤더 검사를 우회할 수 있게 됩니다. 또한 자바스크립트를 이용하면 CSRF 토큰을 알아낸 것도 가능합니다.

패스워드 변경과 같은 중요한 기능을 실행할 때 CSRF공격 대응에 가장 좋은 방법은 기존의 패스워드를 다시 한 번 입력받도록 하여 사용자 본인이 직접 기능을 실행하는지 확인하는 것입니다. 아마 본인이 이용하는 사이트 중에서도 패스워드를 변경할 때 기존 패스워드를 같이 입력받는 경우를 종종 본 적이 있을 것입니다. 이 때에는 공격자가 사용자의 기존 패스워드를 알 수 없기 때문에 CSRF 공격을 할 수 없습니다.

파일 인클루전 공격 대응

파일 인클루전 공격에 대응하는 가장 좋은 방법은 외부 사용자가 입력한 파일 이름을 인클루드에 사용하지 않는 것입니다. 어쩔 수 없이 파일의 이름을 외부에서 입력 받아야 하는 경우에는 반드시 그 입력값을 검증해야 합니다. 웹 보안 - 웹 보안을 위한 공통 고려사항 - 입력값 검증 섹션을 참고하기 바랍니다.

가급적 화이트리스트 검증을 사용하여, 인클루드가 필요한 파일 이름의 목록을 작성하여 해당 파일들만 허용하고 나머지 파일 이름에 대해서는 모두 차단해야 합니다. 블랙리스트 검증의 경우에는 http://, https:// 와 같은 프로토콜 관련 문자열이나, ../ 와 같은 디렉터리 드래버설 공격을 위한 문자열을 차단하여 파일 인클루전 공격에 대응할 수 있습니다.

파일 업로드 공격 대응

파일 업로드 공격의 대응 방법은 다음과 같이 정리할 수 있습니다.

  • 꼭 필요한 파일 형식만 업로드되도록 파일의 확장자와 내용을 검사한다. 파일의 확장자만 검사하는 경우, 파일의 실제 내용을 확장자와 다르게 전송함으로써 우회할 수 있으니 파일의 내용까지 일부 검사하여 파일의 종류를 확실하게 검사해야 한다.
  • 업로드된 파일을 사용자가 접근 불가능한 경로에 저장한다. 파일 업로드를 위한 별도의 서버를 구축하고 웹 애플리케이션을 서비스하는 서버와 완전히 분리하는 것도 좋다.
  • 파일이 업로드되는 디렉터리의 실행 권한을 제거한다.
  • 업로드된 파일을 다른 확장자로 변경한다. 예를 들어, 실습에서 사용된 php 확장자 파일의 php 확장자를 제거하거나 변경하여 저장하면, 해당 파일의 경로로 접속하더라도 php 코드가 실행되지 않도록 할 수 있다.
  • 업로드된 파일의 이름을 랜덤으로 재생성하여 저장한다. 공격자가 자신이 업로드한 파일의 경로를 추측하지 못하게 한다.

그런데 웹 애플리케이션에 파일 인클루전 취약점이 존재하면 일부 대응 방법을 우회할 수 있습니다. 따라서 파일 인클루전 취약점으로부터의 보호를 위해 (웹 보안 - 파일 인클루전 공격) 섹션도 참고하길 바랍니다.

민감한 데이터 노출 대응 방안

HTTPS 프로토콜

HTTP 프로토콜로 전달되는 데이터는 공격자에게 쉽게 노출될 수 있기 때문에, 로그인과 같은 중요한 기능은 HTTPS 프로토콜을 이용하여 데이터가 암호화되어 전송되도록 구현해야 합니다. 요즘에는 전체 사이트를 HTTPS 프로토콜을 이용하여 암호화하는 경우도 많이 있습니다.

참고HTTPS를 사용하면 HTTP를 사용했을 때보다 더 많은 데이터가 전달되기 때문에 성능이 떨어지게 됩니다. 과거에는 이러한 성능 문제로 필요한 부분만 HTTPS로 구현했지만, 최근에는 SSL/TLS 가속 기술의 발달로 웹사이트의 모든 페이지를 HTTPS 프로토콜로 구현하는 추세입니다.

HTTPS와 HTTP를 같이 사용하도록 개발된 웹사이트의 경우, HTTPS에서 HTTP 프로토콜로 전환될 때 민감한 데이터가 전송되지 않도록 각별히 기울여야 합니다.

웹 스토리지 보호 대책

앞에서 실습을 통해 확인한 것처럼 민감한 데이터를 로컬 스토리지에 저장하는 것은 위험합니다. 어쩔 수 없이 민감한 데이터를 클라이언트로부터 전달받아야 하는 경우에는, 민감한 데이터를 쿠키를 통해 전달하도록 하고 해당 쿠키에 HttpOnly 플래그를 추가해야 합니다. 이렇게 하면 자바스크립트로 해당 쿠키를 읽지 못하기 때문에, 웹 애플리케이션에서 크로스 사이트 스크립팅 취약점이 발견되어 공격을 당하더라도 민감한 데이터를 보호할 수 있습니다. HttpOnly 플래그에 대해서는 1장의 HTTP 응답 메시지 - 응답 헤더 - Set-Cookie 섹션을 참고하기 바랍니다.

검증된 암호화 사용

민감한 데이터를 저장할 때에는 데이터들을 암호화하여 저장해야 합니다. 암호화와 관련해서는 2장의 암호화 섹션의 내용을 참고하기 바랍니다.

IDOR 공격 대응

IDOR에 대한 보호 대책으로, 웹 애플리케이션은 사용자로부터 전달되는 모든 입력 값을 신뢰해서는 안됩니다. 사용자 입력값이 원래 의도대로 전달된 정상적인 값인지 입력값 검증을 거쳐야 합니다. 2장의 입력값 검증 섹션을 참고하기 바랍니다. 화이트리스트 검증이 가장 좋습니다.

또한 앞선 실습의 가격 정보처럼 굳이 클라이언트로부터 전달받을 필요가 없는 정보는 웹 애플리케이션 내부에서 직접 설정하여 불필요한 파라미터 조작 가능성을 원천 차단해야 합니다.

관리자 페이지 우회 공격 대응

관리자 페이지 인증 우회에 대한 대응 방법으로, 서버가 제공하는 모든 기능에는 각 기능을 요청하는 사용자가 해당 기능을 실행할 수 있는 적절한 권한을 가지고 있는지 확인하는 루틴이 구현되어야 합니다. 특히 관리자 기능이나 RBAC(Role Based Access Contol, 롤 기반의 접근 제어) 기능이 구현되어 있다면 더욱더 철저한 검증이 필요합니다.

/admin/과 같이 누구나 쉽게 추측할 수 있는 디렉터리를 사용하는 것도 지양하는 것이 좋습니다. 관리자 인터페이스를 별도의 포트 번호에서 제공하는 것도 좋습니다. 관리자 메뉴는 HTTPS 프로토콜을 이용하도록 구현하여 전송되는 데이터가 노출되지 않도록 해야 합니다.

추가적으로 보안성을 높이고자 한다면, 웹 애플리케이션 외부적으로 특정 IP 범위를 지정하여, 지정된 사용자만 관리자 메뉴에 접근할 수 있도록 접근 통제를 구축하는 것도 고려할 수 있습니다.

디렉터리 드래버설 공격 대응

디렉터리 트래버설 공격으로부터 보호하기 위해서는 IDOR 공격 대응과 마찬가지로 적절할 입력값 검증을 수행해야 합니다. 가급적이면 화이트리스트 방식의 검증이 더 좋지만, 경우에 따라 화이트리스트 검증이 불가능한 경우, ../와 같은 문자열을 차단하는 블랙리스트 검증을 사용할 수도 있습니다. 이 경우 http:// 와 같이 프로토콜 이름이 입력되는 것 역시 차단하여 원격에 있는 파일이 지정하는 것도 차단해야 합니다.

XXE 공격 대응

XXE 공격의 원천적인 대응 방법은, 외부 엔티티 참조 기능이 필요하지 않은 경우 DTDs나 외부 엔티티 관련 설정을 비활성화 화는 것입니다. 설정을 비활성화하는 방법은 프로그래밍 언어나 XML 파서의 종류에 따라 다릅니다. 주요 언어별 설정법은 아래 OWASP 문서 링크에 잘 정리되어 있으니 참고하기 바랍니다.

https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet

시스템 운영자나 보안 관리자 관점에서는 ENTITY 태그가 요청 메시지를 통해 전달되는 것이 확인되면 일단 주의를 기울이고, 원래 의도된 요청인지 확인하는 것이 필요합니다. 서비스 중인 웹 애플리케이션에서 XML 외부 엔티티 기능을 사용할 필요가 없다면, 웹 방화벽 등의 장비를 이용하여 해당 메시지를 차단하는 것이 좋습니다.

알려진 취약점 공격 대응

취약한 소프트웨어를 최신 버전(또는 취약점이 수정된 버전)으로 업데이트함으로써 이에 대응할 수 있었습니다. 예를 들어 하트블리드 취약점은 OpenSSL 1.0.1g 이상의 버전으로 업데이트하여 해결할 수 있습니다. 쉘쇼크 취약점은 bash43-027 이후 발표된 최신 버전의 bash를 사용함으로써 해결할 수 있습니다. PHP-CGI 취약점 역시 마찬가지로 5.3.12와 5.4.2 이후의 최신 PHP 버전으로 업데이트하여 해결할 수 있습니다.

운영체제에서 제공하는 구성 요소에 취약점이 존재하는 경우에는, 사용자가 개별 패키지를 직접 컴파일하여 업데이트하지 않더라도, 대다수의 운영체제가 자동 업데이트 방식을 포함하여 패키지 업데이트를 위한 방법을 별도로 제공하고 있습니다. (예. 마이크로소프트, 레드햇 보안 업데이트). 이에 대해서는 운영체제의 문서 등을 통해 확인하기 바랍니다. 하나의 시스템에는 수많은 패키지들이 설치되어 운영하는데 취약점이 발생할 때마다 일일이 취약점 정보를 찾아 해결하는 것은 불가능한 일입니다. 따라서 시스템을 항상 최신 업데이트 상태로 유지하는 것이 좋습니다.

참고리눅스의 경우 배포판에 따라 패키지를 업데이트하기 위한 명령어가 다릅니다. 레드햇, 페도라, 센트OS는 yum 명령어로, 우분투, 데비안 사용자는 apt-get 명령어를 이용하여 패키지를 업데이트할 수 있습니다.

개발 프로젝트에서 상용 소프트웨어를 사용하는 경우에는 해당 개발사 및 유통사를 통해 관리는 받을 수 있겠지만, 오픈소스를 사용하는 경우에는 각 오픈소스에 대한 관리가 필요합니다. 오픈소스의 구성요소를 분석하여 나열하고, 모니터링하며, 항상 최신 패치가 적용될 수 있도록 관리하는 프로세스가 정립되어 있어야 합니다.

알려진 취약점을 찾기 위한 소프트웨어중 하나인 OWASP Dependency-Check를 이용하면 개발 프로젝트(주로 자바 프로젝트) 내에서 사용하는 오픈소스 라이브러리(dependency, 의존 라이브러리)들을 찾고, 각 라이브러리의 알려진 취약점 정보를 확인할 수 있습니다.

알려진 취약점을 찾기 위한 또 하나의 유용한 소프트웨어인 IoTcube는 고려대학교 산하 연구센터인 CSSA(소프트웨어 보안 국제공동연구센터)에서 개발한 보안 취약점 분석 플랫폼으로, 보안 취약점을 발견하는데 유용하게 사용할 수 있는 기능을 여러 가지 제공합니다. 그중에서도 취약한 코드 클론 탐지 기능은 C/C++ 기반 오픈소스의 알려진 취약점(CVE; Common Vulnerability Exposure)들의 소스코드를 분석하여 이와 유사한 코드가 개발 프로젝트에서도 사용되고 있는지 검사해주는 기능을 제공합니다.

이와 같은 알려진 취약점을 확인할 수 있는 소프트웨어를 CI/CD에 포함시켜 개발 프로세스 자동화를 구축하는 것도 좋은 방법이 될 수 있습니다. CI/CD는 지속적 통합/지속적 배포(Continuous Integration, Continuous Delivery)의 과정으로, 개발, 테스트, 제품 릴리즈 단계와 같은 소프트웨어 개발에 필요한 단계를 통합하여 관리하는 개발 프로세스를 의미합니다. 전통적인 개발 프로세스에 비해 시간과 비용을 절약하여 제품 출시 주기를 앞당길 수 있으며, 테스트 자동화 등을 통한 제품의 질적 향상도 가져올 수 있습니다.

최근에는 CI/CD보다 광범위한 개념의 데브옵스(DevOps)라는 용어도 많이 사용합니다. 개발(Dev; development)과 운영(Ops; operations)을 통합한 이 데브옵스 과정에서부터 보안을 적용하면, 소프트웨어의 보안성을 저비용 고효율로 확보할 수 있습니다.

자바 역직렬화 취약점 공격 대응

CommonsCollections 패키지를 이용한 공격은 과거의 취약한 CommonsCollections 패키지를 포함하고 있는 모든 자바 프로젝트를 대상으로 시도될 수 있습니다. 따라서 아파치 CommonsCollections 패키지를 최신 버전으로 업데이트하여 공격을 예방해야 합니다. 하지만 일일이 이러한 패키지를 확인하여 업데이트하는 것은 어렵기 때문에, 프레임워크를 비롯한 웹 애플리케이션 개발을 위해 사용하는 구성요소들을 항상 최신 버전으로 유지하는 것을 권장합니다.

만일 개발 프로젝트에서 자체적으로 역직렬화를 수행하는 경우에는 다음과 같은 내용을 고려하여 역직렬화 취약점을 예방할 수 있습니다.

  • 역직렬화 전에 반드시 인증 과정을 수행한다.
  • 출처를 알 수 없는 객체의 경우 역직렬화를 수행하지 않는다.
  • 직렬화된 객체에 디지털 서명이 되도록 하여 역직렬화 과정에서 객체의 변조 여부(무결성)를 점검한다.
  • 가급적 최소 권한으로, 가능하다면 격리된 환경에서, 역직렬화를 수행한다.

캡챠(CAPTCHA)

자동화 공격과 구별하기 위해 사람이 직접 접속하고 있음을 확인하는 시스템 또는 프로그램. 주로 기계가 알아보기 힘든 이미지나 흘려쓴 글씨를 보여주고 응답을 기다려 확인한다.

APT(Advanced Persistent Threat, 지능적 지속 위협) 공격

특정 기업을 공격하기 위해 장기간 동안 들키지 않고 여러 단계의 과정을 거쳐 공격하는 것을 의미합니다. 즉 SQL 인젝션 공격 등과 같은 특정 기술을 이용한 공격을 이용하는 것이 아니라, 다양한 공격 기법을 총동원하여 특정 기업을 공격하는 행위에 더 가깝습니다.