Gem 完美的 Ruby 图形验证码 Gem - RuCaptcha

huacnlee · October 26, 2015 · Last by huacnlee replied at January 22, 2017 · 37349 hits
Topic has been selected as the excellent topic by the admin.

社区里面已经有好多寻找 Ruby 验证码库的帖子了:

但其实包括我在内一直没有一个好的选择,原因:

  • 大多数现有的验证码库是基于 RMagick 实现的,这东西用起来困难,依赖 ImageMagick 版本,还有内存泄露风险,比如 simple_captcha, easy_captcha
  • 另外一类是基于文本问答形式的,比如 gotcha, humanizer
  • 还有种是三方服务,比如 Google 的 reCAPTCHA,但验证需要连 Google API 访问困难或缓慢;

今天 @lgn21st 说上周 Ruby China 邮件发送量异常,一看后台,注册表单被刷了...需要给注册页面和登陆页面加上验证码,至少能提高难度。

于是又开始寻找验现成证码库,结果查了半天,发现还是没有合适的... 无意中搜索到 Ruby China 上一个回帖 并尝试了一下,效果很好,另外这个方式也正好符合我的预期,没有 RMagick,是图形验证码,可定制。

于是包装成了一个 Gem 并改善了一下细节。

项目地址

https://github.com/huacnlee/rucaptcha

特点

  1. 不需要 RMagick,所以安装不再有困难、内存泄露也不再有了!
  2. 调用系统 ImageMagick 命令生成图片,效率高,和 mini_magick 机制一样;
  3. 使用简单;
  4. 自动化的文件缓存,减少图片生成时对 CPU 的开销;
  5. 漂亮!

使用方法

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

效果

建议加上配置噪点数量和干扰线正余弦

#2 楼 @huobazi 不懂正余弦,求完善

最近更新好迅速,这个不错。

开发速度好快

赞,之前找了好久没找到满意的

比 easy_captcha 好看多了 :thumbsup:

不错,很多应用都需要这个 :plus1:

