2014-06-25

 

 

執筆中

 

 

C++によるCAPTCHA(画像認証)の実装です。

特徴は、

制限事項

万一プログラムが誤動作した際に、サーバ運営会社や他の利用ユーザに迷惑をかける恐れがあります。自分が管理権を持ったサーバーでのみ実行するなど、慎重に運用してください。このプログラムを使用したことによる結果について、作者は一切の責任を負いません。

インストール

captcha.tar.gz

上の書庫ファイルを展開して、captchaディレクトリに移動し、makeでコンパイルします。

実行に必要なファイルは次の通り。

ファイル名 属性 備考
captcha.cgi 755 CGI本体
captcha.digits.cgi 644 フォント画像
captcha.status.cgi (空のファイル) 666 セッション情報

上記すべてのファイルをバイナリモード(コード変換を行わない)でサーバに転送します。

CGIスクリプトに埋め込む

captcha.cgiをウェブブラウザから引数無しで実行すると、このページの上部に表示されているような「CAPTCHA」の文字が表示されます。もし、Internal Server Errorが表示される場合には、ファイルの属性と、転送モードを確認してください。特にバイナリモードで転送しないと絶対に動作しないので注意してください。

IDを生成する

captcha.cgiをスクリプトから、generate引数を付けて実行すると、id(識別コード)が帰ります。第二引数の数値は桁数を指定します。

Rubyでの例を示します。

captcha_id = `./captcha.cgi generate 3`.chomp

idは20桁のランダムな英数字から成ります。

画像を表示する

captcha.cgiをウェブブラウザからid引数を付けて実行すると、画像が表示されます。

Rubyでのフォームの実装例を示します。

<input type=hidden name=id value="#{captcha_id}">
<img src="captcha.cgi?id=#{captcha_id}"><br>
上に表示されている数字を入力して送信ボタンを押してください<br>
<input type=text name=captcha>

認証を行う

検証その1

captcha.cgiをスクリプトからfindコマンドとidを付けて実行すると、数値文字列が帰ります。この文字列と、フォームから入力された文字列を比較して、一致したら認証をパスしたことになります。

  error = ''
if cgi.has_key?('submit') && ENV['REQUEST_METHOD'].upcase == 'POST' captcha_id = cgi['id'] if captcha_id =~ /^[0-9A-Za-z]+$/ accept = false cap = `./captcha.cgi find #{captcha_id}`.chomp if cap != '' && cap == cgi['captcha'] accept = true else error += "画像認証が失敗しました。" end if accept # 更新処理を行う

検証その2

captcha.cgiをverifyコマンドとid、および比較文字列を付けて実行すると、成否が帰ります。

./captcha.cgi verify ug2UfSffnLNuJhOqqhQF 1,3:945

上の例では、2文字目(ゼロオーダーで1文字目)から始まる3桁が 945 であるかどうか検証し、一致した場合は標準出力に pass をを出力し、異なった場合は fail を出力します。

スクリプトから、captcha.cgiを起動する際、文字列にセミコロン ( ; ) やパイプ ( | ) などが含まれると、OSコマンドインジェクション脆弱性による攻撃ができる恐れがあり、最悪、OS環境を破壊することができてしまいますので、慎重に実装する必要があります。

 

 

 

 

執筆中

 

WordPressに組み込む

WordPress 3.9.1 に組み込んでみました。プラグインではありません。phpファイルを直接書き換えています。

wp-comments-post.php

130行目付近

	wp_die( __('ERROR: please type a comment.') );

$cap_id = trim($_POST['captcha_id']);
$captcha1 = trim($_POST['captcha1']);
$captcha2 = trim($_POST['captcha2']);
$captcha3 = trim($_POST['captcha3']);
if ( $captcha1 == ''
&& $captcha3 == ''
&& preg_match('/^[0-9]+$/', $captcha2)
&& preg_match('/^[0-9A-Za-z]+$/', $cap_id)
&& trim(exec(ABSPATH . 'captcha.cgi verify ' . $cap_id . ' 1,3:' . $captcha2)) == 'pass'
) {
// ok
} else {
wp_die( __('Error: CAPTCHA verification failed.') );
} $comment_parent = isset($_POST['comment_parent']) ? absint($_POST['comment_parent']) : 0;

wp-includes/comment-template.php

2200行目付近

        <?php echo $args['comment_notes_after']; ?>

<?php $cap_id = exec(ABSPATH . 'captcha.cgi generate 5'); ?>
<style>
<!--
#captcha1 {
display: none;
}
#captcha3 {
display: none;
}
-->
</style>
<p>CAPTCHA(画像認証)</p>
<p><img src=<?php echo site_url('captcha.cgi' . '?id=' . $cap_id); ?>></p>
<p>上の画像の<b>最初と最後を除いた3桁の数字</b>を入力して、送信ボタンを押してください。<br>
</p>
<p class="comment-form-captcha"><input id="captcha1" name="captcha1" type="text" style="width:5em;" /></p>
<p class="comment-form-captcha"><input id="captcha2" name="captcha2" type="text" style="width:5em;" /></p>
<p class="comment-form-captcha"><input id="captcha3" name="captcha3" type="text" style="width:5em;" /></p>
<input name="captcha_id" type="hidden" value="<?php echo $cap_id ?>" /> <p class="form-submit">

この例では、3つのテキストフィールドを用意し、そのうち1番と3番をダミーとし、2番目のフィールドのみ検証します。ダミーフィールドに値が入っていた場合は、即座に検証失敗とします。

 

 

 

プラグイン化や多言語化を行って頂ける、PHPに詳しくて親切な方、もしいらっしゃったらご連絡ください。

 

 

執筆中