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

ASP.NET Core是否支持JSON Web Signature(RFC7515)用于RESTful API防篡改?

在ASP.NET Core中用JWS保护REST API请求防篡改的实现方案

完全可以用JSON Web Signature (JWS, RFC7515)来保护你的请求内容防篡改,正好适配你这种明文HTTP的场景——毕竟JWS的核心就是对内容进行签名验证,确保传输过程中内容没被篡改,同时内容本身是明文可见的,完全符合你的需求。

下面我会一步步带你在ASP.NET Core里实现这个方案,用自定义输入格式化器来处理JWS格式的请求体,自动完成签名验证并反序列化成你的CreateRequest对象:


1. 准备工作:安装依赖包

首先需要安装微软的JWT处理包,它原生支持JWS的解析和验证:

dotnet add package System.IdentityModel.Tokens.Jwt

2. 实现自定义JWS输入格式化器

我们需要创建一个自定义的InputFormatter,让ASP.NET Core能够识别并处理JWS格式的请求体,自动完成签名验证和反序列化:

using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Options;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using System.Text.Json;

public class JwsInputFormatter : InputFormatter
{
    private readonly JwtSecurityTokenHandler _tokenHandler;
    private readonly TokenValidationParameters _validationParams;

    public JwsInputFormatter(IOptions<JwsValidationSettings> settings)
    {
        _tokenHandler = new JwtSecurityTokenHandler();
        // 这里用对称密钥示例,生产环境可以换成RSA非对称密钥(更安全)
        _validationParams = new TokenValidationParameters
        {
            ValidateIssuer = false,       // 根据业务需求决定是否验证签发者
            ValidateAudience = false,     // 根据业务需求决定是否验证受众
            ValidateLifetime = false,     // 如果不需要过期时间验证可以关闭
            IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(settings.Value.SecretKey))
        };

        // 注册支持的JWS媒体类型
        SupportedMediaTypes.Add("application/jws");
        SupportedMediaTypes.Add("application/jose+json");
    }

    public override bool CanRead(InputFormatterContext context)
    {
        var contentType = context.HttpContext.Request.ContentType;
        return contentType != null && 
               (contentType.Contains("application/jws") || contentType.Contains("application/jose+json"));
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        var request = context.HttpContext.Request;
        using var reader = new StreamReader(request.Body);
        var jwsString = await reader.ReadToEndAsync();

        try
        {
            // 验证JWS签名并解析Token
            _tokenHandler.ValidateToken(jwsString, _validationParams, out var validatedToken);
            var jwtToken = validatedToken as JwtSecurityToken;

            if (jwtToken == null)
            {
                return await InputFormatterResult.FailureAsync();
            }

            // 将JWS的Payload反序列化成目标Model类型(这里是CreateRequest)
            var payload = JsonSerializer.Deserialize(jwtToken.Payload.SerializeToJson(), context.ModelType);
            return await InputFormatterResult.SuccessAsync(payload);
        }
        catch (SecurityTokenValidationException ex)
        {
            // 签名验证失败,将错误信息添加到ModelState
            context.ModelState.TryAddModelError(string.Empty, $"JWS签名验证失败: {ex.Message}");
            return await InputFormatterResult.FailureAsync();
        }
        catch (Exception ex)
        {
            context.ModelState.TryAddModelError(string.Empty, $"处理JWS请求失败: {ex.Message}");
            return await InputFormatterResult.FailureAsync();
        }
    }
}

// 用于配置JWS验证参数的实体类
public class JwsValidationSettings
{
    public string SecretKey { get; set; } = string.Empty;
}

3. 注册自定义格式化器到ASP.NET Core管道

在Program.cs中注册我们的格式化器和配置项:

var builder = WebApplication.CreateBuilder(args);

// 绑定JWS验证配置(从appsettings.json读取)
builder.Services.Configure<JwsValidationSettings>(builder.Configuration.GetSection("JwsValidation"));

builder.Services.AddControllers(options =>
{
    // 将自定义JWS格式化器添加到输入格式化器列表的最前面
    var jwsSettings = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<JwsValidationSettings>>();
    options.InputFormatters.Insert(0, new JwsInputFormatter(jwsSettings));
});

var app = builder.Build();

app.UseAuthorization();
app.MapControllers();
app.Run();

然后在appsettings.json中添加密钥配置(注意密钥要足够强,对称密钥建议至少16位以上):

"JwsValidation": {
  "SecretKey": "your-strong-256-bit-secret-key-here"
}

4. 修改控制器Action支持JWS请求

更新你的控制器Action,指定接受JWS格式的请求,并通过ModelState判断签名是否验证通过:

[Produces("application/json")]
[Route("api/WebService")]
public class WebServiceController : ControllerBase
{
    [HttpPost("CreateRequest")]
    [Consumes("application/jws", "application/jose+json")] // 指定接受的媒体类型
    public IActionResult Create([FromBody] CreateRequest request)
    {
        // 先检查JWS签名验证是否通过
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (request == null)
        {
            return BadRequest();
        }

        // 处理你的业务逻辑...
        return Ok();
    }
}

// 你的CreateRequest实体类示例
public class CreateRequest
{
    public string RequestId { get; set; } = string.Empty;
    public string Content { get; set; } = string.Empty;
}

5. 客户端如何发送JWS请求

客户端需要将CreateRequest序列化为JSON,然后生成JWS签名后发送,下面是C#客户端的示例代码:

using System.IdentityModel.Tokens.Jwt;
using System.Text;
using System.Text.Json;

// 与服务端共享的密钥
var secretKey = "your-strong-256-bit-secret-key-here";
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256);

// 创建要发送的请求对象
var requestObj = new CreateRequest { RequestId = "REQ-001", Content = "Test content" };
var payloadJson = JsonSerializer.Serialize(requestObj);

// 生成JWS
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = new JwtSecurityToken(
    signingCredentials: signingCredentials,
    payload: payloadJson
);
var jwsString = tokenHandler.WriteToken(jwtToken);

// 发送POST请求,指定Content-Type为application/jws
using var client = new HttpClient();
var content = new StringContent(jwsString, Encoding.UTF8, "application/jws");
var response = await client.PostAsync("http://your-api-url/api/WebService/CreateRequest", content);
response.EnsureSuccessStatusCode();

关键注意事项

  • 密钥管理:如果用对称密钥,必须确保客户端和服务端安全共享;生产环境推荐用RSA非对称密钥(客户端用私钥签名,服务端用公钥验证),避免密钥泄露风险。
  • 防重放攻击:如果需要防止请求被重复提交,可以开启ValidateLifetime,并在JWS中添加exp(过期时间)和nbf(生效时间)声明,同时可以结合唯一请求ID做额外校验。
  • 性能优化:高并发场景下,可以缓存验证密钥,避免重复创建密钥对象;也可以考虑异步验证逻辑。

内容的提问来源于stack exchange,提问作者Earl Sven

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:06:42