본문 바로가기

보안

웹 개발 보안 체크리스트

반응형

Guide 1. 세션유지를 위해서 Cookie를 사용할경우, 위/변조에 대비해야 한다.


  • 보안 수단없이 쿠키에 인증정보를 저장해서 사용할 경우 해당값들의 위,변조가 가능하며, 이로 인하여 다른 사용자로 위장 또는 권한상승 등의 문제가 생길 수 있다. 따라서 쿠키를 사용할 경우, 쿠키값의 불법 위/변조가 불가능하도록 구현해야 한다.
  • 점검방법 :
    사이트에 로그인한 후, 웹브라우저의 주소창에 javascript:document.cookie; 입력해서 내용을 확인한 후, 해당 세션 쿠키를 사용하는 웹어플리케이션 소스 점검을 통해 불법 변조탐지루틴이 있는지 확인한다.
  • 조치방법 :
    아래 방법들 중에서 가능한 것을 선택해서 적용함.

1) 쿠키값 암호화를 통한 쿠키불법 변조방지(서버에서 전송받은 쿠키를 복호화 한후, 위/변조 되었는지 확인)
2) 쿠키값에 대한 Message Digest(예, MD5, SHA-1 등) 값의 첨부 및 검증을 통한 위/변조탐지 (아래예제참조)
3) 쿠키에 세션값을 저장하는 대신 어플리케이션 서버 세션 사용 (사용하는 웹 어플리케이션 서버가 지원하는지 확인 필요)

<php 예제>

$secret_word = 'lgcard_secret_value';

// 쿠키 설정하기
$id = 'lgcard';
$hash = md5($secret_word . $id);
setcookie('id', $id . '-'. $hash);

// 받은 쿠키가 변조되었는지 확인하기
list($cookie_id,$cookie_hash) = explode('-',$_COOKIE['id']);
if (md5($secret_word.$cookie_id) == $cookie_hash) {
    $id = $cookie_id;
} else {
    die('Invalid cookie !');
}

<asp 예제>

<!--#include virtual="/crypto/MD5.asp"-->
secret_word = "lgcard_secret_value"

// 쿠키 설정하기
id = "lgcard"
hash = md5(secret_word & id);
Response.Cookie("id") = id
Response.Cookie("id_hash") = hash

// 받은 쿠키가 변조되었는지 확인하기
cookie_id = Request.Cookie("id")
cookie_hash = Request.Cookie("id_hash")
If md5(secret_word & cookie_id) = cookie_hash) Then
    'Cookie 값이변조되지않았으므로, 세션ID 값설정
    id = cookie_id
Else
    'Cookie 값이 변조되었기 때문에, 오류처리
End

<jsp예제>

String secret_word = "lgcard_secret_value";

// 쿠키 설정하기
String id = "lgcard";
String id_hash = CryptoUtil.md5(secret_word + id);
Cookie userCookie= new Cookie("id", id + "-"+ id_hash);
Response.addCookie(userCookie);

// 받은 쿠키가 변조되었는지 확인하기
Cookie[] cookies = request.getCookies();
for (int i=0; i<cookies.length; i++) {
    Cookie thisCookie= cookies[i];
    if (thisCookie.getName().equals("id")) {
        String cookie_value = thisCookie.getValue();
        StringTokenizerst = new StringTokenzier(cookie_value, "-");
        String cookie_id = st.nextToken();
        String cookie_hash = st.nextToken();
        if (CryptoUtil.md5(secret_word + cookie_id).equals(cookie_hash)) {
            id = cookie_id;
        } else {
            // Cookie 값이 변조되었기 때문에, 오류처리
        }
    }
    // 다른 쿠키에 대한 처리 루틴
}
  • 쿠키에 대한 Hash 값을만들때, 공격자가 해당 Hash 값을 불법으로 생성하는것을 막기 위해서, 웹 사용자에게 공개 되지않는
    secret_word 값을 함께 사용한다. 이값은 해당 웹어플리케이션에서 사용할 수 있도록 공용 설정 파일 등에 저장해서 사용하는
    것을 권장한다.

