PHP & Others

게시판 스팸 글 막기( Transaction의 유효성 처리 )

페이지 정보

본문

회원가입, 상품구매, 결제, 이벤트 참여 등의 웹프로그램은 입력화면과 해당 내용에 대한 실행 프로그램간의 상호 유효성이 상당히 중요합니다. 웹의 경우는 웹이 가지고 있는 Stateless 라는 특성 때문에 입력화면 또는 조회화면과 실행 프로그램이 상호 독립적일 수 밖에 없으며 이에 대한 Transaction 처리가 항상 문제가 되어 왔습니다.
다른 사이트(허가되지 않는 비 정상적인 사이트)에서 입력 또는 조회화면을 두고 결과만 훔쳐 보다든지 ( 만화 사이트에 직접 접속하지 않고 다른 사이트를 통하여 쉽게 만화를 본다든지 ), 아님 프로그램을 작성하여 게시판에 무차별적으로 스팸성 글을 올리거나 사이트 이벤트 시에 프로그램을 작성하여 이벤트를 참여하여 사이트에 과다한 부하를 주는 경우를 많이 봐 왔습니다.

많은 경우가 개발자들이 Transaction 처리를 위한 유효성 검사를 전혀 하지 않기 때문에 발생한다고 생각합니다. 저도 가끔은 상품에 눈이 어두워 이벤트 참여를 위한 프로그램을 작성한 경우가 있는데 대부분은 비 무장으로 저를 맞아 주더군요.

URL,Cookie, POST 또는 GET,Referer 정보를 분석 후에 HTTP 통신 모듈을 활용하면 반나절 정도 만 투자하면 자동 글 게시 프로그램을 작성할 수 있습니다. ( 이에 대한 방법이 궁금하면 아이헬퍼스 사이트의 강좌란에 "자동으로 게시판에 글기재하기" 를 참고하면 좋을 것 같습니다. ) 이러한 프로그램들이 비정상적이라고 이야기만 할 수는 없습니다. 검색엔진이 사이트 정보를 읽어 가고 리눅스에서 lynx 를 통하여 웹에 접속할 수 있으며, 사람들이 자동차를 튜닝하는 것처럼 나만의 강력한 브라우저를 위하여 사용자가 얼마든지 튜닝을 할 수 있는 것이니까요.

당연히 중요한 부분에는 입력화면과 실행프로그램간에 유효성 검사를 해야 된다고 생각합니다.실행 프로그램에서는 해당 정보가 입력화면에서 왔다는 인증된 값을 검사하는 것이지요.

아래와 같이 다양한 방법을 생각해 볼 수 있을 것 같습니다.


1. Input 태그의 Hidden 속성을 사용하여 특정 값을 넘기는 방법
2. Referer 값 점검
3. 입력화면에서 쿠키를 저장 후에 실행 프로그램에서 해당 쿠키 정보 확인

입력화면에 Random 한 문자열을 출력하고 사용자가 해당 문자열을 입력하게 하는 방법
1 ~ 3번의 경우는 일정기간 동안은 먹힐 수 있겠지만 해당 값을 수정하여 적용만 해주면 다시 간단하게 뚫고 들어 올 수 있습니다. 4번은 사용자가 해당 값을 항상 넣어 주어야 하는 불편함과 적용하기 힘든 곳도 많을 것 같습니다.

3번의 방법을 활용한 제가 사용하는 방법을 소개할까 합니다.

1. Token 함수 만들기

아래와 같이 키 값을 만들고, 읽고 그리고 점검하는 함수를 작성합니다.
///////////////////////////////////////////////////////////////////////
// 함  수  명 : putTocken
// 입력 필드 : -
// 설      명 : token 설정
function putToken() {
                $token = md5(uniqid(rand(),1));
                setcookie("C_TOKEN",$token,0,"/","");
}

///////////////////////////////////////////////////////////////////////
// 함  수  명 : getTocken
// 입력 필드 : -
// 설      명 : token 읽기
function getToken() {
                $token = md5(uniqid(rand(),1));
                setcookie("C_TOKEN",$token,0,"/","");
                return $token;
}

///////////////////////////////////////////////////////////////////////
// 함  수  명 : checkToken
// 입력 필드 : -
// 설      명 : token check
function checkToken() {
        global $C_TOKEN,$TOKEN;
        if($C_TOKEN == $TOKEN){ putToken(); return true; }
        else { return false; }
}




사람이 쉽게 인식 할 수 없도록 유일한 문자열에 대하여 MD5로 암호화하여 해당 값을 쿠키 정보로 저장합니다.

$token = md5(uniqid(rand(),1));
setcookie("C_TOKEN",$token,0,"/","");

2. 입력화면에서 키 값을 설정하기

getToken 함수를 이용하여 키 값을 쿠키에 저장하고 Input Hidden 태그를 사용하여 쿠키에 저장한 키 값을 넘겨 준다.

$token = getToken();

<input type="hidden" name="TOKEN" value="<?=$token?>">





3. 실행프로그램에서 키 값 확인하기

