HMAC issue with GET values representing arrays

Shopify Partner
70 3 5

I've come up against a bit of an issue. After reading and re-reading the docs; I'm not finding anything all too helpful.

Here's the gig. I'm using your go-to php hmac verification process. Again - I know - I should have done this in Ruby, but what's done is done ... for now.

 

public function verifyHMAC(){
    // This should be called at the top of every embedded page.

    // Retrieve HMAC request parameter
    $hmac = $_GET['hmac'];

    // cut the hmac element
    $diff = ['hmac' => ''];
    $params = array_diff_key($_GET, $diff);

    // lexical sort
    ksort($params);

    $hmac_hash = hash_hmac('sha256', http_build_query($params), __API_SECRET_KEY);

    // Use hmac data to check that the response is from Shopify or not
    if(hash_equals($hmac, $hmac_hash)){

      // We're good - return TRUE
      return TRUE;
    }else die(__VERIFICATION_ERROR);
  }

So, I have 2 admin links setup; both are customer oriented. One from the customer profile (it returns the customer id in the get string) and the other in the customer list (it returns a get "array" of ids).

 

The single customer id; works fine, just like every other page in the app. The problem is when shopify kicks a get array back, as it does with a multiple customer select admin link, the verifyHMAC function shicks brits (no, it doesn't shave British people; I've simply employed a euphemistic spoonerism).

 

So, that's my issue. I've tried all sorts of permutations of the function. I've flattened the GET['ids'] array, I've removed the array, I've renamed the stupid things ... to no avail. Has anybody else come up against this issue?

 

The GET string that's being passed looks like this as far as ids go:

ids%5B%5D=9999999999&ids%5B%5D=8888888888

Whereas the output, if I vardump the array before I throw it through http_build_query looks like this:

ids%5B0%5D=9999999999&ids%5B1%5D=8888888888

Notice the '0' and '1' between the square brackets (aka: %5B and %5D) ... so my question is: why is Shopify sending me an obvious array without any indices? gah!

Thoughts? I'd love to hear them...

Most people, it turns out, just aren't interested unless they have to pay for it. Go figure.
0 Likes
Highlighted
Shopify Staff
Shopify Staff
481 62 72

Hey @PhobosTech,

 

Instead of using http_build_query($params), try file_get_contents("php://input") instead, this should make your verification function a little more robust.

 

@angeloghiotto shared a PHP function you can reference here.

1 Like
Highlighted
Shopify Partner
70 3 5

::EDIT::

Hrm - for a second I thought you were asking me to replace http_build_query with file_get_contents. Ok, I'll look at this and let you know. Thanks.

Most people, it turns out, just aren't interested unless they have to pay for it. Go figure.
0 Likes
Highlighted
Shopify Partner
70 3 5

Sorry, this isn't working for me.

It looked like the post you're referring to is in reference to using hooks. This isn't a hook; it's an embedded admin link. The hmac comes through GET vars, not through headers.

Most people, it turns out, just aren't interested unless they have to pay for it. Go figure.
0 Likes
Highlighted
Shopify Partner
70 3 5

@scottydont 

 

See, here's the problem I'm running into.

The following pages all work with my hmac verify function:

I've included 2 strings for each page. The first string is the actual query string straight from the server, with the hmac removed. Second string is the rebuild of the query string from GET variables to pass to the hash_hmac function. 

 

locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607384
locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607384


locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607384
locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607384


locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607384
locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607384


id=2295083958321&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607450
id=2295083958321&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607450


They all look fine, and they all pass the hmac verification.

 

Except for this page:

ids%5B%5D=2295083958321&ids%5B%5D=2612413792305&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607485
ids%5B0%5D=2295083958321&ids%5B1%5D=2612413792305&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607485


This one breaks. I though it was due to the added '0' and '1' between the encoded square brackets, %5B and %5D.

So I cleaned that out with this:

$data = preg_replace('/%5B([\d]+)%5D/','%5B%5D',$http_query);


And so now if we run that last page, the values returned are:

ids%5B%5D=2295083958321&ids%5B%5D=2612413792305&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607485
ids%5B%5D=2295083958321&ids%5B%5D=2612413792305&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580607485


Which are identical - yet hash_hmac()  evokes something else.

Here, I'll just show one of the working pages, and the broken one. The order of strings are:
query string w/out hmac, given hmac, generated hmac based on raw query string
query string built from GET vars, given hmac, generated hmac based on GET var query build
query string that's run through the above preg_replace() function and the hmac generated off of that  ... you tell me if this makes any sense:

locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580608649
b44fcf1a1e182f25b021a5aa53d95e05b9f0382d2a3114883bde4199c7464081
b44fcf1a1e182f25b021a5aa53d95e05b9f0382d2a3114883bde4199c7464081

locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580608649
b44fcf1a1e182f25b021a5aa53d95e05b9f0382d2a3114883bde4199c7464081
b44fcf1a1e182f25b021a5aa53d95e05b9f0382d2a3114883bde4199c7464081

locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580608649
b44fcf1a1e182f25b021a5aa53d95e05b9f0382d2a3114883bde4199c7464081
b44fcf1a1e182f25b021a5aa53d95e05b9f0382d2a3114883bde4199c7464081

Looks perfect. Here's the same output for the only page that's not working:

ids%5B%5D=2295083958321&ids%5B%5D=2612413792305&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580609075
3f83b55db69718134904cffe95c4f161d76a192a0dd5fbb2bea3feb37c78fdb7
dfcce85ff924f60fa6ea3e6335a9957d9bdd7b3b952a5d9660bcc3a05a17bc30

ids%5B0%5D=2295083958321&ids%5B1%5D=2612413792305&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580609075
09e3b95f049e1b3e4a7ebec6aa61987127e3bd175c8c491a046344b399ff6376
dfcce85ff924f60fa6ea3e6335a9957d9bdd7b3b952a5d9660bcc3a05a17bc30

ids%5B%5D=2295083958321&ids%5B%5D=2612413792305&locale=en&shop=nationwide-rewards.myshopify.com×tamp=1580609075
3f83b55db69718134904cffe95c4f161d76a192a0dd5fbb2bea3feb37c78fdb7
dfcce85ff924f60fa6ea3e6335a9957d9bdd7b3b952a5d9660bcc3a05a17bc30

It's not even the correct hmac generated straight from the SERVER query string. For whatever reason, it's just coming over bad. Obviously the middle one shouldn't match - which is fine - but the other two - I mean, c'mon. Something's broken and it ain't my code.

Most people, it turns out, just aren't interested unless they have to pay for it. Go figure.
0 Likes
Highlighted
Shopify Staff
Shopify Staff
481 62 72

Thanks @PhobosTech - I was able to replicate until modifying the format of the IDs. More info here: https://community.shopify.com/c/Shopify-Apps/Hmac-Verification-for-Bulk-Actions/m-p/590611/highlight...

 

Our docs don't seem to mention this - I'll chase it up. Thanks for flagging.

0 Likes