- Notifications
You must be signed in to change notification settings - Fork133
Captcha Gem for Rails, which generates captcha image by Rust.
License
huacnlee/rucaptcha
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Captcha Gem for Rails, which generates captcha image by Rust.
NOTE: According to the use of Ruby China, the verification code looks like has a lower than 5% probability of being parsed by OCR and the verification code is cracked (All Image Captcha libs are has same problem). It is recommended that you use the IP rate limit to enhance the protection.NOTE: 以 Ruby China 的使用来看,验证码似乎有低于 5% 的概率被 OCR 读取解析 (图片验证码都有这个问题) 导致验证码被破解(我们从日志分析绝大多数是成功的,但偶尔一个成功,配合大量机器攻击,导致注册了很多的垃圾账号),建议你额外配合 IP 频率限制的功能来加强保护。
如果你需要更高强度的验证,建议选择商用服务。
- Native Gem base on Rust.
- For Rails Application;
- Simple, Easy to use;
- High performance.
Put rucaptcha in yourGemfile
:
gem 'rucaptcha'
Createconfig/initializers/rucaptcha.rb
RuCaptcha.configuredo# Custom captcha code expire time if you need, default: 2 minutes# self.expires_in = 120 # [Requirement / 重要]# Store Captcha code where, this config more like Rails config.cache_store# default: Read config info from `Rails.application.config.cache_store`# But RuCaptcha requirements cache_store not in [:null_store, :memory_store, :file_store] # 默认:会从 Rails 配置的 cache_store 里面读取相同的配置信息,并尝试用可以运行的方式,用于存储验证码字符 # 但如果是 [:null_store, :memory_store, :file_store] 之类的,你可以通过下面的配置项单独给 RuCaptcha 配置 cache_store self.cache_store=:mem_cache_store# If you wants disable `cache_store` check warning, you can do it, default: false# 如果想要 disable cache_store 的 warning,就设置为 true,default false# self.skip_cache_store_check = true# Chars length, default: 5, allows: [3 - 7]# self.length = 5# Enable or disable Strikethrough, default: true# self.line = true# Enable or disable noise, default: false# self.noise = false# Enable or disable circle background, default: true# self.circle = true# Set the difficulty level, default: 5, allows: [1..10].# Only valid when noise is enabled# self.difficulty = 5# Set the case sensitive, default: false# self.case_sensitive = false# Set the image format, default: png, allows: [jpeg, png, webp]# self.format = 'png'# Custom mount path, default: '/rucaptcha'# self.mount_path = '/rucaptcha'end
RuCaptcha 没有使用 Rails Session 来存储验证码信息,因为 Rails 的默认 Session 是存储在 Cookie 里面,如果验证码存在里面会存在Replay attack 漏洞,导致验证码关卡被攻破。
所以我在设计上要求 RuCaptcha 得配置一个可以支持分布式的后端存储方案例如:Memcached 或 Redis 以及其他可以支持分布式的 cache_store 方案。
同时,为了保障易用性,默认会尝试使用:file_store
的方式,将验证码存在应用程序的tmp/cache/rucaptcha/session
目录(但请注意,多机器部署这样是无法正常运作的)。
所以,我建议大家使用的时候,配置上cache_store
(详见Rails Guides 缓存配置部分的文档)到一个 Memcached 或 Redis,这才是最佳实践。
(RuCaptha do not use Rails Session to store captcha information. As the default session is stored in Cookie in Rails, there's aReplay attack bug which may causes capthcha being destroyed if we store captcha in Rails Session.
So in my design I require RuCaptcha to configure a distributed backend storage scheme, such as Memcached, Redis or other cache_store schemes which support distribution.
Meanwhile, for the ease of use, RuCapthca would try to use:file_store
by default and store the capthca intmp/cache/rucaptcha/session
directory (kindly note that it's not working if deploy on multiple machine).
For recommendation, configure thecache_store
(more details onRails Guides Configuration of Cache Stores) to Memcached or Redis, that would be the best practice.)
Controllerapp/controller/account_controller.rb
When you calledverify_rucaptcha?
, it uses value fromparams[:_rucaptcha]
to validate.
classAccountController <ApplicationControllerdefcreate@user=User.new(params[:user])ifverify_rucaptcha?(@user) &&@user.saveredirect_toroot_path,notice:'Sign up successed.'elserender'account/new'endendendclassForgotPasswordController <ApplicationControllerdefcreate# without any argsifverify_rucaptcha?to_send_emailelseredirect_to'/forgot-password',alert:'Invalid captcha code.'endendend
TIP: Sometimes you may need to keep last verified captcha code in session on
verify_rucaptcha?
method call, you can usekeep_session: true
. For example:verify_rucaptcha? @user, keep_session: true
.
Viewapp/views/account/new.html.erb
<formmethod="POST"> ...<divclass="form-group"><%=rucaptcha_input_tag(class:'form-control',placeholder:'Input Captcha')%><%=rucaptcha_image_tag(alt:'Captcha')%></div> ...<divclass="form-group"><buttontype="submit"class="btn btn-primary">Submit</button></div></form>
And if you are usingDevise, you can read this reference to add validation:RuCaptcha with Devise.
for RSpec
describe'sign up and login',type::featuredobeforedoallow_any_instance_of(ActionController::Base).toreceive(:verify_rucaptcha?).and_return(true)endit{ ...}end
for MiniTest
classActionDispatch::IntegrationTestdefsign_in(user)ActionController::Base.any_instance.stubs(:verify_rucaptcha?).returns(true)postuser_session_path \'user[email]'=>user.email,'user[password]'=>user.passwordendend
When you are using this gem without Devise, you may find out that the invalid message is missing.For this case, use the trick below to add your i18n invalid message manually.
ifverify_rucaptcha?(@user) &&@user.savedo_whatever_you_wantredirect_tosomeplace_you_wantelse# this is the trick@user.errors.add(:base,t('rucaptcha.invalid'))render:newend
Based on MacBook Pro (Apple M3)
rake benchmark
to run benchmark test.
Warming up -------------------------------------- Generate image 84.000 i/100msCalculating ------------------------------------- Generate image 859.075 (± 1.5%) i/s (1.16 ms/i) - 4.368k in 5.085775s
About
Captcha Gem for Rails, which generates captcha image by Rust.