【问题标题】:shopify hmac verification phpshopify hmac验证php
【发布时间】:2025-11-22 05:20:03
【问题描述】:

这是我的代码:

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 不匹配。

我做错了什么?

【问题讨论】:

    标签: php validation shopify hmac


    【解决方案1】:

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

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

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

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

    代替:

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

    【讨论】:

    • 这对我没有帮助:(
    【解决方案2】:

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

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

    这是用于hmac验证的php代码。 参考。 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';
      }
    
    }
    ?>
    

    【讨论】:

      【解决方案3】:

      注意App Proxy 等其他请求不会预设 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 函数,所以如果你使用不同的框架,你可能想要替换它们。

      【讨论】:

        【解决方案4】:

        我有以下工作要做:

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

        【讨论】:

          最近更新 更多