만약, 당신이 웹 상에 공개된 웹 폼을 제공하고 있다면 당신의 응용프로그램을 다른 용도로 사용하길 원하는 사람들의 공격에 항상 노출되어 있는 것이다. 자동화된 로봇들은 포럼, 투표, 방명록, 블로그와 같이 당신의 사이트에서 인기있는 장소에 포스트를 등록하려 한다. 야후를 비롯한 많은 사이트들이 CAPTCHA를 채용하고 있다. CAPTCHA는 "Compeletely automated public Turing test to tell computers and humans apart"의 "약자로 컴퓨터와 인간을 구별할 수 있는 완전히 자동화된 공개 튜링 테스트"를 의미한다. CAPTCHA는 카네기 멜론 컴퓨터 공학과의 프로젝트로 어떤 요청을 인간이 한 것인지, 사람이 한 것인지 구별하기 위한 것이다. CAPTCHA 기술을 사용하면 웹 상에서 어떤 요청을 컴퓨터가 요청한 것인지, 사람이 요청한 것인지 구별할 수 있다.
참고: 위키피디어(wikipedia.org)에 따르면 튜링 테스트는 사람처럼 대화할 수 있는 기계의 능력을 테스트하기 위한 것이다.
방문한 웹 사이트들중에서 CAPTCHA 프로젝트를 본 적이 있을지도 모른다. 이 프로젝트는 렌더링된 페이지에 컴퓨터가 읽을 수 있는 텍스트에서 언급되지 않은 문구를 포함한 이미지를 임의로 생성하는 것이다. 폼은 사용자에게 문구에 제시된 것에 대해 대답할 것을 요청한다. 폼 포스트에 올바른 문구가 포함되어 있지 않으면 사람이 실수를 한 것이거나 인간이 아니라고 결론내릴 수 있다.
Text_CAPTCHA 설치하기
Christian Wenz 덕분에 PEAR는 웹 응용프로그램의 보안 도구로 이런 테스트를 제공할 수 있는 패키지를 갖게 되었다. Text_CAPTCHA 패키지는 간단한 객체지향 인터페이스에 임의의 문구를 동적 이미지로 생성할 수 있는 PHP GD 라이브러리를 사용한다. Text_CAPTCHA를 사용하기 전에, JPEG, PNG, 트루타입 폰트를 지원하기 위해 GD가 설치되어 있어야 한다. 이에 대해서는 PHP Image Functions를 참고하기 바란다.
Text_CAPTCHA는 PEAR의 Image_Text와 Text_Password 패키지를 사용한다. CAPTCHA 테스트에 사용할 임의의 문구를 생성하기 위해 Text_Password를 사용하고, 텍스트를 이미지 파일로 만들기 위해 Image_Text를 사용한다. 명령줄에서 Text_CAPTCHA를 설치하는 과정은 다음과 같다.
$ pear install Text_Password
$ pear install Image_Text
$ pear install --alldeps Text_CAPTCHA
CAPTCHA 사용하기
이제, 패키지를 사용한 시간이다. 새로운 보안 수단을 구현하기 위해 간단하면서도 자주 사용되는 인터페이스 즉, 블로그의 코멘트 폼을 사용해보자. 이 폼에서 name, email, comment 같은 항목들을 블로그에 전송하게 된다.
폼에 CAPTCHA를 추가해보자. 사람인지 확인하기 위한 용도로 Submit 버튼 위에 이미지 태그를 추가한다.
Please enter the text in the image below:
name="captcha_phrase" />mmlt;br /mmgt;
mmlt;img src="captcha.jpg" /mmgt;
이 부분이 Text_CAPTCHA가 들어가는 부분이다. 폼을 사용하기 전에 Text_CAPTCHA를 사용하는 코드를 다음과 같이 작성한다.
require_once("Text/CAPTCHA.php");
$captcha = Text_CAPTCHA::factory("Image");
$captcha->init(150,150);
?>
첫번째 줄은 Text_CAPTCHA.php를 포함시키는 부분이다. 두번째 줄은 Text_CAPTCHA의 하위 클래스로부터 객체를 반환하는 factory 메서드를 사용한다. Text_CAPTCHA의 설계는 CAPTCHA를 렌더링하기 위해 다른 드라이버 타입을 사용할 수 있다. CAPTCHA는 단순히 이미지를 렌더링하는 기술이 아니라 사람과 컴퓨터를 구별하기 위한 기술이기 때문에 다른 기술을 사용할 수 있도록 팩토러 패턴으로 되어 있는 것이다. factory 메서드의 인자는 임의의 이미지를 생성하는 Image 드라이버로 객체를 생성할 것을 지시하는 "Image"를 사용한다. 세번째 줄은 Text_CAPTCHA 객체를 초기화하고, 이를 사용할 것을 지시한다.
초기화 단계는 보다 많은 조사를 수행한다. 먼저, 임의로 생성한 이미지의 폭과 높이를 매개변수로 지정한다. 이들 메서드는 선택사항이며, 사용되지 않으면 기본값인 200과 80이 사용된다. init()은 추가로 매개변수 두 개를 더 사용할 수 있다. 첫번째는 $phrase로 프로그래머가 생성된 이미지에 사용할 암호문을 설정할 수 있다. 암호문을 설정하지 않으면 init()은 최대 8글자로 된 암호문을 자동으로 생성한다. 네번째 매개변수는 $options 배열로 PEAR의 Image_Text 객체에 전달할 인자들을 쓸 수 있으며, 이 정도는 init()에서 텍스트로 이미지를 생성할 때 사용한다.
$options 배열을 사용해서 사용할 폰트와 폰트 크기, 시스템에 설치된 폰트의 경로 등을 설정하기 때문에 Text_CAPTCHA에서 중요한 매개변수다. (윈도우에서 사용하지 않는 한 기본 폰트 경로가 항상 동작하지는 않는다) $options 매개변수를 설정하려면 다음과 같이 배열을 생성해서 init()에 전달하면 된다.
$text_image_options = array(
"font_size"=>"20",
"font_path"=>"/path/to/fonts/",
"font_file"=>"ARIAL.TTF"
);
$captcha->init(150,150,NULL,$text_image_options);
init()에서 이미지와 문구를 생성했으면, 나머지 과정은 간단하다. 브라우저에 표시할 이미지를 생성하면 된다. init()에서 이 과정을 처리하지 않기 때문에, getCAPTCHAAsJPEG()나 getCAPTCHAAsPNG() 같은 접근자 메서드를 사용해서 이미지를 가져와야 한다. 둘 다 버퍼에 임의로 생성된 이미지 데이터를 반환하기 때문에, 이 데이터를 이미지 파일로 변환하는 것은 간단하다. PHP4를 사용하고 있다면 다음 코드를 사용해서 처리한다.
$image_data = $captcha->getCAPTCHAAsJPEG();
$handle = fopen("captcha.jpg", "a");
fwrite($handle, $image_data);
fclose($handle);
PHP5에서는 새로운 함수, file_put_contents를 사용해서 이 작업을 보다 단순화했다.
$image_data = $captcha->getCAPTCHAAsPNG();
file_put_contents("captcha.png",$image_data);
다음으로 해야할 일은 현재 객체에서 문구를 추출해서 세션 변수에 저장하는 것이다. 현재 사용자에 대한 세션을 생성하지 않았다면 세션을 생성해야 한다.
(역주: 이미 세션이 시작되어 있다면 session_start()를 호출하면 안된다.)
session_start();
Text_CAPTCHA의 getPhrase() 접근자 메서드를 사용해서 폼이 전송될 때 사람인지, 컴퓨터인지 테스트하기 위한 문구를 세션에 저장한다.
$_SESSION["captcha_phrase"] = $captcha->getPhrase();
CAPTCHA 인증하기
지금까지는 사용자 폼에 대해서 살펴봤고, 이제는 사용자가 인간인지 아닌지를 판단하는 코드에 대해 살펴볼 순서다. 폼이 전송될 때, 전송된 문구가 세션에 설정되어 있는지, 세션의 값과 같은지를 검사한다. 일치하면 적절한 POST 처리를 수행하고, 그렇지 않으면 폼 전송을 무시하고, 여러분의 필요에 맞는 처리를 수행하면 된다. 다음 코드는 CAPTCHA 테스트의 로직을 설명한 것이다.
session_start();
if (isset($_POST["captcha_phrase"]) &&
$_POST["captcha_phrase"] == $_SESSION["captcha_phrase"])
{
// POST 요청을 처리한다.
}
else {
// 일치하지 않으므로 보안 감사를 한다.(로그 기록 등)
}
?>
결론
CAPTCHA는 응용프로그램에서 원하지 않는 HTTP POST 요청의 상당 부분을 성공적으로 제한할 수 있는 멋진 방법이다. Text_CAPTCHA는 이 기능을 재빠르게 구현할 수 있는 멋진 객체를 제공한다. 현재, 이 패키지는 알파 단계에 있으며, 공식적으로는 제품 단계에 있는 것은 아니다. 그러나, 멋진 출발을 했으며, PEAR에 보안과 관련된 부분을 추가하게 되었다. 모두 행복한 캡차잉~(Happy CAPTCHA-ing!)
Marcus Whitnev는 전세계 1800개 이상의 기업들에 이메일 마케팅을 제공하는, 뉴욕과 내슈빌에 사무실을 둔 이메일 마케팅 서비스 Emma의 제품 개발 부장이다.