checkToken을 사용하여 쿠키에 입력된 키 값과 Input 태그의 TOKEN 으로 넘어온 값을 비교합니다. 비교 후에 항상 키 값을 갱신을 해 줍니다. 이와 같은 처리로 입력화면을 거치지 않고는 정상적으로 실행프로그램이 실행이 되지 않는 것에 대한 신뢰성을 확보할 수 있습니다.

if(checkToken()){
      AddData($conn);
} else {
      die("불법광고는 등록 등록할수 없습니다.");
}




이렇게 처리하고 게시판을 운영했지만 30일 후에 다시 스팸 글들이 올라 오더군요. 그때는 정말로 놀랐습니다. 본인은 도저히 불가능하다고 생각을 했거든요. 스팸글을 올리는 프로그램을 만드는 사람도 밥을 먹고 살아야 하기 때문에 당연히 고민을 많이 했겠지만요. 분명히 사용자가 브라우저를 통하여 사이트를 방문하는 것과 같이 먼저 입력화면에 요청을 하고 쿠키 정보를 셋팅하고 POST 값을 분석하여 입력처리를 한 것이 분명합니다. Referer Check 도 해 보았지만 이미 이에 대한 처리도 해 놓았던 것 같더라구요.

그래서 저는 프로그램은 사람처럼 Button Click 이나 Enter을 치는 Action 을 할 수 없다는 것을 착안하여 Javascript 를 활용하였습니다. ( 물론 프로그램으로 처리 할 수 있지요.그러나 그렇게 하기에는 문제점이 많이 있기 때문에 분명히 이와 같이는 할 수 없다고 생각한 것이지요. )

4. Javascript 를 사용하여 입력 Action 대한 신뢰성 확보하기

3번까지의 방법은 입력화면에서는 키 값(Input 태그의 TOKEN)을 쿠키에 저장한 값으로 설정해 놓았습니다. 그러나 여기서는 해당 값을 빈 문자열로 둡니다. 그리고 사용자가 모든 입력을 끝내고 Enter 나 확인버튼을 Click시 ( Onsubmit Event 발생할 때) 에 sec_lib.php3 의 SecSubmit() 자바스크립트 함수를 사용하여 TOKEN 값을 설정하도록 작성해 놓았습니다.

<script language="JavaScript" src="/lib/sec_lib.php3"></script>
<script language="javascript">
      function sendit()
      {
              ff = document.f1;
              if (ff.NAME.value ==""){
                    alert("작성자를 입력하세요");
                    ff.NAME.focus();
                    return false;
              }
              SecSubmit(ff);
              return true;
      }
</script>
<body bgcolor="#FFFFFF" leftmargin="14" topmargin="14" marginwidth="14" marginheight="14" onload="">
<FORM NAME="f1" METHOD="post" ACTION="right01_cmd.phtml" onsubmit="return sendit();">

<input type="hidden" name="TOKEN" value="">
..




Sec_lib.php
function SecSubmit(ff){
      if(ff.TOKEN){
              ff.TOKEN.value = getCookieiHelpers("C_TOKEN");
      } else {
              alert('자료입력 방지를 위하여 Token 처리');
              return false;
      }
}

function getCookieiHelpers (name) {
              var dcookie = document.cookie;
              var cname = name + "=";
              var clen = dcookie.length;
              var cbegin = 0;
              while (cbegin < clen) {
                    var vbegin = cbegin + cname.length;
                            if (dcookie.substring(cbegin, vbegin) == cname) {
                                  var vend = dcookie.indexOf (";", vbegin);
                                  if (vend == -1) vend = clen;
                            return unescape(dcookie.substring(vbegin, vend));
                    }
                    cbegin = dcookie.indexOf(" ", cbegin) + 1;
                    if (cbegin == 0) break;
              }
              return "";
}




물론 해당 방법도 문제점이 전혀 없는 것은 아니다. 그러나 이와 같은 보안적인 처리를 하지 않은 곳이 더욱 많다는 것이 문제라고 생각합니다.

1. 글 작성을 열심히 하고 브라우저를 새 창으로 열었을 경우에 키 값이 다시 초기화 되어 입력이 되지 않는다.
2. 위와 같은 내부 로직을 안다면 입력화면을 거치고 쿠키의 키 값과 Input 태그의 키 값을 무조건 같게 해 논다면 스팸 글을 다시 올릴 수 있다.

Input 태그의 키 값 그리고 쿠키의 키 값 그리고 자바스크립트를 통한 키 값의 연결에서 암호화 방법을 좀 더 고민한다면 완벽하게 스팸으로부터 해방 될 수 있을 것입니다.

http://www.ihelpers.co.kr/programming/right11_detail.phtml?TYPE=8&KEY=&FIELD=&PAGE=1&NO=242&CMD=view

관련자료

등록된 댓글이 없습니다.
Today's proverb
가지로 자태를 뽐내기 보다 비록 보기에는 볼품없지만 뿌리를 내리기 위해 힘쓰는 자가 되자.