view 添加代码后 undefined local variable or method `ru_captcha' for #<#Class:0xbc0a7e74:0xbc0a7424>

#10 楼 @guojhq 我说明文件漏掉了 Routes 的配置,补上了

其实 simple captcha 也可以不依赖 RMagick 的:

SimpleCaptcha.backend = :quick_magick

看到这个贴 .我立马登陆...试试..效果非常好喔!晚上试试...

有没有类似 refresh_button 的功能,重新刷一个验证码

#15 楼 @david_inner JS 实现一下,让 img src 重新设置一个,就可以了

可以参考:https://github.com/ruby-china/ruby-china/commit/f6f21b4f53272c8c9e25ab05c8a27a6b823012c9

验证码输错时现在显示的是繁体字 驗證碼不正確

#17 楼 @KoALa 已经修正了,等下一个版本发布

@huacnlee 已经用了,谢谢!

在本地用 homebrew 只装了 ImageMagick 没有装 ghostscript

结果图片死活没出来,也没看到错误。

总算搞定,遇到同样状况的可以试试看 ghostscript 装了没。

#21 楼 @excalibur 我本地装了 imagemagic 和 gs,还是白色的-。-

#22 楼 @crazyphage 好吧这个是版本问题

mac 下只装 ImageMagick,如楼上所说出不来,ubuntu 下没问题。装 ghostscript 试看看

不动则已,一动惊天动地...

RuCaptcha 中的 Ru 是什么意思?是 如意如意随我心意快快显灵快快显灵 吗 😄

#27 楼 @psvr 来自于 reCAPTCHA 的变形 re -> ru

什么图片显示不出来呢。。。又无异常出现。。初学 ruby on rails 求大神帮忙解决。

#29 楼 @bighuzi ImageMagick 装了没,看 Rails 控制台日志

#30 楼 @huacnlee

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'

跟这个有关系吗?

#31 楼 @bighuzi 我不知道,这个看不出问题,请在 GitHub Issue 上面提交完整的日志信息

#32 楼 @huacnlee

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)

#32 楼 @huacnlee 这是所有日志信息了。 初学。。求大神指教。。

#29 楼 @bighuzi 安装 ImageMagick 和 ghostscript 后应该可以解决,我刚开始也和你的现实一样

#35 楼 @zyjloveher 谢谢好人。。。

37 Floor has deleted

这个验证码不太好认。我每次都输错好多次 😢

收藏一下,哈哈

这个不错,我说怎么登录有验证码了

收藏,晚点试试。

验证码的预生成图片比较好吧。不知道即时生成对 cpu 影响多少

#43 楼 @sforce100 确实担心性能问题,如果爬虫一直请求改图片,应该会对 cpu 造成很大消耗。个人意见,生成的图片尺寸 10 多 k 的样子,可以考虑预存 10 个图片队列和它的值到 redis 里,每隔一定时间更新一下图片队列,请求的时候直接拿图片和存他的值到 session 就可以了。

#44 楼 @embbnux 如果加上那个就太复杂了,我会尝试一些其它方案,比如文件 cache 来优化,利用已有的验证码,每天换一批

#45 楼 @huacnlee 期待更新,版本更新好快 0.1.4 了

有没有人遇到使用 rails s -e production 能显示验证码图片,但是 nginx + passenge 显示不出图片

thin 也没问题

#44 楼 @embbnux

如果爬虫一直请求改图片,应该会对 cpu 造成很大消耗

不用担心吧,任何一个动态页面爬虫一直请求都会消耗 cpu

0.2.0 已经发布,文件缓存功能有了

@embbnux @sforce100

#49 楼 @kikyous 调用 imagick 的 convert 命令来生成图片应该比普通的请求消耗会大点,可以测试看看

Errno::ENOENT (No such file or directory @ dir_initialize - /home/ubuntu/projects/xxx/tmp/cache/rucaptcha):

从 0.1.4 升级到 0.2.0 之后,报错了呢?

Oh 忘了确保目录存了

结果是一片白色,没有报错,并且 imagemagick-6.9.1-4,ghostscript-9.16,是不是版本问题?

#56 楼 @cckkll Rails 控制台有错误信息吗?

#57 楼 @huacnlee 什么错误都没有

@huacnlee 我也是同样的情况 一片白色,版本 imagemagick-6.9.1-3 ghostscript-9.16

#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

@huacnlee

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)

没有报错 产生的图片就是一张白色的图片....

#61 楼 @ren_jiaxing 尝试新版本 0.2.3,如果有错,调用 /rucaptcha/ 路径,会有直接的异常抛出。

63 Floor has deleted

这个并不完美~

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

产生的图片为一张白色图片 啥也看不到....

#66 楼 @ren_jiaxing 你重启了没,如果验证码生成失败 0.2.3 会有异常的

#65 楼 @embbnux #64 楼 @flypiggys 0.2.5 增加了验证码的有效期,可以避免这个问题

#67 楼 @huacnlee 重新启动了,我觉得验证码没有失败 生成成功了 不过不知道神马原因 都是白色的...

#69 楼 @ren_jiaxing#60 楼 那段命令,执行看看结果什么样的

@huacnlee 运行的结果是产生了一张白色的图片 不知道是里面的字是白色的还是生成有问题 有啥办法可以看不?会不会是 ghostscript 版本的问题?

#71 楼 @ren_jiaxing 你用我那段脚本执行出来是白色的图?

#72 楼 @huacnlee 对的出现的是白色图片 我贴出来

#73 楼 @ren_jiaxing

$ brew uninstall imagemagick

然后重新安装试试,另外你可以尝试一下 ImageMagick 官方关于 draw 这页的命令,看看是否能生成出来

http://www.imagemagick.org/Usage/draw/

#68 楼 @huacnlee 那个回帖里的代码就是作者在极客公园写下的…现在我们时不时的还会被刷注册,每次 sendgrid 都被暂停,session 这个问题是我之前排除过的一个原因,但依然没有根治……因为满足不了现在需求正好在重写用户中心,重构完如果还不能根治就得把代码开源出来大家来找茬了😂😂😂

@huacnlee (RuCaptcha: convert: unrecognized option `-sketch'.) 这是少什么?