Guide 2. 접근제어가 필요한 모든 페이지에 로그인 체크 및 권한 체크를 구현하자.


  • 접근제어가 필요한 페이지 및 모듈들에는 모두 통제수단(로그인 체크, 권한 체크)이 적용되어야 한다. 특히, 하나의 프로세스가 여러 개의 페이지 또는 모듈로 이뤄져 있을때 권한 체크가 누락 되었을 경우, 설정된 접근 권한을 우회해서 트랜젝션을 실행할 수 있는 위험이 존재한다.
  • 점검방법: 소스리뷰
  • 조치방법:
    1) 접근권한이 필요한 모든 페이지/모듈에 해당 루틴 구현
    2) 이를 위해서 공통 모듈을 사용하는 것을 권장한다.

Guide 3. 첨부파일 업로드 기능을 통한 스크립트 업로드 및 실행을 금지하자.


  • 게시판 첨부파일 업로드, 사진 업로드 모듈등 사용자가 임의의 파일을 서버로 전송할 수 있는 기능을 이용해서 공격자가 작성한 악의적인스크립트를 서버에 업로드 한 후, 이를 실행시킬 수 있다면 해당 서버에서 임의의 명령어 실행, Web DB 불법 접근 및 해당 Application Server 와 신뢰 관계를 맺고있는 서버들(예, Web DB서버, 내부 연동서버등)을 공격할 수 있는 위험이 있다. 본 취약점은 게시판 업로드 모듈뿐아니라 그림 파일을 올리는 기능을 통해서도 발견되고 있기 때문에, 사용자가 파일을 업로드 할 수 있는 모든 모듈에 적용된다.
  • 점검방법 : 해당 Application Server 가 지원하는 Script 파일을 업로드한 후, 이를 웹브라우저로 직접 접근해서 실행이 되는지 확인한다.
  • 조치방법

1) 해당 Application Server에서Script로 실행될 수 있는 확장자(예, .jsp, .asp, .php, .inc 등)로된 파일의 업로드를 차단한다.
2) 첨부파일을 웹디렉터리가 아닌 곳에 저장한후, 다운로드 스크립트를 사용해서 사용자에게 전달할 수 있게한다.
3) 다운로드 스크립트를 구성할때, 파일명을 Parameter로 받는것보다 파일이름은 DB에 저장하고 해당index만을 Parameter로
받아서 사용하면 더 안전하다.

※주의사항

1) 확장자를 비교할경우, 대소문자를 무시한 문자열비교를 해야만한다. 이를 적용하지않으면 공격자는
"malcious.Jsp ", "malicious.jSp ", "malicious.jsP " 등과 같은 파일명을 사용해서 통제루틴을 우회할 수 있기 때문이다.
2) 웹어플리케이션 서버에서 실행 스크립트로 설정한 모든 확장자에 대해서 점검해야하며, 이들 확장자 목록은 웹 서버 관리자에게 문의해서 확인해야 한다.


Guide 4. 첨부파일 다운로드 스크립트를 악용한 서버 파일 유출을 방지하자.


  • 첨부파일 다운로드 스크립트에 파일 경로를 포함한 parameter 를 사용할 경우, 원하는 디렉터리를 벋어나서 임의의 파일을 다운로드 할 수 있는 취약점이 있다. 이로 인하여 공격자는 서버의 중요 파일 또는 웹어플리케이션 소스 파일 등에 접근이 가능하다.
  • 점검방법: http://localhost/download.jsp?file=lgsec.txt 와 같이 구현되어있는 웹 어플리케이션이 있다고하자.

1) Application Server가Unix/Linux인경우
http://localhost/download.jsp?file=../../../../../../../etc/passwd 를 입력했을때 Application Server의 /etc/passwd
파일을 획득할 수 없어야 한다.
2) Application Server가 Windows 계열인 경우
http://localhost/download.asp?file=../../../winnt/win.ini 를 입력했을때 win.ini 파일을 획득할 수 없어야 한다.

  • 조치방법 : 사용자로 부터 전송받은 디렉터리 이름, 파일 이름 값에 "../ " 또는 "..\ "이 존재하면 오류처리 한다.

