简体   繁体   English

shopify hmac 验证 php

[英]shopify hmac verification php

This is my code :这是我的代码:

function verifyRequest($request, $secret) {
  // Per the Shopify docs:
  // Everything except hmac and signature...

  $hmac = $request['hmac'];
  unset($request['hmac']);
  unset($request['signature']);

  // Sorted lexilogically...
  ksort($request);

  // Special characters replaced...
  foreach ($request as $k => $val) {
    $k = str_replace('%', '%25', $k);
    $k = str_replace('&', '%26', $k);
    $k = str_replace('=', '%3D', $k);
    $val = str_replace('%', '%25', $val);
    $val = str_replace('&', '%26', $val);
    $params[$k] = $val;
  }

  echo $http = "protocol=". urldecode("https://").http_build_query( $params) ;
  echo $test = hash_hmac("sha256", $http , $secret);

  // enter code hereVerified when equal
  return $hmac === $test;
}

The hmac from shopi and hmac created from my code is not matching. shopi 的 hmac 和从我的代码创建的 hmac 不匹配。

What am I doing wrong?我究竟做错了什么?

You only need to include the request parameters when creating the list of key-value pairs - don't need "protocol=https://".您只需要在创建键值对列表时包含请求参数 - 不需要“protocol=https://”。

https://help.shopify.com/api/getting-started/authentication/oauth#verification https://help.shopify.com/api/getting-started/authentication/oauth#verification

You'll need to urldecode() the result of http_build_query().您需要对 http_build_query() 的结果进行 urldecode()。 It returns a url-encoded query string.它返回一个 url 编码的查询字符串。

http://php.net/manual/en/function.http-build-query.php http://php.net/manual/en/function.http-build-query.php

Instead of:代替:

 echo $http = "protocol=". urldecode("https://").http_build_query( $params) ;
 echo $test = hash_hmac("sha256", $http , $secret);

Something like this:像这样的东西:

 $http = urldecode(http_build_query($params));
 $test = hash_hmac('sha256', $http, $secret);

hmac can be calculated in any programming language using sha256 cryptographic algorithm.可以使用 sha256 加密算法在任何编程语言中计算 hmac。

However the doc for hmac verification is provided by shopify but still there is confusion among app developers how to implement it correctly.然而,shopify 提供了 hmac 验证的文档,但应用程序开发人员仍然对如何正确实施它感到困惑。

Here is the code in php for hmac verification.这是php中用于hmac验证的代码。 Ref.参考http://code.codify.club http://code.codify.club

<?php

function verifyHmac()
{
  $ar= [];
  $hmac = $_GET['hmac'];
  unset($_GET['hmac']);

  foreach($_GET as $key=>$value){

    $key=str_replace("%","%25",$key);
    $key=str_replace("&","%26",$key);
    $key=str_replace("=","%3D",$key);
    $value=str_replace("%","%25",$value);
    $value=str_replace("&","%26",$value);

    $ar[] = $key."=".$value;
  }

  $str = join('&',$ar);
  $ver_hmac =  hash_hmac('sha256',$str,"YOUR-APP-SECRET-KEY",false);

  if($ver_hmac==$hmac)
  {
    echo 'hmac verified';
  }

}
?>

Notice for other requests like the App Proxy a HMAC will not be preset, so you'll need to calculate the signature.请注意,对于App Proxy等其他请求,不会预设 HMAC,因此您需要计算签名。 Here a function that caters for both types of requests including webhooks:这里有一个函数可以满足包括 webhooks 在内的两种类型的请求:

public function authorize(Request $request)
{
    if( isset($request['hmac']) || isset($request['signature']) ){
        try {
            $signature = $request->except(['hmac', 'signature']);

            ksort($signature);

            foreach ($signature as $k => $val) {
                $k = str_replace('%', '%25', $k);
                $k = str_replace('&', '%26', $k);
                $k = str_replace('=', '%3D', $k);
                $val = str_replace('%', '%25', $val);
                $val = str_replace('&', '%26', $val);
                $signature[$k] = $val;
            }

            if(isset($request['hmac'])){
                $test = hash_hmac('sha256', http_build_query($signature), env('SHOPIFY_API_SECRET'));

                if($request->input('hmac') === $test){
                    return true;
                }
            } elseif(isset($request['signature'])){
                $test = hash_hmac('sha256', str_replace('&', '', urldecode(http_build_query($signature))), env('SHOPIFY_API_SECRET'));

                if($request->input('signature') === $test){
                    return true;
                }
            }
        } catch (Exception $e) {
            Bugsnag::notifyException($e);
        }
    } else { // If webhook
        $calculated_hmac = base64_encode(hash_hmac('sha256', $request->getContent(), env('SHOPIFY_API_SECRET'), true));

        return hash_equals($request->server('HTTP_X_SHOPIFY_HMAC_SHA256'), $calculated_hmac);
    }

    return false;
}

The above example uses some Laravel functions, so уоu may want to replace them if you use a different framework.上面的例子使用了一些 Laravel 函数,所以如果你使用不同的框架,你可能想要替换它们。

I've got the following to do this:我有以下几点来做到这一点:

// Remove the 'hmac' parameter from the query string
$query_string_rebuilt = removeParamFromQueryString($_SERVER['QUERY_STRING'], 'hmac');
// Check the HMAC
if(!checkHMAC($_GET['hmac'], $query_string_rebuilt, $shopify_api_secret_key)) {
    // Error code here
}

/**
 * @param string $comparison_data
 * @param string $data
 * @param string $key
 * @param string $algorithm
 * @param bool $binary
 * @return bool
 */
function checkHMAC($comparison_data, $data, $key, $algorithm = 'sha256', $binary=false) {
    // Check the HMAC
    $hash_hmac = hash_hmac($algorithm, $data, $key, $binary);
    // Return true if there's a match
    if($hash_hmac === $comparison_data) {
        return true;
    }
    return false;
}

/**
 * @param string $query_string
 * @param string $param_to_remove
 * @return string
 */
function removeParamFromQueryString(string $query_string, string $param_to_remove) {
    parse_str($query_string, $query_string_into_array);
    unset($query_string_into_array[$param_to_remove]);
    return http_build_query($query_string_into_array);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM