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

huacnlee · 发布于 2015年10月26日 · 最后由 huacnlee 回复于 2017年1月22日 · 12408 次阅读
De6df3
本帖已被设为精华帖!

社区里面已经有好多寻找 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

效果

共收到 110 条回复
15

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

De6df3

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

808

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

1638

开发速度好快

15999

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

3406

比easy_captcha好看多了 :thumbsup:

96

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

96

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

De6df3

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

8

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

SimpleCaptcha.backend = :quick_magick
2203

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

21131

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

De6df3

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

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

3406

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

De6df3

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

14006

@huacnlee 已经用了,谢谢!

20974

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

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

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

11354

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

11354

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

15999

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

9592

赞!

2419

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

756

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

De6df3

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

96

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

De6df3

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

96

#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'

跟这个有关系吗?

De6df3

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

96

#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)
96

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

4521

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

96

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

37楼 已删除
808

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

10594

收藏一下,哈哈

20960

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

19199

:plus1:

23231

收藏,晚点试试。

4115

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

15999

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

De6df3

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

15999

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

96

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

96

thin 也没问题

2564

#44楼 @embbnux

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

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

De6df3

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

@embbnux @sforce100

15999

#50楼 @huacnlee 赞!!!

15999

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

1638

cool!

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

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

De6df3

Oh 忘了确保目录存了

13883

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

De6df3

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

13883

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

13684

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

De6df3

#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
13684

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

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

De6df3

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

63楼 已删除
3444

这个并不完美~

verify_rucaptcha? 这里有逻辑不全, 攻击者只需要手动填写一次验证码即可利用这个 session 使用脚本继续刷注册..

15999

#64楼 @flypiggys #62楼 @huacnlee 修复得好快,刚想发pull request已经修复了,感觉直接在每次verify删掉session比较好,设置过期时间太繁杂了

13684

@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

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

De6df3

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

De6df3

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

13684

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

De6df3

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

13684

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

De6df3

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

13684

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

De6df3

#73楼 @ren_jiaxing

$ brew uninstall imagemagick

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

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

3444

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

96

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

De6df3

#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
1173

昨天加上RuCaptcha,今天半夜已经被破解了,开始设置了4位验证码,改成6位还是不行,implode设置的0.4. 后来根据@larryzhao 的推荐换了 http://geetest.com/ ,暂时挡住了,还在观察效果。

23361

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

23361

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

De6df3

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

De6df3

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

14006

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

De6df3

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

0.3.1 已经发布了

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

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

1173

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

9861

赞一个

96

@huacnlee 不能设置 width 和height了?

96

感觉上 右空间不满

23315

有几个问题想请问一下

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

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

7754

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

16701

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

16701

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

20859

收藏了,感谢楼主

16701

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

16701

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

De6df3

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

16701

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

101楼 已删除
23028

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

3489

@huacnlee grape里使用RuCaptcha吗

16701

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

96

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

De6df3

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

15820

我报了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

96

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

737f5d

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

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

Eda824

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

3673

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

96

好热闹的帖子

De6df3

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

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

De6df3 huacnlee 关闭了讨论 1月22日 10:39
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册