ArgumentError:字符串在设计可锁定模块中包含空字节

ArgumentError: string contains null byte in devise lockable module

提问人:Asad Shahid 提问时间:6/1/2023 更新时间:6/1/2023 访问量:85

问:

我正在使用 devise gem。当用户尝试解锁其帐户时,我收到 ArgumentError:string 包含空字节错误。

下面是我的应用的堆栈跟踪和环境:Here's the stacktrace and environment of my app:

ArgumentError: string contains null byte

at
exec_prepared(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/postgresql_adapter.rb:689)
 
at
block (2 levels) in exec_cache(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/postgresql_adapter.rb:689)
 
at
block in permit_concurrent_loads(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/dependencies/interlock.rb:48)
 
at
yield_shares(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/share_lock.rb:187)
 
at
permit_concurrent_loads(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/dependencies/interlock.rb:47)
 
at
block in exec_cache(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/postgresql_adapter.rb:688)
 
at
block (2 levels) in log(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract_adapter.rb:722)
 
at
block (2 levels) in synchronize(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26)
 
at
handle_interrupt(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25)
 
at
block in synchronize(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25)
 
at
handle_interrupt(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21)
 
at
synchronize(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21)
 
at
block in log(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract_adapter.rb:721)
 
at
instrument(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/notifications/instrumenter.rb:24)
 
at
log(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract_adapter.rb:712)
 
at
exec_cache(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/postgresql_adapter.rb:687)
 
at
execute_and_clear(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/postgresql_adapter.rb:658)
 
at
exec_query(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:98)
 
at
select_prepared(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract/database_statements.rb:493)
 
at
select_all(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract/database_statements.rb:68)
 
at
block in select_all(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract/query_cache.rb:105)
 
at
block in cache_sql(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract/query_cache.rb:122)
 
at
block (2 levels) in synchronize(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26)
 
at
handle_interrupt(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25)
 
at
block in synchronize(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25)
 
at
handle_interrupt(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21)
 
at
synchronize(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21)
 
at
cache_sql(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract/query_cache.rb:113)
 
at
select_all(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract/query_cache.rb:105)
 
at
find_by_sql(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/querying.rb:46)
 
at
block in exec_queries(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation.rb:821)
 
at
skip_query_cache_if_necessary(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation.rb:839)
 
at
exec_queries(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation.rb:808)
 
at
load(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation.rb:626)
 
at
records(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation.rb:250)
 
at
to_ary(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation.rb:245)
 
at
find_nth_with_limit(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation/finder_methods.rb:527)
 
at
find_nth(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation/finder_methods.rb:512)
 
at
first(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/relation/finder_methods.rb:120)
 
at
find_first(/app/vendor/bundle/ruby/2.7.0/gems/orm_adapter-0.5.0/lib/orm_adapter/adapters/active_record.rb:22)
 
at
find_first_by_auth_conditions(/app/vendor/bundle/ruby/2.7.0/gems/devise-4.7.1/lib/devise/models/authenticatable.rb:275)
 
at
find_or_initialize_with_errors(/app/vendor/bundle/ruby/2.7.0/gems/devise-4.7.1/lib/devise/models/authenticatable.rb:291)
 
at
send_unlock_instructions(/app/vendor/bundle/ruby/2.7.0/gems/devise-4.7.1/lib/devise/models/lockable.rb:172)
 
at
create(/app/vendor/bundle/ruby/2.7.0/gems/devise-4.7.1/app/controllers/devise/unlocks_controller.rb:13)
 
at
send_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal/basic_implicit_render.rb:6)
 
at
process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/abstract_controller/base.rb:195)
 
at
process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal/rendering.rb:30)
 
at
block in process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/abstract_controller/callbacks.rb:42)
 
at
block in run_callbacks(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/callbacks.rb:112)
 
at
block in included(/app/vendor/bundle/ruby/2.7.0/gems/sentry-raven-2.7.4/lib/raven/integrations/rails/controller_transaction.rb:7)
 
at
instance_exec(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/callbacks.rb:121)
 
at
block in run_callbacks(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/callbacks.rb:121)
 
at
run_callbacks(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/callbacks.rb:139)
 
at
process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/abstract_controller/callbacks.rb:41)
 
at
process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal/rescue.rb:22)
 
at
block in process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal/instrumentation.rb:33)
 
at
block in instrument(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/notifications.rb:180)
 
at
instrument(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/notifications/instrumenter.rb:24)
 
at
instrument(/app/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.4/lib/active_support/notifications.rb:180)
 
at
process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal/instrumentation.rb:32)
 
at
process_action(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal/params_wrapper.rb:245)
 
at
process_action(/app/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/railties/controller_runtime.rb:27)
 
at
process(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/abstract_controller/base.rb:136)
 
at
process(/app/vendor/bundle/ruby/2.7.0/gems/actionview-6.0.3.4/lib/action_view/rendering.rb:39)
 
at
dispatch(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal.rb:190)
 
at
dispatch(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_controller/metal.rb:254)
 
at
dispatch(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/routing/route_set.rb:50)
 
at
serve(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/routing/route_set.rb:33)
 
