Browse Source

Escape ampersand in params or equal in keys before signing with hmac.

Dylan Thacker-Smith 9 years ago
parent
commit
9c66013b0a
3 changed files with 21 additions and 2 deletions
  1. 11 2
      lib/shopify_api/session.rb
  2. 1 0
      shopify_api.gemspec
  3. 9 0
      test/session_test.rb

+ 11 - 2
lib/shopify_api/session.rb

@@ -1,4 +1,5 @@
 require 'openssl'
+require 'rack'
 
 module ShopifyAPI
 
@@ -53,8 +54,16 @@ module ShopifyAPI
         params = params.with_indifferent_access
         return false unless signature = params[:hmac]
 
-        sorted_params = params.except(:signature, :hmac, :action, :controller).collect{|k,v|"#{k}=#{v}"}.sort.join('&')
-        OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new(), secret, sorted_params) == signature
+        calculated_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new(), secret, encoded_params_for_signature(params))
+
+        Rack::Utils.secure_compare(calculated_signature, signature)
+      end
+
+      private
+
+      def encoded_params_for_signature(params)
+        params = params.except(:signature, :hmac, :action, :controller)
+        params.map{|k,v| "#{URI.escape(k.to_s, '&=%')}=#{URI.escape(v.to_s, '&%')}"}.sort.join('&')
       end
     end
 

+ 1 - 0
shopify_api.gemspec

@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
   s.license = 'MIT'
 
   s.add_dependency("activeresource")
+  s.add_dependency("rack")
 
   dev_dependencies = [['mocha', '>= 0.9.8'],
                       ['fakeweb'], 

+ 9 - 0
test/session_test.rb

@@ -171,6 +171,15 @@ class SessionTest < Test::Unit::TestCase
       assert_equal true, ShopifyAPI::Session.validate_signature(params)
     end
 
+    should "return true when validating signature of params with ampersand and equal sign characters" do
+      ShopifyAPI::Session.secret = 'secret'
+      params = {'a' => '1&b=2', 'c=3&d' => '4'}
+      to_sign = "a=1%26b=2&c%3D3%26d=4"
+      params['hmac'] = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ShopifyAPI::Session.secret, to_sign)
+
+      assert_equal true, ShopifyAPI::Session.validate_signature(params)
+    end
+
     private
 
     def make_sorted_params(params)