perl で Captcha 認証(セキュリティ画像)をやる方法について
ユーザ登録とかでロボット等でのスパム登録を防止したりって用途に使われているアレです。こんなヤツ。
最近はブログのコメントとかのスパム防止でもよく見かけます。まずは基礎知識。このような画像で認証を行うことを Captcha っていいます。wikipedia の情報を引用すると、
もっとも一般的な画像によるCAPTCHAの場合、次のように画像に記されている文字や数字を読み取ることができるか否かによって人間と機械を判別する。
- CAPTCHAシステムは、ランダムな文字や数字の列を画面に表示する。表示される文字は歪んでいたり一部が覆い隠されていたりして、機械が自動的に読み取ることは難しい。
- ユーザーは画面に描かれている文字の列を読み取り、同じ文字列をシステムに入力する。
- システムが表示した文字列とユーザーが打ち込んだ文字列が一致していれば、ユーザーは歪んだ画像を認識する能力を持っていると考えられる。システムはそのユーザーが人間であると推測する。
これを perl で実装するには・・・なんてことをここ数日調べていたので情報まとめています。なかなかこの手の日本語情報が少ないので誰かの役に立つかなと。ある意味 http://perl-users.jp/ 向けだったりと。
長くなりそうなので、2〜3エントリに渡って説明をしていきたいと思っています。まずは perl で captcha をやりたい場合にはベースとなるモジュールが2つあります。
Authen::Captcha
結構古く(2003年)からあるモジュール。昔はこれを使うのが流行っていたみたい。現在は更新も止まっているようだし、キャプチャ画像生成において、固定の背景とフォント画像を用いて画像生成するため、セキュリティ的にアレでしょって感じで使われなくなっているようです。ちなみにキャプチャ画像とユーザが入力した文字の整合性チェックまでモジュールが面倒を見てくれています。使用を推奨しないよって意見が多いようなので、説明もここまで。僕自身もそれほど解析をしてません。
GD::SecurityImage
Authen::Captcha のあとがま。互換モードとか実装されていて乗り換えも意識して作られています。こちらは、TrueType フォントが使えるので自分の好きなフォントでキャプチャ画像を生成できます。背景画像は設定できないけど、ドットやラインなどがランダムで描画される仕掛けになっています。ちなみに、こちらのモジュールはあくまでキャプチャ画像の生成と表示を担当するのみ。キャプチャ画像とユーザが入力した文字の整合性チェックはユーザ側が実装するポリシーになっています。そこら辺はまた別途説明。
さて、このモジュール。引数がいろいろあって何をどうすると、どんな画像が生成されるのかがちょっと把握しづらいです。おまけに僕が探していたタイプのキャプチャ画像のスタイル指定ができなかったので、勝手に拡張しました。
※フォントのサイズをランダムで変更 + 背景画像にランダムライン + フォント描画開始位置の指定 を加えました。
※この辺は後ほど作者に patch を送りたいけど英語めんどい。
そんなわけで、このエントリは、このオプションをこうすると、こんな画像が生成されますよってサンプルまでで終了。そこから先はまた次回で。このプログラムが GD::SecurityImage を勉強する素材としてもちょうど良いかと思う次第です。
GD::SecurityImage でキャプチャ画像を生成してみる
※ptrange / style=line" は勝手に拡張した部分。それ以外はオリジナルに実装されているオプション。全てのオプションを網羅したわけではありませんけど、これで 80% 程度は網羅されているはず。何をどう設定するか把握するのにお役立て下さい。
まずはキャプチャ画像表示プログラムはこんな感じ。form から受け取った値を元に GD::SecurityImage の設定値を決めて画像生成やってます。
#!/usr/local/perl use strict; use warnings; use GD::SecurityImage; #use GD::SecurityImage backend => 'Magick'; # ImageMagick が入っている方はこちらで use HTTP::Date; use CGI; my $q = CGI->new; my $fontcol = $q->param('fontcolor') || '#000000'; my $linecol = $q->param('linecolor') || '#555555'; my $style = $q->param('style') || 'line'; my $config = { session_name => 'captcha_string', new => { lines => $q->param('lines') || 20, angle => $q->param('angle') || 0, scramble => $q->param('scramble') || 0, ptsize => $q->param('ptsize') || 20, ptrange => $q->param('ptrange') || 0, thickness => $q->param('thickness') || 1, width => 300, height => 100, rnd_data => [ 'A' .. 'Z' ], margin => [ 10, 10 ], bgcolor => $q->param('bgcolor') || '#eeeeee', font => "フォント名.ttf", }, create => [ "ttf", $style, $fontcol, $linecol ], particle => [ $q->param('particle1') || 100, $q->param('particle2') || 1 ], out => { force => "jpeg" }, }; my $image = GD::SecurityImage->new( %{ $config->{new} } ); $image->random(); $image->create( @{ $config->{create} } ); $image->particle( @{ $config->{particle} } ); my ( $image_data, $mime_type, $random_string ) = $image->out( %{ $config->{out} } ); print $q->header( -type => qq{image/$mime_type}, -expires => time(), -last_modified => HTTP::Date::time2str, -pragma => 'no-cache', -cache_control => 'no-cache' ); print $image_data;
ちなみに、キャプチャ画像を生成するにあたって、フォントの色等には注意が必要です。ちょっとした画像ソフトでフィルタしたら機械的に文字認識が可能なんて事にならないように。なんて事は次回以降に説明したいと思います。
コメントやシェアをお願いします!
yuuki
はじめまして。
GD::SecurityImageをダウンロードしたのですが使い方が分らないのです。
アドバイスしてもらえないでしょうか
GD::SecurityImage でキャプチャ画像を生成してみる。の
この設定でキャプチャ画像を表示をクリックするとスクリプトが現れますが、Captcha 認証の設定に何か関係あるのでしょうか?
よろしくお願いします。
boyacky
ありがとうございました。いただきました。
scramble = 0 でも ptrange, margin が有効になるようにちょこっとだけ、手直ししちゃいました。
drk
boyacky さん>
無保証ですが、改変したソースを下記におきましたのでご自由にお使い下さい。w
http://www.drk7.jp/pub/ap/captcha/src/GD-SecurityImage-1.65-plus.tar.gz
boyacky
「フォントのサイズをランダムで変更 + 背景画像にランダムライン + フォント描画開始位置の指定」の拡張、すばらしいです。ノーマルで生成される画像に若干の不満がありましたが、これで解消できそうです。
拡張部分を使わせていただくことは、できないでしょうか?