Solved

HMAC validation on bulk action (ids array)

ShinDHL
Shopify Partner
3 0 1

Hello,

I've added a bulk action link and while the default hmac validation works in all other cases, it fails on bulk action.

 

For example, if you add a bulk action "orders action drop-down", select multiple orders and then try to validate that request with hmac validation, none of the checks seem to work.

 

Multiple ids come in as ids[]=1234567890&ids[]=1234567891 etc.

 

There's actually no standard for arrays in queries, as it differs per language.

 

That said, the most common solution mentioned here is converting multiple 'ids[]' to a single key 'ids' with the value as a single string like '["1234567890", "1234567891"]' and then use that to validate.

 

However, I don't know what happened but since the last answer in 2020, but this does not work. So I've been guessing what the format should be for the last 5 hours, but to no avail.

I've also tried:
ids=["1234567890","1234567891"]
ids=['1234567890','1234567891']
ids=['1234567890', '1234567891']
ids[]=["1234567890", "1234567891"]
ids[]=['1234567890', '1234567891']
ids={"1234567890","1234567891"}

ids={"1234567890", "1234567891"}
ids={'1234567890','1234567891'}
ids={'1234567890', '1234567891'}

ids=[1234567890,1234567891]

ids=[1234567890, 1234567891]

Also tried shuffling the values in the array in case that matters for the lexicographical order. Of course, also tried using the param value as an actual array. Furthermore, also tried the more exotic 'solutions' found here, all of them very old and not working.

 

An up-to-date answer on what the format should be would be nice, unless we start recommending skipping validation the moment an array is found (which is a high security risk). I haven't seen any updated answer, does that mean no one is validating bulk action when using the bulk action extension?

 

Greetings,
Shin Ho
Plugin Development Team
DHL Parcel Netherlands

Accepted Solution (1)
Jason27
Shopify Partner
107 3 38

This is an accepted solution.

Yes it works perfect, heres the full function

  public function verifyHmac( $params ) {

        ///FIX FOR IDS[] INCLUDED HERE

        // Ensure shop, timestamp, and HMAC are in the params
        if (array_key_exists('shop', $params)
            && array_key_exists('timestamp', $params)
            && array_key_exists('hmac', $params)
        ) {
            // Grab the HMAC, remove it from the params, then sort the params for hashing
            $hmac = $params['hmac'];
            unset($params['hmac']);

            // Convert array values in the params to a string
            foreach($params as $key => &$value) {
                if (is_array($value)) {
                    $value = '["' . implode('", "', $value) . '"]';
                }
            }

            ksort($params);
            
            // Concatenate all of the params
            $paramsString = urldecode(http_build_query($params));

            // Return the comparison result
            return $hmac === hash_hmac('sha256', $paramsString, $this->getShopifyField('shopify_secret'));
        }
}

 

 

View solution in original post

Replies 4 (4)

Jason27
Shopify Partner
107 3 38

Did you find an answer to this? Having same issue... oh just found the solution to this using chatgpt:

 

 // Convert array values in the params to a string
            foreach($params as $key => &$value) {
                if (is_array($value)) {
                    $value = '["' . implode('", "', $value) . '"]';
                }
            }
ShinDHL
Shopify Partner
3 0 1

Did that chatgpt solution work for you? In my test that didn't work and it's already one of the solutions I've tried in the past. (Wrap in [ ], wrap values in double quotes, separated by comma and space).

Jason27
Shopify Partner
107 3 38

This is an accepted solution.

Yes it works perfect, heres the full function

  public function verifyHmac( $params ) {

        ///FIX FOR IDS[] INCLUDED HERE

        // Ensure shop, timestamp, and HMAC are in the params
        if (array_key_exists('shop', $params)
            && array_key_exists('timestamp', $params)
            && array_key_exists('hmac', $params)
        ) {
            // Grab the HMAC, remove it from the params, then sort the params for hashing
            $hmac = $params['hmac'];
            unset($params['hmac']);

            // Convert array values in the params to a string
            foreach($params as $key => &$value) {
                if (is_array($value)) {
                    $value = '["' . implode('", "', $value) . '"]';
                }
            }

            ksort($params);
            
            // Concatenate all of the params
            $paramsString = urldecode(http_build_query($params));

            // Return the comparison result
            return $hmac === hash_hmac('sha256', $paramsString, $this->getShopifyField('shopify_secret'));
        }
}

 

 

ShinDHL
Shopify Partner
3 0 1

Hi Jason27,

Thanks for providing the whole function. I found the difference on where it broke for my code:

I was lacking `urldecode()` on `http_build_query($params)` and that happened to coincidentally break the hmac checks on only bulk calls.

Thank you so much!

Greetings,
Shin