如何用SHA256withRSA解密验证签名?Webhook场景遇参数缺失难题
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 likenonce,timestampin 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 + transactionidin 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,
ImportSubjectPublicKeyInfoisn’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