at
block in <class:Constraints>(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/routing/mapper.rb:18)
 
at
serve(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/routing/mapper.rb:48)
 
at
block in serve(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/journey/router.rb:49)
 
at
each(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/journey/router.rb:32)
 
at
serve(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/journey/router.rb:32)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/actionpack-6.0.3.4/lib/action_dispatch/routing/route_set.rb:834)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
call!(/app/vendor/bundle/ruby/2.7.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:192)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:169)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
call!(/app/vendor/bundle/ruby/2.7.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:192)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:169)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
call!(/app/vendor/bundle/ruby/2.7.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:192)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/omniauth-1.9.2/lib/omniauth/strategy.rb:169)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/omniauth-1.9.2/lib/omniauth/builder.rb:45)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/rack-attack-6.5.0/lib/rack/attack.rb:113)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
traced_call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/rack/agent_hooks.rb:30)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
traced_call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/rack/browser_monitoring.rb:32)
 
at
call(/app/vendor/bundle/ruby/2.7.0/gems/newrelic_rpm-6.8.0.360/lib/new_relic/agent/instrumentation/middleware_tracing.rb:99)
 
at
call(/app/app/middlewares/rescue_bad_request.rb:11)
Key --------------------------------------------Value
context----------------------------------------devise/unlocks#create
environment----------------------------------------production
framework----------------------------------------Rails: 6.0.3.4
language----------------------------------------ruby
request.POST.commit----------------------------------------Resend unlock instructions
**request.POST.user.email--------------------------------- ~Y**
request.body----------------------------------------{}
request.headers.Accept----------------------------------------text/html,application/xhtml+xml,application/xml; q=0.9,image/avif,image/webp,image/apng,*/*; q=0.8,application/signed-exchange; v=b3; q=0.7
request.headers.Accept-Encoding
gzip, deflate, br
request.headers.Content-Type----------------------------------------application/x-www-form-urlencoded; charset=utf-8
request.headers.Host----------------------------------------app.mywebsite.com
request.headers.Origin----------------------------------------https://app.mywebsite.com
request.headers.Referer---------------------------------------https://app.mywebsite.com/unlock/new
request.method----------------------------------------POST
request.params.action----------------------------------------create
request.params.controller----------------------------------------devise/unlocks
request.url----------------------------------------https://app.mywebsite.com/users/unlock
**request.headers.User-Agent----------------------------------------Mozilla/5.0 (compatible; Detectify) +https://detectify.com/bot/********-****-****-****-************

我不知道如何重现它。每次我输入任何字符串(UTF-8 除外)作为电子邮件时,我都会收到来自 devise 的“找不到电子邮件”消息,这是预期的行为。但是这个机器人以某种方式输入了这样一个字符串,导致异常 ArgumentError: string contains null byte in devise lockable module

我试图通过curl请求这个网址来重现它,如下所示:curl --request POST 'http://localhost:3000/users/unlock' --data 'commit=Resend unlock instructions&user[email]=~Y&authenticity_token=SfXU+dkGu1injlMNycmrHxHBmDV4Fkl9czU/B4/uKCgiZ1uA8SJVC6la2REKIaMw7GX16znJMYj9jxjwMo0BXg=='

请注意,这里我希望用户[电子邮件]是~Y,但我的终端以某种方式将其转换为~Y 然后我使用中间件将这封电子邮件的编码强制转换为 UTF-16,以便我可以使用它重现该问题(来自另一个 stackoverflow 问题)(Ruby on Rails “UTF-8 中的无效字节序列”由于机器人)


require 'rack'
require 'logger'
class HandleInvalidPercentEncoding
  DEFAULT_CONTENT_TYPE = 'text/html'
  DEFAULT_CHARSET      = 'utf-8'

  attr_reader :logger
  def initialize(app, stdout=STDOUT)
    @app = app
    @logger = defined?(Rails.logger) ? Rails.logger : Logger.new(stdout)
  end

  def call(env)
    begin
      request = Rack::Request.new(env.dup)
      if request.post? && request.url.include?('users/unlock')
        request.params['user']['email'] = request.params['user']['email'].force_encoding('UTF-16')
      end
      # if request.params.controller = devise/unlocks
      # URI.decode(string).force_encoding('UTF-8').valid_encoding?
      request.params
      @app.call(env)
    rescue ArgumentError => e
      # Encoding::CompatibilityError => e
      raise unless e.message =~ /invalid %-encoding/
      message = "BAD REQUEST: Returning 400 due to #{e.message} from request with env #{request.inspect}"
      logger.info message
      content_type = env['HTTP_ACCEPT'] || DEFAULT_CONTENT_TYPE
      status = 400
      body   = "Bad Request"
      return [
        status,
        {
           'Content-Type' => "#{content_type}; charset=#{DEFAULT_CHARSET}",
           'Content-Length' => body.bytesize.to_s
        },
        [body]
      ]
    end
  end

end

但即使在更改编码后,电子邮件仍保持原样,即 ~Y,与我的预期相反)(“\x7E\x59”) ...奇怪,我收到“找不到电子邮件”。请帮助我在其修复中重现错误

Ruby-on-Rails Ruby UTF-8 设计

评论


答: 暂无答案