Guide 5. SQL Injection 공격에 대비하자.


  • 사용자로 부터 입력 받은값을 DB query 에 사용할 경우, 공격자는 원하는query 문을 injection할 수 있는 취약점이 있다. 로그인 모듈이 SQL Injection 에 취약할 경우, 사용자의 비밀번호를 몰라도 정상적으로 로그인할 수 있는 위험이 있으며, 게시판 등의 모듈이 취약할 경우 DB 내용이 외부로 유출 또는 임의의 DB Query가 실행될 수 있다.
  • 원리
    ID, PASSWORD를 받아서 로그인 성공 여부를 처리하는 예를 들어보자.
  • id = request("id"); passwd= request("passwd"); query = "SELECT * FROM Member WHERE id = '" + id + "' AND passwd= '" + passwd+ "'";

로 되어있어서 결과 Record 가 있을 경우 회원 로그인 성공처리하는 경우, Id에 ' or 1=1 –- 입력할 경우 비밀번호에 상관없이
다음과 같은q uery가 만들어진다. (여기서 passwd 가 123 으로 입력되었다고 하자)

SELECT * FROM Member WHERE id = ' ' OR 1=1 --' and passwd=  '123'

Oracle DB에서 -- 부분은 주석으로 처리되기 때문에 위 쿼리의 결과는 항상 첫 번째 레코드가 반환되며, 단순하게 레코드 반환 여부만을 점검 하는 식으로 인증이 구현되어 있다면, 로그인이 성공적으로 처리되게 된다. 이를 응용하면 원하는 사용자ID로 로그인이 가능할 수도 있다. 또한 이와같은 원리를 사용해서 사용자 입력값의 조작으로 임의의 DB Query 를 실행시킬 수 있는 위험이 존재한다.

  • 점검방법:

1) 검색어 필드 및 로그인ID, PASSWD 필드에 큰따옴표("), 작은따옴표('), 세미콜론(;) 등을 입력한 후,
DB error가 일어나는지 확인하자.
2) 로그인모듈점검
A. MS SQL인 경우: ID 필드에[ ' or 1=1 ;--], 비밀번호필드에는 아무값이나 입력한 후 로그인을 시도한다.
B. Oracle인 경우: ID 필드에[ ' or 1=1 --], 비밀번호 필드에는 아무값이나 입력한 후 로그인을 시도한다.
C. 기타: ID 필드에[' or ''='], 비밀번호필드에[' or ''=']을 입력한후 로그인을 시도한다.

  • 위 예제 이외에도 다양한 방법이 가능하기 때문에, 로그인 및 사용자 입력 값을 사용하는 소스에서 DB Query 생성 방식을
    직접 점검해야한다.
  • 조치방법

1) 사용자로부터 입력 받은값에 큰따옴표("), 작은따옴표('), 세미콜론(;) 문자가 있으면 이를 제거 또는 사용하는 DB 에
맞게 변환 한 후, DB query 문장에 사용하도록 한다.


Guide 6. Cross-Site Scripting 공격에대비하자.


  • 사용자가 입력한 내용을 기반으로 페이지를 동적으로 생성하는 웹어플리케이션을 악용하면, 해당 페이지를 보는 사용자의
    웹브라우저에서 임의의 코드를 실행할 수 있다. 이는 로그인세션 hijacking, 악성 프로그램 설치등의 client hacking 이 가능하다.
  • 점검방법: 게시판의 제목, 내용 필드 등에 <script>alert( "XSS 취약함 ");</script>입력한 후, 내용을 조회했을 때,
    해당스크립트가 실행되면 취약하다.
  • 조치방법: 사용자로부터 입력받은 내용을 기반으로 페이지를 생성할 경우, "<", "> "는 각각 "<", ">"로 변경한 후 생성한다.

1) PHP 의 경우, htmlspecialchars() 함수를 사용해서 입력받은 값을 변환할수있다.
2) Java 1.4 API 이상

`content = content.replaceAll("<", "&lt;"); // 사용자가입력한내용이content 변수(String 객체)에저장되어있다고가정 content = content.replaceAll(">", "&gt;");`  

3) Java 1.3 API 이하

`intlocation; do { location = content.indexOf('<'); if (location > 0) content = content.substring(0, location) + "&lt;" + content.substring(location+ 1); location = content.indexOf('>'); if (location > 0) content = content.substring(0, location) + "&gt;" + content.substring(location+ 1); } while(content.indexOf('<') != -1 || content.indexOf('>') != -1);`  

