shopify hmac验证php

shopify hmac验证php,php,validation,shopify,hmac,Php,Validation,Shopify,Hmac,这是我的代码: 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(

这是我的代码:

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;
}
shopi中的hmac与根据我的代码创建的hmac不匹配


我做错了什么?

在创建键值对列表时只需要包含请求参数,而不需要“protocol=https://”

您需要对http\u build\u query()的结果进行urldecode()。它返回一个url编码的查询字符串

而不是:

 echo $http = "protocol=". urldecode("https://").http_build_query( $params) ;
 echo $test = hash_hmac("sha256", $http , $secret);
大概是这样的:

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

hmac可以使用sha256加密算法在任何编程语言中计算

然而,用于hmac验证的文档是由shopify提供的,但是应用程序开发人员仍然对如何正确实现它感到困惑

以下是php中用于hmac验证的代码。 参考文献


其他请求(如HMAC)的通知将不会预设,因此您需要计算签名。这是一个满足两种类型请求(包括Webhook)的函数:

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;
}

上面的示例使用了一些Laravel函数,因此如果您使用不同的框架,您可能需要替换它们。

我有以下方法:

// 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);
}

这对我没有帮助:(
// 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);
}