Строка запроса Rails 3

Здесь очень странная ошибка. Мы правильно получаем запрос на что-то вроде "/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/ сообщает мне, что этот пользовательский агент IE9 работает в Windows 7, но мы не смогли воспроизвести ошибку.

Ответы

Ответ 1

Это, безусловно, проблема с кодировкой. Я использую Rails 4 сейчас, а следующая - примерная строка запроса моего текущего проекта. Обратите внимание, что самым первым параметром в querystring является "utf8 = ✓", который отсутствует в вашем запросе.

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

Попробуйте добавить "# encoding: UTF-8 в начале файла"

Ответ 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')