CAPTCHA画像の生成

DS216jでWEBサーバーを構築する備忘録の続き。

サーバーにImage::Magickのインストールができない状況で現状のBBSを温存するためには、何か別の方法でCAPTCHA画像の生成をしなければならない。画像の生成だけならPHPで書かれた「Securityimage」で比較的簡単に出来たが、cgiから呼び出して使うにはキーの認証に難がある。で、perlでImage::Magickを使わずにCAPTCHA画像を生成する方法が無いか調べてみたところ、GD::SecurityImageというperlモジュールが使えそう。

試しにCPANを利用して下記コマンド実行したところエラー無くインストールは完了。

keyinit.plの改造

GD::SecurityImageはCAPTCHA画像の生成のみを行うもので、キーの認証機能は含まれない。そこで、キーコードの生成・認証については今までどおりこちらで配布されているスクリプトを使うことにした。keyinit.plはキーのランダム生成と、出力する画像フォーマットの設定、キーの暗号化と復号の役割を持ち、cgiのプラグインとして動作する。これを以下のように改修した。

まずはImage::Magick用の設定項目である下記部分はザックリ削除。

#-# 文字画像の幅と高さ
$W = '60'; # 幅
$H = '22'; # 高さ

# バックグラウンド画像ファイル
# 単一色のキャンバスを自動生成するか、予め用意された画像を指定
# 画像(gif/jpg形式のみ)を利用する場合は、文字画像の高さ+20ピクセル程度
# の画像を用意すること。
$bgfile = '#ffffff'; # キャンバス色
#$bgfile = 'bg.gif'; # 画像ファイル名

# 画像生成に使用するフォントのパス
# truetypeフォントを絶対パスで指定すること。
# 波型加工する場合は、文字を選ばないと判読不能になる。
# (CentOSはtruetypeフォントはほとんど入っていないので、
# 別途、RHELのSRPMをリビルドしてインストールすると良い。)
# SuSE9.3
#$font = '/usr/X11R6/lib/X11/fonts/truetype/luxirb.ttf';
# SuSE10.2
#$font = '/usr/share/fonts/truetype/luxirb.ttf';
# CentOS4.4
#$font = '/usr/X11R6/lib/X11/fonts/TTF/luxirb.ttf';
# WindowsXP
$font = 'C:\WINDOWS\Fonts\TIMESBD.TTF';

# フォント色
$font_color = '#ee0000';
# フォントサイズ
$font_size = '20';
# 文字が詰まって文字画像が見難い場合の文字間調整
$space = '0'; # 0:なし 1:あり(スペース挿入)
# 文字の高さ方向の微調整(デフォルト:0, 負数可 ex. '-2')
$vert = '0';

# 文字画像の波状加工の振幅とピッチ
# 波状加工しない場合は両方とも0にすること
$amp = '1'; # 振幅
$pitch = '10'; # ピッチ
#$amp = '0'; # 波状加工しない場合は両方とも0にすること
#$pitch = '0';

#-----設定終了----------------------------------------------#

代わりにGD::SecurityImage用の設定項目を追記する。なお、フォントのluxirb.ttfはNASにインストールされていなかったので、古いサーバーからコピーした。画像フォーマットについてはこちらのサイトを参考にパラメータを設定。

# スタイル
#$style = 'default';
#$style = 'rect';
#$style = 'box';
#$style = 'circle';
$style = 'ellipse';
#$style = 'ec';
#$style = 'blank';
#$style = 'line';

# 文字画像の幅と高さ
$captcha_w = '60'; # 幅
$captcha_h = '22'; # 高さ
# フォント色
$font_color = '#ffffff';
# フォントサイズ
$font_size = '12';
#背景色
$bg_color = '#000000';

# 撹乱ラインの設定
$line_color = '#bbbbbb';
$line_n = '3'; #ラインの数
$line_w = '1'; #ラインの幅

#撹乱ドットの設定
$density = '1'; #隣接ドット密度
$maxdots = '15'; #ドットの数

# 画像生成に使用するフォントのパス
# truetypeフォントを絶対パスで指定すること。
$ttf_font = '/volume1/web/bbs/luxirb.ttf';
#-----設定終了----------------------------------------------#

image_gen.cgiの改造

image_gen.cgiは暗号化された確認キーを引数として受け取り、keyinit.plを通じて復号し、CAPTCHA画像を出力する役割を持つ。これを下記のように書き換えた。

#!/usr/bin/perl --
#
# 確認キー用画像表示モジュール
# GD::SecurityImage 版に改造(2017.9.27)by niga

require './keyinit.pl';
use GD::SecurityImage;

# パラメータ受け取り
$val = $ENV{'QUERY_STRING'};
$val =~ s/<//g;
$val =~ s/>//g;
$val =~ s/"//g;
$val =~ s/&//g;
$val =~ s/\s//g;
$val =~ s/\r\n//g;
$val =~ s/\r//g;
$val =~ s/\n//g;

# 確認キーデコード
($text,$old_time) = &de_key($val);
if($space){ $text =~ s/(\w)/$1 /g; chomp($text); }

#---------------------------------------------------
# GD::SecurityImage での画像作成

$image = GD::SecurityImage->new(
   width => $captcha_w,
   height => $captcha_h,
   lines => $line_n,
   thickness => $line_w,
   bgcolor => $bg_color,
   font => $ttf_font,
   ptsize => $font_size,
 # rnd_data => [ 'A' .. 'Z' ],
   rndmax => '4',
   scramble => '0',
   angle => '0',
   );

$image->random($text); #文字列の定義
$image->create('ttf', $style, $font_color, $line_color);
$image->particle($density, $maxdots);