* 주의사항 만약 HTML Tag 의 입력을 허용하는 모듈일 경우, 위의 변환 규칙 대신 <script, </script>, <iframe> 을 각각<!--script, </script--!>, <! &#8212;iframe> 으로 변경하며, 이때 대소문자를 무시한 패턴 매칭 (Java 의 경우 String 클래스의 toLowerCase() 및 substring() 사용) 을 적용해야만 한다.

Guide 7. 사용자에게 전달된 값(HIDDEN form 필드, parameter)을 재사용 할 경우 신뢰해서는 안된다.

  • 주로 회원정보변경 모듈에 사용자의 key값(예, id)를 hidden form 필드로 전송한 후, 이를 다시받아서 update에 사용하는 경우가 있는데, 공격자가 이 값을 변경 할 경우 다른 사용자의 정보를 변경할 수 있는 취약점이 존재한다.
  • 점검방법: HTML 소스에서 FORM 필드 확인 후, 해당값이 어떻게 사용되는지를 소스에서 확인해야한다.
  • 조치방법: 해당값의 무결성을 검사 할수있는 루틴(예, 해쉬값비교) 추가 또는 서버세션을 사용한다.

Guide 8. 최종 통제메커니즘은 반드시 서버에서 수행 되어야한다. (Client-Site Security is NOT secure!!)

  • JavaScript, VBScript 등을 사용한 사용자 입력값 점검 루틴은 우회될 수 있기 때문에, 서버에서 최종 점검하는것이 필요하다.
    물론 서버의 부하를 줄이기위해서 1차적으로 클라이언트 레벨에서 점검할 수 있으나, 보안 통제수단으로 사용할 수 없다.
    첨부파일 업로드 기능에 스크립트 파일의 전송 제한하기 위해서 파일 확장자 검사를 script를 사용해서 웹브라우저 레벨에서 수행할 경우, 공격자는 해당 script를 우회해서 서버에 원하는 스크립트 파일을 전송할 수 있다.
  • 점검방법: HTML 및 웹어플리케이션 소스리뷰

Guide 9. 클라이언트에게 중요정보를 전달하지말자.

  • Java Applet, ActiveX 를 사용해서 C/S 어플리케이션을 작성하는 경우, 클라이언트에서 실행되는 컴포넌트에 중요 정보를 하드코딩 해서는 안된다. Cookie 에중요 정보를 전달할 경우, 암호화를 사용해야 한다.
  • 점검방법

1) HTML 소스리뷰
2) URL 주소에javascript:document.cookie; 입력해서 쿠키내용 확인

Guide 10. 중요 정보 전송시 POST method 및 SSL 을 적용해야 한다.

  • 사용자로부터 중요정보를 받을때는 POST method 를 사용해야 하며, 그 중요도에 따라 SSL을 사용한 암호화 통신을 적용해야 한다.
    SSL은 자료전송시 암호화를 지원하므로, 민감한 정보는 어플리케이션 레벨의 암호화를 고려해야 한다.
  • 점검방법: 중요정보전달 FORM ACTION 에 사용된 프로토콜이 "HTTPS", Xecure로 되어있는지 확인함

Guide 11. 중요한 트랜젝션이 일어나는 프로세스에 사용자의 비밀번호를 재확인 하도록 하자.

  • 사용자의 개인정보 변경 프로세스에 비밀번호를 재확인하는 루틴을 추가 할 경우 불법적인 위장으로 인한 추가 피해를 줄일수있다.
  • 점검방법: 해당프로세스 확인

Guide 12. 중요정보를 보여주는 페이지는 캐쉬를 못하게 설정하자.

  • 중요 정보를 보여주는 화면에 no-cache 설정을 하지 않을 경우, 로그아웃을 한 이후에도 [뒤로가기] 버튼을 사용해서 해당 내용을 볼 수 있는 위험이 존재한다.
  • 점검방법: 중요 정보페이지를 열어본 후, 로그아웃을 한다. 웹브라우저의 "뒤로" 버튼을 눌렀을때 이전 내용이 보이는지 확인.
  • 조치방법: no-cache 설정을 위해서 HTML HEAD 부분에 아래내용을 추가한다.
    <meta HTTP-EQUIV="Pragma" CONTENT="no-cache">

