You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP+CodeIgniter4验证Bluem支付Webhook签名(.crt文件)

在CodeIgniter 4中验证Bluem支付网关Webhook签名

Bluem的Webhook签名验证核心是用他们提供的公钥证书(.crt文件),验证其签名是否与接收到的Webhook请求体匹配,确保请求来自Bluem且未被篡改,以下是具体实现步骤和代码:

核心逻辑

Bluem使用自身私钥对Webhook的原始请求体进行签名,我们通过其提供的.crt公钥证书,验证该签名是否对应请求体,以此确认请求合法性。

实现步骤与代码

1. 获取原始请求数据与签名

在CodeIgniter 4中必须获取未解析的原始请求体(不能用getPost()等解析方法,否则会破坏签名验证的原始数据),同时提取请求头中的Signature字段:

2. 加载并解析.crt公钥证书

将Bluem提供的.crt文件放在非公开目录(如app/Config/),避免被外部直接访问,再通过OpenSSL函数从证书中提取公钥。

3. 执行签名验证

使用openssl_verify()函数完成验证,注意签名通常是Base64编码的,需要先解码。

完整控制器示例

<?php

namespace App\Controllers;

use CodeIgniter\Controller;

class BluemWebhook extends Controller
{
    public function handle()
    {
        // 获取原始请求体
        $rawBody = $this->request->getRawBody();
        
        // 获取Signature请求头
        $signature = $this->request->getHeaderLine('Signature');
        if (empty($signature)) {
            return $this->response->setStatusCode(400)->setJSON(['status' => 'error', 'message' => '缺少签名']);
        }
        
        // 加载证书文件(替换为你的实际路径)
        $certPath = APPPATH . 'Config/bluem_public.crt';
        if (!file_exists($certPath)) {
            return $this->response->setStatusCode(500)->setJSON(['status' => 'error', 'message' => '证书文件不存在']);
        }
        
        // 解析证书并提取公钥
        $cert = openssl_x509_read(file_get_contents($certPath));
        if (!$cert) {
            return $this->response->setStatusCode(500)->setJSON(['status' => 'error', 'message' => '无效的证书文件']);
        }
        
        openssl_x509_export($cert, $certString);
        $pubKey = openssl_pkey_get_public($certString);
        if (!$pubKey) {
            return $this->response->setStatusCode(500)->setJSON(['status' => 'error', 'message' => '提取公钥失败']);
        }
        
        // 解码签名(Bluem的签名通常是Base64编码)
        $decodedSignature = base64_decode($signature);
        if ($decodedSignature === false) {
            return $this->response->setStatusCode(400)->setJSON(['status' => 'error', 'message' => '签名格式无效']);
        }
        
        // 执行签名验证(确认Bluem的签名算法,默认用SHA256)
        $verifyResult = openssl_verify($rawBody, $decodedSignature, $pubKey, OPENSSL_ALGO_SHA256);
        
        // 释放OpenSSL资源
        openssl_x509_free($cert);
        openssl_pkey_free($pubKey);
        
        // 处理验证结果
        if ($verifyResult === 1) {
            // 签名验证通过,执行你的业务逻辑
            // 比如更新订单状态、记录日志等
            return $this->response->setStatusCode(200)->setJSON(['status' => 'success']);
        } elseif ($verifyResult === 0) {
            return $this->response->setStatusCode(403)->setJSON(['status' => 'error', 'message' => '签名无效']);
        } else {
            return $this->response->setStatusCode(500)->setJSON(['status' => 'error', 'message' => '签名验证过程出错']);
        }
    }
}

关键注意事项

  • 启用OpenSSL扩展:确保PHP环境已启用OpenSSL扩展,否则加密验证函数无法运行。
  • 确认签名算法:如果Bluem使用的不是SHA256,需替换openssl_verify中的算法常量(如OPENSSL_ALGO_SHA512),具体参考Bluem官方文档。
  • 原始请求体不可修改:必须使用接收到的原始请求体,不能添加、删除或修改任何字符(包括空格、换行),否则验证会失败。
  • 证书安全存储:.crt文件必须放在非Web可访问目录,防止被恶意下载。

内容的提问来源于stack exchange,提问作者Dhruv Pandya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:55:12