Web Hacking 1탄 SQL Injection

Web Hacking 2탄 파일조작

Web Hacking 3탄 구멍난 자바스크립트



1. 시작하기

여러분들은 사용자가 입력한 값에대해 어느정도 검증을 하는지요?

사용자 값을 이것저것 따지고 여러가지 유효성을 체크할려면 아주 귀찮은 일이 아닐수 없습니다

그중에 하나가 웹브라우져에서 실행되는 자바스크립트로 체크하는 방법이 있는데 비지니스 로직이 조금 복잡할때는 자바스크립트로 도배를 하는 경우도 종종 있지요

유효성 검증하는일 저도 정~~말 싫어합니다 하지만 해야 합니다 ㅠ.ㅠ

그럼 어디까지 그 유효성을 체크해야 할까요? 자바스크립트로만 체크하면 될까요?


처음 웹프로그래밍을 할때는 저도 자바스크립트로만 입력값을 검증하면 되는줄 알았습니다

한마디로 몰랐죠

하지만 이제는 알기때문에 자바스크립트뿐만 아니라 서버쪽에서도 동일하게 체크해 주어야 합니다

사용자가 입력한 값이 얼마나 무서운지는 앞의 1탄, 2탄의 강좌를 통해 어느정도는 감을 잡으셨으리라 생각하고 이번 강좌에서는 왜 서버쪽에서도 체크해야 하는지!에 대해 간략히 알아보겠습니다



2. 자바스크립트 체크


입력값의 자리수가 13자리인지 체크하여 맞으면 submit을 만약 그렇지 않다면 정상적인 입력값을 요구하는 입력갑검사 로직이 있다고 가정하겠습니다 그리고 서버쪽에서는 꼭 13자리가 넘어와야 정상적인 처리를 할수 있다고 하겠습니다

그럼 아래와 같은 간단한 코드가 나올겁니다


http://www.jakartaproject.com/html/input.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {
    var obj = document.f.register_no;
    if (obj.value.length != 13) {
        alert('주민번호 정상적으로 입력하세요');
        return false;
    }
}

</script>


<form name=f method=post action=process.jsp onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>


 실제 웹 브라우져에서 보면 아래와 같습니다

"33" 이라는 두자리 수만 입력하니 역시나 재입력을 요구하는 alert창이 떳습니다 (가끔 깜짝깜짝 놀라죠 -,-)




그럼 정상적으로 "1111111111111" 의 입력값 13자리를 입력해 보겠습니다




 

그리고 이 값은 process.jsp 라는곳에서 파라미터로 받아 아래와 같이 처리합니다

코드는 간단하게 그 입력값과 레퍼러 값을 보여주겠습니다


http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>


<%
String register_no = request.getParameter("register_no");
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>


request.getHeader("referer")는 헤더정보에서 referer값을 가져오는 함수로, 이전 페이지 주소값을 가져옵니다

그럼 화면은 아래와 같이 나옵니다


자 정상적으로 처리되었습니다



3. 자바 스크립트 우회

그럼 이제부터 자바스크립트로 입력값의 자리수 체크로직을 피해가는 방법을 알아봅시다

어떤 방법이 있을까요?


URL로 접근

입력값이 몇가지 되지 않는다면 아래 방법이 가장 편하겠군요

즉 브라우져 주소창에다 직접 입력 합니다


http://www.jakartaproject.com/html/process.jsp?register_no=2222

아래와 같은 화면이 나올겁니다

메쏘드정보 (request.getMethod())를 찍어보니 GET 이 나오는군요!

그렇다면 이같은 직접 URL값을 막기위해 간단히 POST만 허용하는 로직을 추가해 버립시다


http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>


