名称: 安全编码 描述: 提供安全编码实践指导,包括OWASP Top 10 2025、CWE Top 25、输入验证、输出编码和语言特定的安全模式。用于代码安全漏洞审查、安全控制实施或学习安全开发实践。 允许工具: 读取、全局、搜索、任务
安全编码
编写安全代码的全面指导,涵盖OWASP Top 10 2025、CWE Top 25和语言特定的安全模式。
何时使用此技能
在以下情况使用此技能:
- 审查代码以查找安全漏洞
- 实施输入验证或输出编码
- 学习常见安全弱点(OWASP、CWE)
- 修复已识别的安全问题
- 编写安全敏感代码(认证、授权、数据处理)
- 进行安全代码审查
OWASP Top 10 2025 快速参考
| 排名 | 漏洞 | 关键缓解措施 |
|---|---|---|
| A01 | 访问控制失效 | 服务器端访问检查、默认拒绝、CORS限制 |
| A02 | 安全配置错误 | 硬化配置、移除默认设置、禁用不必要功能 |
| A03 | 软件供应链故障 | SCA、SBOM、验证依赖、完整性检查 |
| A04 | 加密失效 | 强加密(AES-256)、TLS 1.2+、不使用已弃用算法 |
| A05 | 注入攻击 | 参数化查询、输入验证、上下文感知编码 |
| A06 | 不安全设计 | 威胁建模、安全设计模式、深度防御 |
| A07 | 认证失败 | 多因素认证、强密码、安全会话管理 |
| A08 | 数据完整性故障 | 数字签名、完整性验证、安全CI/CD |
| A09 | 日志记录与告警故障 | 集中式日志记录、异常检测、审计追踪 |
| A10 | 异常处理不当 | 安全失败、通用错误消息、完整异常处理 |
详细缓解措施: 见 OWASP Top 10 2025 参考
核心安全编码原则
1. 输入验证
永远不要信任用户输入。 在服务器端验证所有输入。
using System.Text.RegularExpressions;
// 好:服务器端验证,使用白名单
public static partial class InputValidation
{
[GeneratedRegex(@"^[a-zA-Z0-9_]{3,20}$")]
private static partial Regex UsernamePattern();
/// <summary>
/// 根据白名单模式验证用户名。
/// </summary>
public static bool ValidateUsername(string username) =>
!string.IsNullOrEmpty(username) && UsernamePattern().IsMatch(username);
}
// 坏:无验证
public string ProcessUsername(string username) => username; // 危险!
验证策略:
- 白名单验证:定义允许的内容(首选)
- 黑名单验证:定义不允许的内容(安全性较低)
- 类型检查:确保正确数据类型
- 范围检查:验证值在预期范围内
- 长度限制:防止缓冲区溢出和DoS
2. 输出编码
根据上下文编码输出,以防止注入攻击。
| 上下文 | 编码方法 | 示例 |
|---|---|---|
| HTML 正文 | HTML 实体编码 | <script> |
| HTML 属性 | 属性编码 | ' 对应 ' |
| JavaScript | JavaScript 编码 | \x3Cscript\x3E |
| URL 参数 | URL 编码 | %3Cscript%3E |
| CSS | CSS 编码 | \3C script\3E |
| SQL | 参数化查询 | 使用预编译语句 |
3. 参数化查询(注入预防)
数据库操作始终使用参数化查询。
// 好:使用 SqlCommand 的参数化查询
using var cmd = new SqlCommand(
"SELECT * FROM Users WHERE Username = @username AND Status = @status",
connection);
cmd.Parameters.AddWithValue("@username", username);
cmd.Parameters.AddWithValue("@status", status);
// 好:使用 Dapper 的参数化查询
var users = await connection.QueryAsync<User>(
"SELECT * FROM Users WHERE Username = @Username AND Status = @Status",
new { Username = username, Status = status });
// 坏:字符串插值(SQL 注入易受攻击)
var query = $"SELECT * FROM Users WHERE Username = '{username}'"; // 易受攻击
4. 认证安全
- 使用强密码哈希:Argon2id、bcrypt、scrypt(见
cryptography技能) - 实施多因素认证:基于时间的OTP、硬件密钥、通行密钥
- 安全会话管理:HttpOnly cookie、安全标志、短过期时间
- 账户锁定:防止暴力攻击
- 凭证存储:永不存储明文密码
5. 授权安全
- 默认拒绝:要求显式权限授予
- 服务器端检查:永不依赖客户端授权
- 验证对象所有权:检查用户可以访问请求的资源
- 使用间接引用:映射内部ID到用户特定引用
- 实施RBAC/ABAC:使用结构化访问控制模型
6. 错误处理
// 好:向用户返回通用错误消息,详细日志记录
public async Task<IActionResult> ProcessData([FromBody] DataRequest request)
{
try
{
await _dataService.ProcessSensitiveDataAsync(request.Data);
return Ok();
}
catch (DbException ex)
{
_logger.LogError(ex, "用户 {UserId} 处理请求时数据库错误", User.GetUserId());
return StatusCode(500, new { error = "发生错误" });
}
}
// 坏:暴露内部细节
catch (DbException ex)
{
return StatusCode(500, new { error = ex.Message }); // 易受攻击 - 暴露内部
}
错误处理规则:
- 向用户返回通用错误消息
- 服务器端记录详细错误
- 永不暴露堆栈跟踪、数据库错误或内部路径
- 安全失败(出错时拒绝访问)
语言特定模式
JavaScript/TypeScript
// XSS 预防 - 使用 textContent,而不是 innerHTML
element.textContent = userInput; // 安全
element.innerHTML = userInput; // 易受攻击
// 必须渲染HTML时使用 DOMPurify
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
// 避免 eval() 和 Function()
eval(userInput); // 易受攻击
new Function(userInput)(); // 易受攻击
// 使用严格模式
'use strict';
C# / .NET
// 安全进程执行 - 使用参数列表,避免外壳
using System.Diagnostics;
public static async Task<string> SafeExecuteAsync(string command, params string[] args)
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = command,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false, // 安全:无外壳解释
CreateNoWindow = true
}
};
foreach (var arg in args)
process.StartInfo.ArgumentList.Add(arg); // 安全:无需外壳转义
process.Start();
var output = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();
return output;
}
// 坏:外壳注入易受攻击
Process.Start("cmd", $"/c dir {userInput}"); // 易受攻击
// 安全文件操作 - 防止路径遍历攻击
public static class SafeFileAccess
{
/// <summary>
/// 安全读取文件,防止路径遍历攻击。
/// </summary>
public static string SafeReadFile(string baseDir, string filename)
{
var basePath = Path.GetFullPath(baseDir);
var filePath = Path.GetFullPath(Path.Combine(baseDir, filename));
if (!filePath.StartsWith(basePath, StringComparison.OrdinalIgnoreCase))
throw new UnauthorizedAccessException("检测到路径遍历");
return File.ReadAllText(filePath);
}
}
// 使用 Entity Framework 的参数化查询
var users = context.Users
.Where(u => u.Username == username) // 安全 - 参数化
.ToList();
// 尽可能避免原始SQL,如需使用参数
var users = context.Users
.FromSqlRaw("SELECT * FROM Users WHERE Username = {0}", username)
.ToList();
// CSRF 保护的防伪令牌
[ValidateAntiForgeryToken]
public IActionResult UpdateProfile(ProfileModel model)
{
// 处理更新
}
// 使用数据注解进行输入验证
public sealed class UserInput
{
[Required]
[StringLength(100, MinimumLength = 3)]
[RegularExpression(@"^[a-zA-Z0-9_]+$")]
public required string Username { get; init; }
}
安全代码审查清单
输入处理
- [ ] 所有输入在服务器端验证
- [ ] 尽可能使用白名单验证
- [ ] 强制执行长度限制
- [ ] 执行类型检查
- [ ] 验证文件上传(类型、大小、内容)
输出编码
- [ ] 应用上下文适当的编码
- [ ] 不在HTML/JS/SQL中使用原始用户输入
- [ ] 正确设置 Content-Type 头
- [ ] X-Content-Type-Options: nosniff
认证
- [ ] 强密码哈希(Argon2id/bcrypt)
- [ ] 会话令牌随机且不可预测
- [ ] 注销时使会话无效
- [ ] 失败尝试后账户锁定
- [ ] 仅通过HTTPS传输凭证
授权
- [ ] 每个请求都有访问控制
- [ ] 默认拒绝策略
- [ ] 对象级别授权检查
- [ ] 不暴露直接对象引用
数据保护
- [ ] 敏感数据在静态时加密
- [ ] 数据传输使用TLS 1.2+
- [ ] 不在URL或日志中存储敏感数据
- [ ] 适当的密钥管理
错误处理
- [ ] 向用户返回通用错误消息
- [ ] 安全记录详细错误
- [ ] 不暴露堆栈跟踪
- [ ] 安全失败(出错时拒绝)
快速决策树
您在解决什么安全问题?
- SQL/NoSQL注入 → 使用参数化查询、ORM
- XSS(跨站脚本) → 上下文感知输出编码、CSP
- CSRF → 防伪令牌、SameSite cookie
- 认证 → 见
authentication-patterns技能 - 授权 → 见
authorization-models技能 - 密码学 → 见
cryptography技能 - 机密/凭证 → 见
secrets-management技能 - API 安全 → 见
api-security技能
参考
- OWASP Top 10 2025 详细参考 - 完整缓解措施和示例
- CWE Top 25 参考 - 最危险的软件弱点
- 语言特定模式 - 各语言安全指南
相关技能
| 技能 | 关系 |
|---|---|
authentication-patterns |
认证实现细节(JWT、OAuth、通行密钥) |
authorization-models |
访问控制(RBAC、ABAC) |
cryptography |
加密、哈希、TLS |
api-security |
API特定安全模式 |
secrets-management |
凭证和机密处理 |
版本历史
- v1.0.0 (2025-12-26): 初始发布,包含OWASP Top 10 2025、核心原则
最后更新: 2025-12-26