Guide 13. 암호화를 올바르게 이해하고 사용하자.

  • 자체개발한 암호화 알고리즘 사용을 지양하며, 공인된 암호화알고리즘(3DES, SEED, AES 등)을 사용하는것을 고려한다.
    암호화키를 사용하지 않는 알고리즘은 암호화 알고리즘이 아니라, 단순 인코딩 알고리즘으로 기밀성을 보장할 수 없다.
    암호화키는 소스에 hard-coding 되어서는 안되며, 제한된 사람만이 접근이 가능하도록 해야 한다.

Guide 14. 관리자 페이지는 내부에서만 접근이 가능하도록 하자.

  • 웹 사이트관리자를 위한 페이지가 존재 할 경우, 외부에서 접근이 불필요하다면 내부 특정 IP 에서만 접근할 수 있도록 통제해야 한다.
  • 이를위해서 특정 Directory 에 관리자 페이지들을 구성하고, 해당 Directory 에 접근 제한을 적용한다.
  • 조치방법: Apache Web Server 를 사용하는 경우 httpd.conf 에 아래 내용을 추가하면 된다.
    (관리자페이지가/lgsec/admin 아래 저장되어 있고, 관리자IP가 192.168.0.101 인 경우)
    <Directory "/lgsec/admin"> Deny from all Allow from 192.168.0.101 </Directory>

Guide 15. 각 언어에서 제공하는 보안수단을 이해한 후 사용한다.

  • Java

1) Java Class 역컴파일 문제
Java 언어의 Byte-code 특성으로 인하여 Java class는 쉽게 역컴파일이 가능하다.
만약 Java Applet 에 중요정보(예, 원격지접속을 위한 ID/PASSWORD, DB Query, 직접 제작한 암호화 알고리즘, 프로그램 로직 등)를 hard-coding 했다면, 이를 발견한 공격자는 해당정보를 악용할 수 있는 위험이 존재한다. 따라서 외부로 전송되는 Java class 파일에는 중요 정보를 hard-coding 하는 것을 지양해야 한다.
2) Secure Code guidelines (Sun Microsystems) - http://www.java.sun.com/security/seccodeguide.html
Sun Microsystems 에서는Java 프로그램 개발시 고려해야 할 다양한 보안사항을 제공하고 있다.

  • ASP(Visual Basic, C++, C# 등을 사용한 모든 ASP 에 적용)

1) include 파일을 보호하자
2) Server.HTMLEncode
- 용도: 특정 문자열에 대한 HTML encoding을 수행한다. 사용자가 입력한 값으로 HTML 페이지를 구성하기 전에 사용하면
Cross-Site Scripting 공격등에 효과적이다.
- 적용가능한IIS : IIS 5.0 이상
- 사용법 : <%= Server.HTMLEncode("<script>alert(document.cookie);</script>") %>
- 결과 : <script>alert(document.cookie); </script>
3) Server.URLEncode
4) Session.Abandon
- 용도: Session 객체에 저장되어 있는 모든 정보를 삭제한다. 사용자 로그아웃 프로세스에 사용해서 기존 세션 정보를
보호하기 위해서 사용할 수 있다.
- 적용 가능한IIS : IIS 5.0 이상
- 사용법 :<% Session.Abandon %>

  • PHP