#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/ ,暂时挡住了,还在观察效果。

为什么 rucaptcha_input_tag 产生的 input type 是 email ? 郁闷了好半天。。。。

#78 楼 @xmonkeycn 赞,可是收费的。。。

#79 楼 @hechao051 让移动设备上默认键盘是英文的

#78 楼 @xmonkeycn 你网站地址多少,我看看可能的原因

#82 楼 @huacnlee 那个 type = email 触发了 html5 的 email 验证!

#84 楼 @colorfulberry #79 楼 @hechao051 #78 楼 @xmonkeycn

0.3.1 已经发布了

  • 增加了复杂度,文字更加紧凑,干扰线和文字颜色接近,随机旋转正负 5°
  • input 文本框 type 的问题修正了

@huacnlee 好的,谢谢,升级去啰

#82 楼 @huacnlee iranshao.com, 不过我们已经换了 geetest 了。 更换以后还是一直在被拉验证码。 RuCaptcha::CaptchaController#index访问量高的时候有500多rpm

@huacnlee 不能设置 width 和 height 了?

感觉上 右空间不满

有几个问题想请问一下

  1. <%= rucaptcha_input_tag(class: 'form-control', placeholder: 'Input Captcha') %> 页面是其他人写的 我没办法加入这样的代码,能不能有一个图片文件直接发给前端呢 2.verify_rucaptcha?(@user) 这里验证的属性是什么 user 表有哪些字段才可以这样验证

@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)

#90 楼 @guojhq 右边的部分是白色的问题解决了么?

#93 楼 @warmwind 我也遇到这个问题,右边的白色太多了

这个非常好用,就是有一个问题,右边的空白太多了,能否居中显示文字和干扰线 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 指点

收藏了,感谢楼主

@huacnlee 右边有空白的问题解决了吗?

我改了下代码,最多能做到这样,但是这样似乎有些不安全

#97 楼 @goody9807 空白是由于随机线的长度造成的,你排版的时候让验证码图片在独立一行,不要在意它吧,像 Ruby China 登陆界面这样,看不出来

#99 楼 @huacnlee 谢谢,不过我的背景不是白色的,排版不太好排

101 Floor has deleted

想实现选择验证码,把正确的验证码和错误的混合在一起供用户选择,不知如何用 js 获取验证码

@huacnlee grape 里使用 RuCaptcha 吗

感谢楼主 0.3.2 完美解决右边空白问题,太感谢了!100 个赞!!!!

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,不懂,求解释

#105 楼 @whiney 不处理 Windows 的问题

我报了 libfreetype.6.dylib 相关的错误。 解决方案如下: brew uninstall --force freetype && brew install freetype 之后又报了 libpng 的错误 和上面的方法一样 brew uninstall --force libpng && brew install libpng

参考:https://github.com/Automattic/node-canvas/issues/471

@huacnlee 我这边部署好了,但是验证码不显示。能帮忙看看是什么情况吗?地址:http://115.28.165.211/

@huacnlee hi, 最近在一个项目里使用这个 gem,碰到一个疑问想请教一下。

在 form 里我希望在页面上直接做 client side validation, 简单来说就是在用户不输入验证码的时候直接在页面上显示提示信息并且不允许点击 submit。 为了达到这个效果我找了一个 gem 叫 client-side-validation 的,对于 rails 原生的 form helper 支持地很好,但是这里我不太明白怎样把 rucaptcha 给加进去,请问有没有什么想法能提供一下? 谢谢。

#105 楼 @whiney 刚刚处理了 Windows 下的开发问题,PR 17v0.3.2.1开始支持 Windows 下的开发。感谢@huacnlee

我觉得应该在 readme 里写一下 还要装一下 sudo apt-get install ghostscript

好热闹的帖子

RuCaptcha 2.0.0 发布了,不在需要 ImageMagick 啦

https://ruby-china.org/topics/32192

huacnlee closed this topic. 22 Jan 10:39
You need to Sign in before reply, if you don't have an account, please Sign up first.