【问题标题】:Rails 3 query stringRails 3 查询字符串
【发布时间】:2014-03-18 13:20:23
【问题描述】:

这里非常奇怪的错误。我们正确地收到了类似“/users/8788234”的请求

在 Rails 中我们称之为:

redirect_to(:controller => 'login', :from_external_page => true, :on_login => request.env['REQUEST_URI']) and return

我们在 Rails 日志中看到(如我们所料): 重定向到

https://sampleapp.com/login?from_external_page=true&on_login=%2Fusers%2F8788234

但是我们从 IP 看到的下一个请求的查询字符串的值被打乱了:

Started GET "/login?from_external_page=gehr&on_login=%2Shfref%2S8788234" for xx.xxx.xxx.xxx at yyyy-mm-dd

这既使查询字符串值无意义,又导致以下错误:

ArgumentError: invalid %-encoding

(%2F 已更改为无效的 %2S)。查询字符串中每个键值对的每个值都移动了 13 个字符。每次我们看到这个,用户代理都会显示:“Mozilla/5.0(兼容;MSIE 9.0;Windows NT 6.1;WOW64;Trident/5.0)”,但我们也看到用户代理成功地导航应用程序。有没有人见过这样的事情? http://www.whatismybrowser.com/ 告诉我这个用户代理是在 Windows 7 上运行的 IE9,但我们无法重现该错误。

【问题讨论】:

  • 您是从用户那里得到报告,还是只在日志中看到这些事件?如果没有用户的报告,那么这些可能是模糊测试的结果吗?
  • 有趣!问题是他们正在关注电子邮件中的有效注册链接。是否有可能存在感染电子邮件然后使用凯撒密码的模糊攻击?
  • 这看起来不像是 Rails 错误,而是 MSIE9 中的错误。重定向将使用 302 状态代码发送回浏览器,然后浏览器会跟随该链接。可以肯定的是,使用 Wireshark(1) 记录网络流量,特别检查 302 响应是否损坏以及后续 GET 请求是否实际包含额外文本(它不是由您的 Web 服务器或其他 Rack 插件添加的。如果它不在网络上,请尝试使用不同的服务器(不是 Webrick)。(1) 是的,我知道这很难,因为您无法按需重现错误。但这是确定的唯一方法......
  • 听起来像是一个编码问题,正如@kdeisz 建议的那样,您的字符串值正在使用 rot13 / caesar 密码进行编码。 Rails 和浏览器可能会在下面进行一些奇怪的编码协商。非常仔细地检查您的标头和字符串编码。您使用的 Ruby 版本也可能会产生影响。 1.9 引入了正确的字符串编码。只有值(字符串)而不是符号会受到影响,这让人相信,而且它是在 urlencoding 之前完成的。
  • 我们还在对我们系统生成的电子邮件中引用的其中一个 URL 的请求中看到查询字符串的类似 ROT13 编码。同样,UA 是"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)。目前我只知道这些,但我们的网络应用是 Java,而不是 Rails。

标签: ruby-on-rails windows internet-explorer


【解决方案1】:

这肯定是编码问题。我现在正在使用 Rails 4,以下是我当前项目的示例查询字符串。请注意,查询字符串中的第一个参数是“utf8=✓”,您的查询字符串中缺少该参数。

profiles?utf8=✓&min_age=1&max_age=99&min_height=1&max_height=6&min_weight=1&max_weight=400

尝试添加"# encoding: UTF-8 at the beginning of the file"

【讨论】:

    【解决方案2】:

    如果有人好奇,我最终只是为嵌套查询字符串编写了一个中间件解析器,如果 13 个字符的移位使其有效,它会将其旋转回 13 个字符。我不会接受它作为答案,希望有人能够真正回答它。无论如何,这是我的方法:

    # used to parse out invalid query strings, attempt to fix them, and
    # handle the resulting query appropriately
    class InvalidEncodingParser
    
      # creates the middleware instance with a reference to the application
      def initialize(app)
        @app = app
      end
    
      # parse out bad queries, attempt to fix
      def call(env)
        begin
          # no need to scrub_nested_query if QUERY_STRING is blank or unescapable
          env['QUERY_STRING'].blank? or Rack::Utils.unescape(env['QUERY_STRING'])
        rescue ArgumentError
          env['QUERY_STRING'] = scrub_nested_query(env['QUERY_STRING'])
        end
        @app.call(env)
      end
    
      private
    
      # attempts to unescape both the query params and rot13 of the query params
      def scrub_nested_query(query_string = '')
        params = []
        (query_string || '').split(/[&;] */n).each do |param|
          if valid_query_param?(param)
            params << param
          elsif valid_query_param?(rotate_13_characters(param))
            params << rotate_13_characters(param)
          else
            raise ArgumentError
          end
        end
        params.join('&')
      end
    
      # applies a caesar cipher with a shift of 13 characters to the value of the
      # query key, value pair if the given param contains an equal sign
      def rotate_13_characters(param)
        key, value = param.split('=', 2)
        value.nil? ? param : (key + '=' + value.tr('A-Za-z', 'N-ZA-Mn-za-m'))
      end
    
      # attempts to unescape the param, returns false if it fails
      def valid_query_param?(param)
        param.blank? or Rack::Utils.unescape(param).present?
      rescue ArgumentError
        false
      end
    
    end
    

    ...然后将以下内容放在我的application.rb 文件的底部

    # Use invalid encoding middleware to parse out invalid encodings in the query string 
    # of the url and handle them appropriately 
    config.middleware.insert_before(ActionDispatch::ParamsParser, 'InvalidEncodingParser') 
    

    【讨论】:

      猜你喜欢
      • 2011-04-28
      • 2014-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多