Ruby on Rails で CAPTCHA を行う
長年メンテナンスしてきた幾多の掲示板 CGI がスパムに犯されているのを目の当たりにしているので、最近は CAPTHCA に大注目の私なのですが、今日は、Ruby on Rails による Web アプリケーションに割と簡単に CAPTCHA を導入する方法を紹介します。
使うのは Ruby/CAPTCHA というライブラリです。個人的には、それほど洗練されたライブラリだとは思っていないのですが、「とりあえず CAPTCHA をつけたい」と言った場合には必要十分です。
まず、Ruby/GD をインストールします。どこぞの Blog で Ruby/CAPTHCA は RMagick に依存すると書いてありましたが、Ruby/GD が正解です。インストールの仕方は以下を参照してください。「もう Ruby/GD は入ってるぜ!」という方は、freetype をサポートするビルドオプションをつけてインストールしたかを確認してください。
つぎに Ruby/CAPTCHA をインストールします。これは gem でふつうに入ります。
# gem install captcha
次に Controller を編集します(以下はクラス宣言部等は省略しています)。
gem 'ruby-gd' gem 'captcha' require 'captcha' def captcha w = CAPTCHA::Web.new # フォントの指定 w.font = "/usr/share/fonts/bitstream-vera/VeraBd.ttf" # 生成した CAPTCHA 用画像の保存先 w.image_dir = "/path/to/rails/public/images/captcha" w.font_size = 23 w.rotation = 28 w.x_spacing = 6 w.y_wiggle = 22 @image = w.file_name @digest = w.digest @image_width = w.image.width @image_height = w.image.height if params[:digest] && params[:key] if CAPTCHA::Web.is_valid(params[:key], params[:digest]) session[:captcha] = true redirect_to :action => "new" else flash[:notice] = "あなたは、本当に人間ですか?" end end end
最後に view を編集します。
<% form_tag :action => 'captcha' do %> <p><%= image_tag "captcha/#{@image}", :size => "#{@image_width}x#{@image_height}", :alt => "" %></p> <input type="text" name="key" value="" /> <input type="hidden" name="digest" value="<%= @digest %>" /> <%= submit_tag "認証" %> <% end %>
これで OK です。
この方法の難点をあげますと
1 に関しては、Ruby/CAPTHCA でも clean というメソッドで古い画像ファイルを消すことができるのですが、SAFE レベルが 2 以上だと動かないので私は使っていません。ただ、今後 FIX されることを期待して以下のようにオーバーライドして使っています。
module CAPTCHA class Web def clean Dir.foreach(@image_dir) do |entry| next if entry !~ /\.png$/ entry.untaint if Time.now - File.stat(File.join(@image_dir, entry)).mtime > @clean_up_interval File.delete(File.join(@image_dir, entry)) end end end end #class Web end #module CAPTCHA
これを用いる場合は file_name メソッドが呼ばれる瞬間に画像ファイルが生成されるのでその直前に以下のように追加します。
# 以下で指定した秒数以前のファイルは削除する w.clean_up_interval = 600 w.clean
2 に関しては、メッセージダイジェストから CAPTCHA 文字列を推測するのは容易なことではないし、やったとしても恐らく人が手で打つより遅いでしょうから、CAPTCHA の役目が著しく損なわれることはないでしょう(CAPTHCA 画像が OCR で突破されるのと同じぐらいのリスクかな?)。
3 に関してはなすすべなしです。以前紹介した JCapthca なら音声 CAPTCHA もできるようなので、そういった別のソリューションを用いるしかないと思います。