<%
if (!"POST".equals(request.getMethod())
   return;

String register_no = request.getParameter("register_no");
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

이러면 괜찮겠지 흐흐.. 라고만끝나면 안됩니다


로컬파일로 접근

①번의 방법은 GET방식때문에 막혔습니다 그러면 자바스크립트를 우회하면서 POST방식으로 보내는 방법은 없을까요? 물론 있습니다

웹브라우져는 "소스보기" 라는 좋은 메뉴가 있습니다 있는건 적극 활용합시다 ㅎㅎ

소스보기한 후 바탕화면에 저장하여 약간 손을 보았습니다

즉 입력값을 체크하는 자바스크립트를 무력화 시키면서, action을 수정해 주었습니다


C:\Documents and Settings\Administrator\바탕 화면\client.html

<script>

/* 입력한값이 13자리인지 체크 후 전송 */

function validateValue() {

    return true;
}

</script>


<form name=f method=post action="http://www.jakartaproject.com/html/process.jsp" onsubmit="return validateValue()">
주민번호 <input type=text name=register_no> <input type=submit name=btn value=submit>
</form>



웹화면은 다음과 같겠죠


"submit"버튼을 클릭합니다 ^^


역시나 자바스크립트를 거치지 않고 process.jsp에 13자리수가 아닌 "22"값을 무난히 보냈습니다



그럼 서버쪽에서는 "어이쿠 이런 헤더정보도 체크해야 겠군" 하고 다음 코드를 추가해 버릴겁니다

즉 레퍼러값이 null인 경우는 허용할수 없다는 것이죠


http://www.jakartaproject.com/html/process.jsp

<%@ page contentType="text/html; charset=euc-kr" %>


<%

if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;

String register_no = request.getParameter("register_no");
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>

그럼 위와같은 소스가 될것입니다

그럼 과연 위 소스가 안전할까요?


HEADER값 조작

그렇다면 HEADER값을 조작해 봅시다 어떻게 조작할 수 있을까요?

여러가지 프로그램들이 있지만 그중에 Achilles 라는 proxy server를 이용하여 조작해 보겠습니다

Achilles라는 proxy server는 웹브라우져와 서버간의 HTTP 세션을 중간에서 가로채어 원하는대로 수정한 후 보낼수 있도록 해주는 작으면서도 강력한 프로그램입니다


※ 참고

Achilles 문서를 보면 맨 첫줄에 나오는 문장입니다

"Achilles is a tool designed for testing the security of web applications"

이 프로그램은 웹어플리케이션의 보안 테스팅을 하는데 작성되었으므로 테스팅용으로만 사용합시다


다운로드

http://www.mavensecurity.com/achilles


우선 위에서 작성한 바탕화면에 저장된 C:\Documents and Settings\Administrator\바탕 화면\client.html 를 실행한 결과를 Achilles가 Intercept한 결과입니다

여러 가지 헤더정보들이 보이며 쿠키값까지 조작할수 있습니다

하지만 위의 헤더정보에는 referer값이 없습니다 그래서 referer체크에서 null이 나와 로직에 걸립니다

그렇다면 referer정보를 추가해 줍시다


파랑색으로 줄쳐진 부분을 에디팅하여 추가해주었습니다

Referer: http://www.jakartaproject.com/html/input.html

그런다음 "Send"버튼으로 전송합니다


짠~

그러면 조작된 헤더정보를 알아채지 못하고 헤더의 referer값을 가져오는군요!



4. 서버쪽 로직 추가!

위에서 자바스크립트를 우회하는 몇가지 방법들을 알아보았습니다

결론은 하나입니다 즉! 서버쪽에서도 동일하게 체크해 주어야 합니다


<%@ page contentType="text/html; charset=euc-kr" %>


<%

String register_no = request.getParameter("register_no");


if (!"POST".equals(request.getMethod())
   return;


if (request.getHeader("referer") == null)
   return;


if (register_no.length() != 13)

   return;
%>


헤더정보 <%=request.getHeader("referer")%><br><br>
주민번호 <%=register_no%>


그렇다면 서버쪽에서만 체크하고 클라이언트에서는 체크할 필요가 없다고 생각할지도 모르지만,

그만큼 서버쪽으로 오는 request를 줄이면 더더욱 좋겠죠

자잘한것 하나때문에 서버쪽 부하를 줄수 없는 노릇아니겠습니까?


자 이러이러 하고 저러저러한 이유로 우리는 이제부터라도 클라이언트에서는 자바스크립트로,

서버쪽에서는 또 서버쪽 스크립트로 사용자가 입력한 값에대해 유효성을 검증해야 하는것을 알았습니다

로직이 복잡한 경우 가뜩이나 자바스크립트도 복잡한데 그 로직을 서버쪽에서 다시한번 만든다는게 힘들다는거 다들 압니다 하지만 안전한 웹페이지를 만들기 위해 다같이 노력해야 되지 않겠습니까?


Web Hacking 1탄 부터 이번 3탄에 이르기까지 웹 프로그래밍 하면서 반드시 필요하고 인식해야 하는 부분에 대해 논하였습니다

마지막으로 다시한번 언급하자면 우리가 잠깐 잊고 지나가거나 혹은 귀찮아서 지나치는 사소한 부분들 때문에 엄청난 결과를 가져올 수 있다는 것입니다 미리미리 예방하고 예측해서 방지하는수 밖에 없습니다 그럼 다들 건승~!~!


이상 GoodBug였습니다~


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

2009/08/26 17:25 2009/08/26 17:25

Trackback Address :: 이 글에는 트랙백을 보낼 수 없습니다