# 画像書き出し
my($image_data, $mime_type, $text) = $image->out( force => 'gif');

#----------ファイル出力テスト用
#print "$mime_type, $text\n";
#open my $fh, '>', "$text.gif";
#binmode($fh);
#print $fh $image_data;
#close($fh);

#----------画像出力用
print "Content-type: image/gif\n\n";
binmode(STDOUT);
print $image_data;
undef $image;
exit;

これらの改修にて、BBSのcgi上でCAPTCHA画像の生成と認証が正常にできるようになった。Image::Magickを使った時と比べてやや単調なイメージになってしまうが、一応キーは暗号化されているし、ロボットSPAMに対しては一定の抑止力にはなるだろう。

開発環境のインストール

Synology DS216jをWEBサーバーとして設定する備忘録、前回からの続き。

BBSのCAPTCHA画像の生成には旧blog記事に書いたようにこちらのサイトのスクリプトを利用させてもらっている。導入前はSPAM投稿が頻繁にみられていたが、ここ数年SPAMを削除した記憶がないので効果はかなりあったと思う。今ではCAPTCHAはAIで解読できるらしく、時代遅れという説もあるが、現時点ではSPAMの被害はゼロといってよく、当面はこのまま様子を見ることにしたい。

運用中のCAPTCHA生成スクリプトは、画像イメージの作成にImage::Magickというperlのモジュールを必要とする。インストールはyumやcpanといったパッケージマネージャ経由か、ソースパッケージからのビルドで行うが、このNASでyumは使えないようなのでソースパッケージをビルドできるように開発環境をインストールすることにした。

パッケージマネージャーのインストール

まずは、Entware-ngというパッケージ管理ソフトをインストールするが、こちらのサイトの記載通りの手順でできた。これでopkgコマンドが使えるようになるのでPackages listを見てsectionがdevelとなっているものは一通りインストールしておいた。

また、Synologyの開発環境のインストールとして、こちらのサイトを参考にして、DS216jと互換性のあるDSM Tool Chainをインストールした。これでソースパッケージのビルドができるようになるはず。

Image::Magickがインストールできない

Entware-ngのPackages listを見ると、imagemagickのインストールに対応しているが、cgiから利用するにはこれだけではだめで、PerlモジュールのImage::Magick(perl-magick)のインストールも必要となる。残念ながらopkgではperl-magickのインストールは出来ないようだが、opkgでCPAN(perlbase-cpan)をインストールすればCPAN経由でImage::Magickをインストールできるかも、ということでやってみる。下記はエラー無く完了。


これはインストールの途中で、ccache-gccが無いというエラーが出て止まってしまう。Cコンパイラの動作を高速化するキャッシュだそうだが、ccasheのソースパッケージをビルドしてインストールしてみたが解決しなかった。パスを通してもccache-gccとしてシンボリックリンクを貼ってもダメ。たぶん、上でインストールしたDSM Tool Chainにccacheが入っていないのがご不満なのだろうと思う。

CPAN経由は諦めて、Image::Magickのソースパッケージを展開してビルドしてみたが、sudo make installの段階で「致命的エラー」が出て終了。

CGIからPHPは使えるか

どうやってもImage::Magickがインストールできなかったので、方針転換して画像生成を他の方法で行うことにした。SecureimageというPHPスクリプトを使うと、比較的簡単かつ凝ったCAPTCHAイメージを作れるらしいということで、試してみた。

こちらのサイトを参考に、Secureimageをサーバーに展開し、BBSのcgiのCAPTCHAイメージ挿入部分を下記のように書き換えてみたところ、綺麗に表示されるようになった。


表示までは簡単であったが、ここからが問題。キーの認証はどうするのか。perlとphpに互換性はないので別々にスクリプトを動かすことになるが、引数のやりとりに難があるし、セキュリティ上も好ましくないことが分かったため、この方法は却下となった。

perl / cgiスクリプト実行環境の整備

前回からの続き。SynologyのNASはDSM経由でapache,perlのインストールができるが、任意のディレクトリでcgiを動作させるためにはコンフィギュレーションファイル等の編集による設定が必要。以下に設定した項目について覚書として記録しておく。

 httpd22.confの設定

DSMではapache2.2と2.4のインストールに対応しているが、2.4は何かとトラブルが多いとの話なのでapache2.2で運用することにした。この場合設定ファイルはhttpd22.confとなり、これをroot権限で書き換える。

以下のようにcgiを動作させたいディレクトリの分だけhttpd22.confに追記する。.htaccessファイルを置く方法もあるが、httpd22.confに記述したほうがパフォーマンスが良いらしい。

<Directory /var/services/web/bbs>
   AllowOverride None
   Options +ExecCGI
   Order allow,deny
   Allow from all
</Directory>

 

httpd.conf内のAddHandlerの記述に追記して.plファイルもcgiスクリプトとして設定する。

AddHandler cgi-script .cgi .pl

 

なお、viの操作は、iキーで挿入モード、escで戻り、:wで上書き、:qで終了。設定を有効にするにはapacheのrestartが必要であるがDSM上で停止、始動が可能。

cgiファイルの編集

cgiファイルの先頭のperlのパスを明示する部分については、下記のようにしておけばOK。

#!/usr/local/perl --

パーミッション設定

cgi,plファイルの属性はchmod 755 で変更しておく。ログファイルは666、書き込みの発生するディレクトリは777にしておく。

jcode.plの修正

perlのバージョン違いによりjcode.plがエラーを吐くようになったため、下記を参考にjcode.plを書き換えた。http://icepotato.cocolog-nifty.com/blog/2014/04/jcodepldefinedh.html

ここまでやって、BBSのログが表示されるようになったがCAPTCHA画像が出てこない。これについてはまた次回。