Квадратные скобки, нарушающие генерацию подписи OAuth - как их кодировать? - PullRequest
0 голосов
/ 30 ноября 2018

Я генерирую подпись OAuth с использованием Ruby для сайта, который использует OAuth.До сих пор все работало нормально, пока я не попытался добавить некоторые параметры в квадратных скобках.Теперь я получаю сообщение об ошибке «Подпись не соответствует».

Я предполагаю, что когда Оаут генерирует подпись, он имеет дело с квадратными скобками иначе, чем я с ними обращаюсь, когда генерирую свою подпись.

Вот как я генерирую свой сигнал OAuth (в Ruby):

oauth_params = {
  "oauth_consumer_key" => options["key"], #oAuth Consumer Key
  "oauth_nonce" => MiscUtilities.generate_nonce, #oAuth Nonce - just a random numnber
  "oauth_signature_method" => "HMAC-SHA1", #oAuth Signature Method - don't need to change this
  "oauth_timestamp" => Time.now.to_i.to_s, #oAuth Timestamp, standard seconds since epoch.
  "oauth_version" => "1.0" #oAuth Version - don't need to change this
}
#add any other non-oauth params we've been given
params = oauth_params.merge(options["params"])

#sort and url encode the params
encoded_params = params.sort_by{|k,v| k.to_s}.collect { |k, v| CGI.escape("#{k.to_s}=#{v}") }.join('%26')
signature_base_string = "#{options["method"]}&#{CGI.escape(options["api_url"])}&#{encoded_params}"
signing_key = "#{options["secret"]}&" 

#generate the signature and add it to params
digest = OpenSSL::Digest::Digest.new('sha1')
hmac = OpenSSL::HMAC.digest(digest, signing_key, signature_base_string)
params["oauth_signature"] = Base64.encode64(hmac).chomp
params  

Как я уже говорил, это работало нормально, пока я не добавил квадратные скобки в микс.

Кто-нибудь сталкивался с этой проблемой или мог видеть, что я могу делать неправильно, выше?

Ответы [ 3 ]

0 голосов
/ 19 января 2019

Вы не должны использовать CGI: Escape ни по URL, ни по всей паре ключ-значение.Его следует использовать на ключе и отдельно на значении.Затем эти два будут объединены знаком равенства, а затем эти пары будут добавлены в строку запроса, разделенную символом & '.

Кстати, я вижу, что вы объединяетесь с'% 26 '(закодировано&).Кажется, это не соответствует спецификации, разве что ваши базовые значения не нуждаются в кодировании?Это было бы эквивалентно «кодированию» значений, а затем кодированию всей строки.И, возможно, именно поэтому квадратные скобки вызвали проблему - как только вы добавили их к значению, это значение затем необходимо было закодировать.

 encoded_params = Map [params.map {|k, v| CGI.Escape(k), CGI.Escape(v)}]
                  .sort_by{|k,v| k.to_s}
                  .collect { |k, v| CGI.escape("#{k.to_s}=#{v}") }
                  .join('%26')

Я не рубиновый парень - я просто взялпример из ответа об обработке хеша и примененного здесь.Пожалуйста, сделайте то, что нужно сделать, чтобы сделать этот правильный код ruby.Я также сохранил остальную часть кода;хотя это может сбивать с толку, похоже, что это сработает.

Существует еще одна потенциальная проблема. Согласно спецификации, выполняемая кодировка URI может немного отличаться от обычной кодировки URI.Пробелы% 20 и не +, и все, кроме ALPHA, DIGIT, '_', '-', '.' И '~' должны быть закодированы, и эти значения не должны быть закодированы.Так это относится к CGI: Escape?У меня не установлен ruby, и моя быстрая проверка спецификации привела меня к однострочному документу.

edit: алгоритм выше не будет работать с вещами, которые нужно кодировать, потому что% 's из закодированных вещей будет также закодировано.Для кодирования всего значения требуется небольшая настройка, а не соединение с закодированными амперсандами.

0 голосов
/ 28 января 2019

Я закончил тем, что делал это, что я не считаю особенно чистым, но работает.

#New version following https://developer.twitter.com/en/docs/basics/authentication/guides/creating-a-signature.html
def oauth_signed_params(options)
  #defaults
  options["method"] ||= "POST"

  oauth_params = {
    "oauth_consumer_key" => options["key"], #oAuth Consumer Key
    "oauth_nonce" => generate_nonce, #oAuth Nonce - just a random number
    "oauth_signature_method" => "HMAC-SHA1", #oAuth Signature Method - don't need to change this
    "oauth_timestamp" => Time.now.to_i.to_s, #oAuth Timestamp, standard seconds since epoch.
    "oauth_version" => "1.0" #oAuth Version - don't need to change this
  }
  params = oauth_params.merge(options["params"])
  encoded_params = params.sort_by{|k,v| oauth_percent_encode(k.to_s)}.collect{|k, v| "#{oauth_percent_encode(k.to_s)}=#{oauth_percent_encode(v.to_s)}" }.join('&')

  signature_base_string = "#{options["method"]}&#{oauth_percent_encode(options["api_url"])}&#{oauth_percent_encode(encoded_params)}"
  signing_key = "#{options["secret"]}&" 

  #generate the signature and add it to params
  digest = OpenSSL::Digest::Digest.new('sha1')
  hmac = OpenSSL::HMAC.digest(digest, signing_key, signature_base_string)
  params["oauth_signature"] = Base64.encode64(hmac).chomp
  params     
end

#according to this twitter oauth doc, we actually only percent-encode a limited set of characters.  
#Others are left as is. The ones in the regex below are NOT encoded.
#https://developer.twitter.com/en/docs/basics/authentication/guides/creating-a-signature.html
def oauth_percent_encode(string)
  string.gsub(/[^a-zA-Z0-9\-\.\_\~]/){|match| match == " " ? "%20" : CGI.escape(match)}
end
0 голосов
/ 08 января 2019

Хитрость в том, что вам нужно дважды преобразовать квадратные скобки в базовой строке подписи:

  • [=>% 5B =>% 255B
  • ] =>% 5D =>% 255D
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...