1) [PHP 4 이상] 환경설정(php.ini) 내용 중 register_global 을 "on"으로 설정할 경우, PHP 스크립트의 변수값을 임의로 변경할 수 있는 취약성이 있다. 따라서 register_global 은"off" 로 설정한 후, $_GET, $_POST 문을 사용해서 사용자가 전달한 값을 얻어야 한다.
register\_global = off
2) PHP 스크립트 오류를 사용자에게 보내지 않기 위해서 PHP 환경설정파일(php.ini)에서 아래와 같이 설정한다.
log\_errors = On
display\_errors = Off
3) utf8_decode()
- 용도 : UTF-8 형식의 입력 값을 ISO-8859-1 형식으로 전환해준다. 필터링 규칙을 적용하기 전에 사용할 것을 권장한다.
- 적용 가능한PHP : PHP 3.0.6 이상
4) strip_tags()
- 용도: 문자열로부터 HTML 태그와 PHP 테그를 없앤다. 사용자가 입력한 값을 HTML 화면에 출력 할 경우 사용해서 Cross-Site Scripting 공격을 대비할 수 있다.
- 적용가능한PHP : PHP 3.0.8 이상
- 사용법
A. strip_tags('<script>');: 모든HTML, PHP 태그를 제거한다.
B. strip_tags('<script>', '<script><iframe>'): 첫 번째 인자로 전달된 문자열에서 두번째 인자로 지정된 태그를 제거한다.
5) htmlspecialchars()
- 용도: 특정문자열에 대한 HTML encoding을 수행한다. 사용자가 입력한 값으로 HTML 페이지를 구성하기전에 사용하면 Cross-Site Scripting 공격대비를위해서사용할수있다.
- 적용가능한PHP : PHP 3 이상
- 사용법 : htmlspecialchars("<a href='test'>Test</a>")
- 결과 : <ahref='test'>Test</a>
6) addslashes()
- 용도: DB Query 와 같이 인용된 부분 앞에 역슬래쉬를 붙여서 반환한다. 해당 문자에는 작은따옴표, 큰따옴표, 역슬래쉬, NULL 이있다. SQL Injection 공격을 위해서 사용한다.
- 적용가능한PHP : PHP 3 이상
7) include 파일을보호하자.
8) session_destroy
- 용도: Session 객체에 저장되어있는 모든 정보를 삭제한다. 사용자 로그아웃 프로세스에 사용해서 기존 세션 정보를 보호하기 위해서 사용할 수 있다.
- 적용가능한PHP : PHP 4 이상

Guide 16. 슈퍼 유저 계정을 사용한 코딩 금지

반드시 필요한 경우가 아니면 관리자 및 슈퍼 유저 계정을 사용하여 코딩을 하여서는 안 되며 개발 초기 단계에서 개발하고자 하는 어플리케이션에 특화된 계정을 사용하여 개발하여야 한다. 예를 들어 SQL 서버에 접속하는 어플리케이션일 경우 'sa' 계정보다는 새로운 사용자 계정을 생성하여 개발하여야 한다.

Guide 17. 버퍼 오버플로우

대부분의 보안 취약점은 버퍼오버플로우 문제로 인해 발생한다. 버퍼오버플로우는 고정된 길이의 버퍼에 값을 쓸 때 버퍼의 경계값을 넘어서면서 발생하게 되는데 사용자 입력 값을 읽을 때나 프로그램 내에서 처리하는 중간에 발생한다.
C언어와 C++언어는 버퍼 오버플로우에 대한 보호기능을 제공하지 않으므로 CGI 프로그램을 작성할 때 아래의 사항들을 준수하여야 한다.

    - strcpy(), strcat(), sprintf(), vsprintf(), gets()와 같은 함수는 경계값을 체크하지 않으므로
      strncpy(), strncat(), snprintf(), fget()과 같은 함수로 대체하여야 한다.

    - realpath(), getopt(), getpass(), streadd() 와 같은 함수의 사용은 자제하고
      최소한의 PATH_MAX 바이트 길이를 정해주는 getwd() 함수를 사용하도록 한다.

    - scanf(), sscanf(), fscanf() 함수 사용시에는 읽어들일 수 있는 최고의 버퍼 길이를 명시해야 한다.
  • 취약한 사용 예
    char buffer[256];
    int num;
    num = fscanf( stdio, "%s", buffer );
  • 안전한 사용 예
    char buffer[256];
    int num;
    num = fscanf( stdio, "%255s", buffer );
- memcpy() 함수를 사용할 경우에는 복사할 대상의 크기를 체크하여야 한다.
  • 취약한 사용 예
    unsigned long copyaddress( struct hosten *hp )
    {
        unsigned long address;
        memcpy( &address, hp->h_addr_list[0], hp->h_length );
    }
  • 안전한 사용 예
    unsigned long copyaddress( struct hosten *hp )
    {
        unsigned long address;
        if ( hp->h_length > sizeof( address ) )
            return 0;
        memcpy( &address, hp->h_addr_list[0], hp->h_length );
        return address;
    }

출처: http://imbyuri.blog.me/110012839564

반응형