如何验证ASP.NET Core 7 API输入的System.Uri安全性?
CallbackUrl安全验证补充与可信域名存储方案
一、强化CallbackUrl的安全验证
现有的基础验证还不够全面,建议补充以下几项检查,彻底防范恶意或无效URL:
强制HTTPS协议:确认令牌是敏感数据,必须通过HTTPS传输,避免明文泄露
if (url.Scheme != Uri.UriSchemeHttps) { return BadRequest("Callback URL必须使用HTTPS协议"); }限制合法端口:禁止使用SSH、远程桌面等高危端口,只允许业务常用的HTTPS端口
var allowedPorts = new HashSet<int> { 443, 8443 }; // 可根据业务调整 if (!allowedPorts.Contains(url.Port) && url.Port != -1) // Port=-1对应协议默认端口 { return BadRequest("Callback URL使用了未授权的端口"); }禁止预存参数/片段:防止恶意客户端提前注入参数,干扰后续确认令牌的拼接逻辑
if (!string.IsNullOrEmpty(url.Query) || !string.IsNullOrEmpty(url.Fragment)) { return BadRequest("Callback URL不能包含查询参数或锚点片段"); }校验主机名合法性:确保主机是有效的DNS域名或IP地址,避免畸形URL绕过验证
var hostType = Uri.CheckHostName(url.Host); if (hostType == UriHostNameType.Unknown) { return BadRequest("Callback URL的主机名格式无效"); }
二、可信域名存储方案选型
关于将URL主机与可信列表对比的需求,两种方案各有优劣,按需选择:
硬编码方案
- 适合场景:可信客户端数量极少(1-2个)、域名长期固定不变
- 优势:代码简单,无需数据库依赖,性能无损耗
- 实现示例:
var trustedDomains = new HashSet<string> { "client-a.com", "client-b.org" }; if (!trustedDomains.Contains(url.Host)) { return BadRequest("Callback URL主机不在可信名单内"); } - 缺点:域名变更必须重新部署API,灵活性差
数据库动态读取方案
- 适合场景:可信客户端较多、域名需要频繁添加/修改
- 优势:无需部署即可更新可信域名,支持后台动态管理
- 优化建议:搭配分布式缓存(如Redis)减少数据库查询压力,缓存有效期设为1-2小时即可
- 简化实现示例:
// 注入数据库上下文与缓存服务 private readonly AppDbContext _dbContext; private readonly IDistributedCache _cache; public TestController(AppDbContext dbContext, IDistributedCache cache) { _dbContext = dbContext; _cache = cache; } [HttpPost] public async Task<IActionResult> RegisterNewUser([FromBody] RegisterUserResource resource) { // ... 其他验证逻辑 var cacheKey = "TrustedDomainsList"; var cachedDomains = await _cache.GetStringAsync(cacheKey); HashSet<string> trustedDomains; if (cachedDomains == null) { // 从数据库读取并缓存 trustedDomains = new HashSet<string>(await _dbContext.TrustedDomains.Select(t => t.Domain).ToListAsync()); await _cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(trustedDomains), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) }); } else { trustedDomains = JsonSerializer.Deserialize<HashSet<string>>(cachedDomains); } if (!trustedDomains.Contains(url.Host)) { return BadRequest("Callback URL主机不在可信名单内"); } // ... 用户注册与邮件发送逻辑 return Ok(); }
内容的提问来源于stack exchange,提问作者Bob.at.Indigo.Health
相关产品推荐
相关产品推荐

