ASP 보안

    제목은 "~ script 보안"이라는 거창한 말을 썼지만,
    기본적으로 서버 스크립트 작성시 보안 관련된 부분에 해당하는 항목들을 모아봤습니다.

    1. database 연결 문자열을 web에서 분리

    database connection 연결 문자열을 사용하고 있다면, 이 문자열을 별도의 file로 만들어서 관리해야 합니다. http protocol로 접근이 불가능한 위치에 놓거나 별도의 파일로 만들어 불러써야 한다.

    2. 중복 login 방지

    중복 login 방지를 위한 log table을 DB에 추가하여서 log table에 login된 아이디 record를 삽입, session이 종료되었을 시 session_onend 이벤트를 통해 DB에서 login된 id의 record를 삭제하는 방식.
    그리고, Login ID만이 아니라 IP를 검사하여 동일 사용자 인지 판단, 막는다.

    3. 소스 및 특정 주소 노출 방지

    일반적으로 접근해야 하는 파일들은 모두 perma link를 노출하고 관리하되, sever측에서만 실행되는 파일들은 가능한 한 주소가 노출되지 않도록 하는 것이 좋다. 원천적인 봉쇄는 할 수 없겠지만, 최소한 주소줄에 노출되어 spammer 등의 접속을 도와주는 꼴은 막을 수 있다.
    여기서 주의할 것이 html source를 막는다거나 주소표시줄의 url을 안보이게 하는 것은 불가능하고, 가능한 노출시켜주는 것이 좋으므로 perma link의 노출을 적극적으로 하는 것이 좋다. 다만 서버에서 실행되는 서버측 프로그램은 할 수 있는 한 막는 것이 더 좋겠다고 본다.

    4. login 오류 횟수(submit 횟수) 제한

    login 오류 횟수 제한을 위하여 user의 정보를 저장하는 table에 password 오류 횟수를 체크하는 항목 'user_pchk'을 추가, 'user_pchk' 가 5 이상이 되면 다시 로그인 시도를 할 수 없고 웹 관리자에게 연락해야 하거나 다른 페이지로 redirect되게 함. 또는 일정 시간(10초쯤)이 지난 뒤에 login할 수 있도록 제한.

    5. referer check

    Login 또는 '글쓰기'등 submit이 되는 모든 페이지에서는 referer의 값을 확인하여 정해진 경로이외의 접근을 막는다.
    일반적으로 웹페이지의 구조상 데이터로직을 가지고 있는 페이지는 이전단계에 폼을 갖는 페이지를 거치게 된다. 따라서, 데이터로직 페이지에서는 이전페이지가 개발자에 의해 작성된 페이지인지를 체크하여 외부에서 의도하지 않은 접근이 이루어 지지 않도록 하여야 한다.
    Referer를 체크해야 하는 또 하나의 단편적인 예를 보자. 회원가입 페이지에서 대부분 팝업창을 이용하여 우편번호 검색과 같은 로직을 대부분 갖고 있다. 우편번호 검색페이지와 같이 단순히 SELECT 하는 페이지를 툴을 이용하여 외부에서 끊임없이 호출하는 경우 데이터베이스가 어떤 상황에 처하게 될지 생각해 보라. 따라서, 페이지 유입경로에 대한 검증 작업이 필요하다.

    7. submit

    보안을 요하는 data를 hidden field에 입력되도록 하지 않는다. 또한 cookie에도 저장하지 않도록 한다. 불가피하게 저장이 필요하다면 암호화해서 저장하고 꼭 기한을 명시해 놓도록 한다.

    8. submit method

    submit 방식을 get방식과 post방식을 분리해서 사용한다. server측의 request는 request.form과 같이 명확한 표시를 해준다.

    아래 부분은 보안이 필요한 모든 페이지에 적용하도록 해야 합니다. <%
    '아래 세 줄은 client PC에 cache되지 않도록 합니다.
    Response.CacheControl = "no-cache"
    Response.AddHeader "Pragma", "no-cache"
    Response.Expires = -1
    %>

    다음의 경우와 같이 변수 값을 서로 다르게 합니다.

    <%
    Response.Buffer=true
    'client side page
    <input type=text id="uid" name="uid" value="">
    <input type="password" id="passwd" name="passwd" value="">

    'server side page
    <%
    '변수를 선언합니다.
    Dim strUserID, strUserPWD
    strUserID = Request.Form("uid")
    strUserPWD = Request.Form("passwd")

    '변수에 넣은 다음 유효성 검사를 실시합니다. 유효하지 않은 문자가 있으면, 요청을 되돌려 보냅니다.
    '유효성 검사는 아래 예를 참조로 정규식 표현 가이드를 활용합니다.
    if strUserID = "[^\w]" then Response.Redirect("/login.asp")
    if strUserPWD = "[^\w]" then Response.Redirect("/login.asp")

    '값이 유효하면 database접속을 시도합니다.
    strConnect = "<<-database connection string->>"
    Set objCN = Server.CreateObject("ADODB.Connection")
    objCN.Open strConnect
    Set objRS = Server.CreateObject("ADODB.Recordset")
    objRS.Open "Select * from Users where uid='" & strUserID & "'",objCN

    if Not objRS.EOF then
      if StrComp(strUserPWD, Rs.Fields("memPassword").value, 1) = 0 then
        'Password is correct.
        'Set a session variable, and redirect the user to a Default.asp page
        'or the main page in your application.
        Session("UserID") = strUserID
        Response.Redirect "Default.asp"
        Response.End
      Else
        'Password is incorrect. Redirect the user to the logon page.
        Response.Redirect "Logon.asp"
        Response.End
      End if
    end if
    %>

    9. 암호화

    사용자 암호를 저장할 때에 hash나 Base64, Server.HTMLEncode, Server.URLEncode를 사용하여 암호 문자열을 incoding해서 저장한다.

    이 코드 예제에는 기능으로 전송된 문자열에서 악성 문자를 제거하는 기능이 포함되어 있습니다. 위의 두 예제 모두에서 제대로 인코딩되도록 코드 페이지가 지정됩니다. 아래 예제는 Microsoft Visual Basic Scripting Edition(VBScript)으로 작성한 것입니다.

    <%@ LANGUAGE="VBScript" %><%
    Response.CodePage = 1252
    Response.Write("Hello, " & RemoveBadCharacters(Request.Form("UserName")))
    Response.Write("<br />This is why you received an error:")

    Function RemoveBadCharacters(strTemp)
      Dim regEx
      Set regEx = New RegExp
      regEx.Pattern = "[^\s\w]"
      regEx.Global = True
      RemoveBadCharacters = regEx.Replace(strTemp, "")
    End Function
    %>

    10. 첨부파일 제한 (중요)

    첨부파일로 실행이 불가능한 몇개의 파일만을 업로드 할 수 있도록 해야 하며, asp, php, js 등 실행이 가능한 파일은 첨부하지 못하도록 해야 한다. fso(scripting.filesystemobject)를 이용하여 system file이 모두 노출될 수 있습니다. html의 경우 <script runat="server">코드가 들어간 html도 업로드 못하도록 해야 한다. 최근에는 flash기반의 source를 악용하는 경우도 있으므로 flash file 또한 막아야 하며, 이렇게 실행이 가능한 file을 upload하는 경우에는 zip등으로 압축하여 올리도록 해야 합니다.

    11.XSS를 방지하기 위한 필터링

    XSS 공격이 무엇인지 간략히 설명하자면 Cross Site Scripting의 약자로 Script 나 Tag 공격을 통해 웹 페이지가 비정상적으로 동작하게 하거나 페이지에 접근하는 유저들의 특정 데이터를 추출해가는 공격을 말한다.
    특정 폼의 입력란(Input Box나 TextArea)에 태그와 자바스크립트를 통해 공격문자열을 입력하게 되면, 그 페이지를 로딩했을 때 해당 명령이 실행되게 된다. 예를 들어, <xmp> 라는 HTML 명령어를 입력하였을 때, < 와 > 로 변경하여 저장하지 않았다면, 해당 페이지는 파싱된 HTML이 실행되지 않고 <xmp>가 실행되어 <xmp> 이하의 HTML 코드들을 페이지상에 노출하게 된다. 또한, <script> 문을 작성하여 저장하게 되면 페이지가 로딩될 때마다 해당 스크립트가 실행되어 사용자의 쿠키 값을 해커가 원하는 서버로 전송시킬 수 도 있으며, 해당 페이지를 자유자재로 다른 특정 페이지로 리다이렉트 시키는 등 이외에도 여러 가지 행위를 할 수 있게 된다.
    이를 방지하기 위해서는 Tag를 저장할 때, “<”와 “>” 부분을 “&lt;”와 “&gt;”로 변경하여야 한며, 입력폼의 MaxLength 제어, “<script”와 같은 단어의 입력 방지 작업들을 하여야 한다. 그리고, 페이지상에 Request.QueryString 과 같은 Value를 나타내야 하는 경우, URLEncoding과 같은 메소드를 이용하여 값을 인코딩하기 바란다.

    12.SQL Injection을 방지하기 위한 필터링

    너무나도 유명한 SQL Injection 이다. SQL Injection을 논할 때 마다, 예전에 방안을 마련하기 위해 수없이 테스트 했던 기억이 늘 떠오르곤 한다. SQL Injection 이 무엇인지 간략히 설명하자면, 데이터를 처리하는 과정을 침투하여 의도되지 않은 데이터 핸들링이 잃어나게 하여 데이터를 변조하거나 획득해가는 공격을 말한다. 따라서, SQL Injection 은 주요한 데이터에 대한 공격이기 때문에 절대적으로 방어해야만 하는 아주 중요한 대상이다. 실감나지 않는다면 만약 공격에 의해 테이블을 Drop 했거나 회원 Data를 획득했다고 가정해 보라.
    SQL Injection 을 방지하기 위해 ADO를 통한 데이터 핸들링 시 전달되는 파라미터들에 대한 필터링 작업이 필요하게 된다. 이러한 필터링 작업만 완벽히 처리해 준다면 보안이 월등히 높아질 것이다.
    파라미터 검증을 위한 함수를 작성할 시에 고려해야 할 사항에 대해 살펴보자.

    1. 데이터 타입 검증 – 데이터는 크게 INT와 Char 형식으로 나뉘게 된다. 따라서, 숫자형의 데이터를 전달해야만 하는 경우 ASP의 IsNumeric 함수를 통해 검증할 수 있다.
    2. 싱글 쿼테이션의 치환 – ADO의 RecordSet 객체를 이용하는 경우 해당 로직에 따라 싱글 퀘테이션을 치환하도록 한다. Ex) ‘ -> ‘’
    3. 문자열 체크 – 문자열이 넘어오는 경우 해당 파라미터의 사이즈에 맞도록 사이즈를 체크하여 불필요한 값이 전달되지 않도록 한다. Left 함수 등을 이용하여 전달되는 데이터의 값을 잘라내는 것도 한 방법이다.
    4. 널 체크 – 반드시 파라미터에 데이터가 전달되어야 하는 경우 널 체크를 통해 값을 인증하도록 한다.
    5. 태그의 허용 - HTML게시판과 같이 태그를 허용하는 경우를 제외하고는 &lt;와 &gt;로 치환하도록 한다.

    이렇게 5가지가 파라미터 검증을 위한 가장 핵심적인 부분이다. 이외에도 해당 로직에 따라 추가적인 파라미터 검증작업이 필요하므로 구현시 보안로직에 대해 잘 고민해야만 한다.
    여기서 주의해야 할 사항이 있다. 이렇게 ASP에서 파라미터 검증을 한다고 하여 SQL Injection 이 완벽히 막아지는 건 아니라는 사실이다. 이 내용은 ASP 웹 소스상에서 최대한 할 수 있는 방어 기법이라는 것이다. 이를 완벽이 막기 위해서는 데이터베이스 차원에서의 방어까지 이루어 져야 한다. 위 내용은 웹 소스상에서 기본적으로 반드시 해줘야 할 작업들에 내한 내용이다.
    위에서 설명한 내용들을 모두 함수로 작성하고, 개발표준안에 추가하여 모든 스크립트가 항상 보안 로직을 통해 작성되도록 해야 한다.

    13.파라미터 이름의 규칙 정의

    많은 웹사이트들에서 쿼리스트링으로 전달되는 값들을 보면 UserCode 혹은 MemberCode, table 등 해당 값이 무엇인지 유추할 수 있게 제작되어 있다. 이러한 값들은 URL 확인 만으로도 값을 확인할 수 있게 된다. 누군가 공격하려 할 때 웹의 구조를 쉽게 파악할수 있다는 것이다. 따라서, 퍼머링크로 사용하지 않고 보안이 필요한 페이지에는 사용자가 쉽게 알아내지 못하도록 해당 파라미터들의 이름을 약어로 사용하거나 암호화 하는 작업이 중요하다.

    14.GET 방식의 지양

    회원코드, 주민번호와 같이 보안이 필요한 데이터를 전송시에 GET 방식을 지양하고 POST방식을 활용토록 하며, POST로 값을 전송할 시에 해당 데이터를 암호화하여 전달하도록 한다. GET 방식을 사용하는 경우 해당 데이터들이 너무나 쉽게 노출되는 경향이 있기 때문이다. 다만 검색엔진 등에 노출되어야 할 게시판 리스트, 게시물 내용보기 등은 GET방식으로 표시하여야 매개변수가 노출되어 직접 링크(perma link)가 가능하므로 무조건 POST쓰는 것은 좋지 않을 수도 있다.

    15.인증정보의 암호화

    XSS 공격을 통해 페이지에 접근하는 유저들의 정보를 쉽게 획득할 수 있다고 하였다. 유저들이 로그인후 갖게 되는 인증정보는 일반적으로 세션 혹은 쿠키를 이용해 저장되게 된다. 따라서, 세션, 쿠키 값을 생성할 시에 암호화를 하여 저장한다면 해당 데이터를 획득했다 할지라도 복호화해야 하는 작업이 필요하게 된다. 따라서, 유저들의 인증정보를 암호화 하는 작업은 상당히 유용한 작업이다.

    16.naming

    웹 폴더 및 페이지 이름에 대해서도 네이밍룰에 대한 권장사항이 있다. 보안 점검 툴을 실행하게 되면 찾는 취약점 중 하나가 웹 폴더 및 페이지의 이름 구조이다. Password.asp 같이 너무나 쉽게 탐지할 수 있는 페이지 구조는 취약점으로 판단하게 된다.
    introduce.asp, product.asp, information.asp 등 검색 등에서 노출이 되어야 하는 파일 이름은 알기 쉽도록 사용하며 보안이 필요한 파일이름은 구조적으로 알기 힘든 이름을 사용하는 것이 좋다. "password.asp" 보다는 "validate.asp"가 좀 더 낫다.

    참고 : ASP보안 (http://technet2.microsoft.com/WindowsServer/ko/Library/45746741-e2b4-4f83-8ddd-d3e57aad9ee91042.mspx?mfr=true)


    Posted by 부니기