社区里面已经有好多寻找 Ruby 验证码库的帖子了:
但其实包括我在内一直没有一个好的选择,原因:
今天 @lgn21st 说上周 Ruby China 邮件发送量异常,一看后台,注册表单被刷了...需要给注册页面和登陆页面加上验证码,至少能提高难度。
于是又开始寻找验现成证码库,结果查了半天,发现还是没有合适的... 无意中搜索到 Ruby China 上一个回帖 并尝试了一下,效果很好,另外这个方式也正好符合我的预期,没有 RMagick,是图形验证码,可定制。
于是包装成了一个 Gem 并改善了一下细节。
https://github.com/huacnlee/rucaptcha
Gemfile:
gem 'rucaptcha'
config/routes.rb
增加 mount RuCaptcha:
Rails.application.routes.draw do
...
mount RuCaptcha::Engine => "/rucaptcha"
...
end
Controller app/controller/account_controller.rb
class AccountController < ApplicationController
def create
@user = User.new(params[:user])
if verify_rucaptcha?(@user) && @user.save
redirect_to root_path, notice: 'Sign up successed.'
else
render 'account/new'
end
end
end
View app/views/account/new.html.erb
<form>
...
<div class="form-group">
<%= rucaptcha_input_tag(class: 'form-control', placeholder: 'Input Captcha') %>
<%= rucaptcha_image_tag(alt: 'Captcha') %>
</div>
...
</form>
如果你需要定制一下,可以新建 config/initializes/rucaptcha.rb
RuCaptcha.configure do
# 配置 cache_store,类似 Rails 的 config.cache_store
# 与其它的验证码库不同, RuCaptcha 将验证码 code 存放在后端,而不是 Session,以避免 Session 重放攻击
# 你需要将 cache_store 配置在一个支持跨进程、跨服务器共享的地方,例如 Memcached, Redis 都可以
# 不可以用 file_store, null_store 或者 memory_store
# 因为这些存储方式无法跨进程或服务器,当多进程、服务器部署的时候验证码会验证不过。
self.cache_store = [:mem_cache_store, '127.0.0.1']
end
#3 楼 @huacnlee 其实是指 干扰线和字体的扭曲程度 eg: http://www.cnblogs.com/chengmo/archive/2010/12/06/1898062.html
view 添加代码后 undefined local variable or method `ru_captcha' for #<#Class:0xbc0a7e74:0xbc0a7424>
其实 simple captcha 也可以不依赖 RMagick 的:
SimpleCaptcha.backend = :quick_magick
#15 楼 @david_inner JS 实现一下,让 img src 重新设置一个,就可以了
可以参考:https://github.com/ruby-china/ruby-china/commit/f6f21b4f53272c8c9e25ab05c8a27a6b823012c9
在本地用 homebrew 只装了 ImageMagick 没有装 ghostscript
结果图片死活没出来,也没看到错误。
总算搞定,遇到同样状况的可以试试看 ghostscript 装了没。
ERROR Errno::ECONNRESET: Connection reset by peer @ io_fillbuf - fd:18
/Users/huzige/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:80:in `eof?'
/Users/huzige/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/httpserver.rb:80:in `run'
/Users/huzige/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread'
跟这个有关系吗?
D, [2015-10-28T17:41:30.913095 #15649] DEBUG -- :
D, [2015-10-28T17:41:30.913134 #15649] DEBUG -- :
D, [2015-10-28T17:41:30.913150 #15649] DEBUG -- :
D, [2015-10-28T17:41:30.913160 #15649] DEBUG -- :
I, [2015-10-28T17:41:30.913247 #15649] INFO -- : Started GET "/account/create" for 127.0.0.1 at 2015-10-28 17:41:30 +0800
I, [2015-10-28T17:41:30.913281 #15649] INFO -- : Started GET "/account/create" for 127.0.0.1 at 2015-10-28 17:41:30 +0800
I, [2015-10-28T17:41:30.918152 #15649] INFO -- : Processing by AccountController#create as HTML
I, [2015-10-28T17:41:30.918192 #15649] INFO -- : Processing by AccountController#create as HTML
I, [2015-10-28T17:41:30.920299 #15649] INFO -- : Rendered account/new.html.erb within layouts/account (0.3ms)
I, [2015-10-28T17:41:30.920351 #15649] INFO -- : Rendered account/new.html.erb within layouts/account (0.3ms)
I, [2015-10-28T17:41:30.920506 #15649] INFO -- : Completed 200 OK in 2ms (Views: 2.0ms | ActiveRecord: 0.0ms)
I, [2015-10-28T17:41:30.920532 #15649] INFO -- : Completed 200 OK in 2ms (Views: 2.0ms | ActiveRecord: 0.0ms)
D, [2015-10-28T17:41:30.931817 #15649] DEBUG -- :
D, [2015-10-28T17:41:30.931848 #15649] DEBUG -- :
D, [2015-10-28T17:41:30.931864 #15649] DEBUG -- :
D, [2015-10-28T17:41:30.931875 #15649] DEBUG -- :
I, [2015-10-28T17:41:30.931980 #15649] INFO -- : Started GET "/rucaptcha/" for 127.0.0.1 at 2015-10-28 17:41:30 +0800
I, [2015-10-28T17:41:30.932102 #15649] INFO -- : Started GET "/rucaptcha/" for 127.0.0.1 at 2015-10-28 17:41:30 +0800
I, [2015-10-28T17:41:30.936878 #15649] INFO -- : Processing by RuCaptcha::CaptchaController#index as HTML
I, [2015-10-28T17:41:30.936913 #15649] INFO -- : Processing by RuCaptcha::CaptchaController#index as HTML
I, [2015-10-28T17:41:30.958078 #15649] INFO -- : Rendered text template (0.0ms)
I, [2015-10-28T17:41:30.958136 #15649] INFO -- : Rendered text template (0.0ms)
I, [2015-10-28T17:41:30.958228 #15649] INFO -- : Sent data (0.5ms)
I, [2015-10-28T17:41:30.958247 #15649] INFO -- : Sent data (0.5ms)
I, [2015-10-28T17:41:30.958317 #15649] INFO -- : Completed 200 OK in 21ms (Views: 0.4ms | ActiveRecord: 0.0ms)
I, [2015-10-28T17:41:30.958341 #15649] INFO -- : Completed 200 OK in 21ms (Views: 0.4ms | ActiveRecord: 0.0ms)
#43 楼 @sforce100 确实担心性能问题,如果爬虫一直请求改图片,应该会对 cpu 造成很大消耗。个人意见,生成的图片尺寸 10 多 k 的样子,可以考虑预存 10 个图片队列和它的值到 redis 里,每隔一定时间更新一下图片队列,请求的时候直接拿图片和存他的值到 session 就可以了。
Errno::ENOENT (No such file or directory @ dir_initialize - /home/ubuntu/projects/xxx/tmp/cache/rucaptcha):
从 0.1.4 升级到 0.2.0 之后,报错了呢?
#59 楼 @ren_jiaxing #58 楼 @cckkll 请直接调用 http://localhost:3000/rucaptcha/ 并看日志是否有输出错误信息
另外尝试直接执行下面的命令,看看是否有错误信息,最后打开 ~/Desktop/foo.png 看看图片是否正常
convert -size 150x48 -fill 'rgba(111,34,125,1)' -draw 'text 5,5 "9"' -fill 'rgba(4,24,24,1)' -draw 'text 37,5 "4"' -fill 'rgba(115,103,3,1)' -draw 'text 69,5 "e"' -fill 'rgba(25,122,36,1)' -draw 'text 101,5 "d"' -draw 'stroke rgba(33,23,71,1) line 3,8 117,5' -draw 'stroke rgba(33,23,71,1) line 4,0 76,33' -draw 'stroke rgba(33,23,71,1) line 0,1 76,27' -wave 3x2 -gravity NorthWest -sketch 1x10+0 -pointsize 38 -weight 700 -implode 0.4 label:- png:- > ~/Desktop/foo.png
Started GET "/rucaptcha/" for 127.0.0.1 at 2015-11-02 14:08:05 +0800
Processing by RuCaptcha::CaptchaController#index as HTML
Rendered text template (0.4ms)
Sent data (8.1ms)
Completed 200 OK in 272ms (Views: 7.7ms)
没有报错 产生的图片就是一张白色的图片....
这个并不完美~
verify_rucaptcha?
这里有逻辑不全,攻击者只需要手动填写一次验证码即可利用这个 session 使用脚本继续刷注册..
#64 楼 @flypiggys #62 楼 @huacnlee 修复得好快,刚想发 pull request 已经修复了,感觉直接在每次 verify 删掉 session 比较好,设置过期时间太繁杂了
@huacnlee 直接访问还是没有报错 就是产生一张白色的图片... Started GET "/rucaptcha/" for 127.0.0.1 at 2015-11-02 17:14:56 +0800 Processing by RuCaptcha::CaptchaController#index as HTML Rendered text template (0.1ms) Sent data (4.4ms) Completed 200 OK in 231ms (Views: 4.1ms)
Using rucaptcha 0.2.3
产生的图片为一张白色图片 啥也看不到....
@huacnlee 运行的结果是产生了一张白色的图片 不知道是里面的字是白色的还是生成有问题 有啥办法可以看不?会不会是 ghostscript 版本的问题?
$ brew uninstall imagemagick
然后重新安装试试,另外你可以尝试一下 ImageMagick 官方关于 draw 这页的命令,看看是否能生成出来
#76 楼 @guojhq http://www.imagemagick.org/Usage/transform/#sketch 你的 ImageMagick 版本可能太老了,请确保 ImageMagick 版本在 6.9 以上
$ convert -version
Version: ImageMagick 6.9.2-5 Q16 x86_64 2015-11-01 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules
Delegates (built-in): bzlib freetype jng jpeg ltdl lzma png tiff xml zlib
昨天加上 RuCaptcha,今天半夜已经被破解了,开始设置了 4 位验证码,改成 6 位还是不行,implode 设置的 0.4. 后来根据@larryzhao 的推荐换了 http://geetest.com/ ,暂时挡住了,还在观察效果。
#84 楼 @colorfulberry #79 楼 @hechao051 #78 楼 @xmonkeycn
0.3.1 已经发布了
有几个问题想请问一下
@huacnlee 大神请问验证码图片没有显示的原因是什么,以下是终端返回的信息 Started GET "/rucaptcha/" for ::1 at 2015-11-26 15:08:57 +0800 Processing by RuCaptcha::CaptchaController#index as / Completed 500 Internal Server Error in 10ms (ActiveRecord: 0.0ms)
这个非常好用,就是有一个问题,右边的空白太多了,能否居中显示文字和干扰线 chars = code.split('') all_left = 50 font_size = RuCaptcha.config.font_size full_height = font_size full_width = (font_size * chars.size) size = "#{full_width}x#{full_height}" half_width = full_width / 2 full_height = full_height half_height = full_height / 2 text_top = 10 text_left = 5 - (font_size * 0.28).to_i stroke_width = (font_size * 0.08).to_i + 1 text_width = (full_width / chars.size) + text_left label = "=#{' ' * (chars.size - 1)}="
我看代码没有设置干扰线的位置,求 LZ 指点
#97 楼 @goody9807 空白是由于随机线的长度造成的,你排版的时候让验证码图片在独立一行,不要在意它吧,像 Ruby China 登陆界面这样,看不出来
windows 下,报这个错误:RuntimeError (RuCaptcha: D:/ruby/Ruby21-x64/lib/ruby/gems/2.1.0/gems/posix-spawn-0.3.11/lib/posix/spawn.rb:164: warning: cannot close fd before spawn 查找原因如下: pid, stdin, stdout, stderr = POSIX::Spawn.popen4(command) Process.waitpid(pid) err = stderr.read 初学 rails,不懂,求解释
我报了 libfreetype.6.dylib 相关的错误。
解决方案如下:
brew uninstall --force freetype && brew install freetype
之后又报了 libpng 的错误
和上面的方法一样
brew uninstall --force libpng && brew install libpng
@huacnlee hi, 最近在一个项目里使用这个 gem,碰到一个疑问想请教一下。
在 form 里我希望在页面上直接做 client side validation, 简单来说就是在用户不输入验证码的时候直接在页面上显示提示信息并且不允许点击 submit。 为了达到这个效果我找了一个 gem 叫 client-side-validation 的,对于 rails 原生的 form helper 支持地很好,但是这里我不太明白怎样把 rucaptcha 给加进去,请问有没有什么想法能提供一下? 谢谢。
RuCaptcha 2.0.0 发布了,不在需要 ImageMagick 啦