You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用SHA256withRSA解密验证签名?Webhook场景遇参数缺失难题

How to Verify SHA256withRSA Webhook Signature in C# (And Resolve Missing Parameters Issue)

Let’s tackle this problem step by step—first clearing up the parameter confusion, then walking through the C# implementation.

First: You Must Have the Missing Parameters (nonce, timestamp, transactionid)

The signature rule sign(apikey + nonce + timestamp + transactionid) only works if you have all four values to re-create the original signed string. There’s no way to verify the signature without nonce, timestamp, and transactionid—this is a fundamental part of how signature verification works (you need to hash the same data the server did, then check if the signature matches).

Here’s what to do:

  • Check the full Webhook response the server sends: these values are almost certainly included either in custom HTTP headers (e.g., X-Nonce, X-Timestamp, X-Transaction-Id) or in the request body payload (look for fields like nonce, timestamp in the JSON/XML response).
  • If you can’t find them, reach out to the service provider to confirm where these parameters are passed in the Webhook notification—they likely omitted this detail from the docs.

Second: C# Implementation for SHA256withRSA Verification

SHA256withRSA maps directly to RSASHA256 in .NET, and you can verify it using the native RSA class (no external libraries needed, unless you’re on an older .NET Framework version). Here’s a complete working example:

Step 1: Full Verification Code

using System;
using System.Security.Cryptography;
using System.Text;

public class WebhookValidator
{
    // Call this method when you receive the Webhook notification
    public bool IsWebhookSignatureValid(
        string apiKey,
        string nonce,
        string timestamp,
        string transactionId,
        string signatureFromHeader,
        string publicKeyPem)
    {
        // 1. Recreate the exact string the server signed (order matters!)
        string dataToVerify = apiKey + nonce + timestamp + transactionId;
        byte[] dataBytes = Encoding.UTF8.GetBytes(dataToVerify);

        // 2. Clean up the PEM public key (remove headers/whitespace)
        string cleanedPublicKey = publicKeyPem
            .Replace("-----BEGIN PUBLIC KEY-----", string.Empty)
            .Replace("-----END PUBLIC KEY-----", string.Empty)
            .Replace("\r", string.Empty)
            .Replace("\n", string.Empty);
        byte[] publicKeyBytes = Convert.FromBase64String(cleanedPublicKey);

        // 3. Import the public key into an RSA instance
        using (RSA rsa = RSA.Create())
        {
            // ImportSubjectPublicKeyInfo works for .NET Core 2.1+, .NET 5+, and .NET Framework 4.7.2+
            rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);

            // 4. Convert the signature from Base64 to bytes (adjust if the server uses Hex encoding!)
            byte[] signatureBytes = Convert.FromBase64String(signatureFromHeader);

            // 5. Verify the signature: SHA256withRSA uses PKCS#1 padding
            return rsa.VerifyData(
                dataBytes,
                signatureBytes,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1);
        }
    }
}

Key Notes to Avoid Mistakes:

  • Order of Data: Double-check that you’re concatenating apikey + nonce + timestamp + transactionid in the exact same order the server uses. Even a single misplaced value will make verification fail.
  • Signature Encoding: The example assumes the signature in the header is Base64-encoded. If the server uses Hex instead, replace Convert.FromBase64String(signatureFromHeader) with a helper method to convert Hex strings to byte arrays.
  • .NET Framework Compatibility: If you’re stuck on .NET Framework <4.7.2, ImportSubjectPublicKeyInfo isn’t available. Instead, you can use the BouncyCastle library to parse the PEM public key, or write a custom parser for the SubjectPublicKeyInfo structure (BouncyCastle is the easier route).

Example Usage

// Assume you extracted these values from the Webhook request:
string apiKey = "your-api-key";
string nonce = "abc123"; // From X-Nonce header or request body
string timestamp = "1699999999"; // From X-Timestamp header
string transactionId = "txn_12345"; // From X-Transaction-Id header or body
string signature = "abcdef..."; // From the signature header (e.g., X-Signature)
string publicKeyPem = "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----";

var validator = new WebhookValidator();
bool isSignatureValid = validator.IsWebhookSignatureValid(apiKey, nonce, timestamp, transactionId, signature, publicKeyPem);

if (isSignatureValid)
{
    // Trust the Webhook content
}
else
{
    // Reject the request—it might be tampered with
}

内容的提问来源于stack exchange,提问作者Kristijan Mirčeta

火山引擎 最新活动