跳转到主内容
极星编程网:以代码为星,赴技术山海!

防止SQL注入的开发培训_强化团队的安全编码意识

string.Replace不能防SQL注入,因其仅做文本替换,无法解决语义污染问题,且易漏Unicode变体、破坏正常数据、挡不住堆叠注入等;正确做法是全程使用参数化查询。 为什么
string.Replace
不能防 SQL 注入 因为替换只是文本处理,而 SQL 注入的本质是语义污染——攻击者靠拼接出合法但恶意的 SQL 语法来绕过检查。
string.Replace
对
'
或
--
的简单替换,既漏掉 Unicode 变体(如全角单引号)、又破坏正常数据(比如用户真名叫
O'Reilly
),还挡不住联合查询、堆叠注入等高级手法。 常见错误现象:
cmd.CommandText = "SELECT * FROM users WHERE name = '" + input.Replace("'", "''") + "'";
看似“转义”了,但遇到
; DROP TABLE users--
依然执行第二条命令。 永远别在拼接前做“关键词过滤”或“字符替换”,这属于防御性幻觉 所有用户输入进入 SQL 语句前,必须走参数化路径,不区分字段类型、不看输入内容 ORM 如 Entity Framework 的
.Where(x => x.Name == input)
默认走参数化,但手写
.FromSqlRaw
就立刻退化回风险区 如何正确用
SqlCommand.Parameters
绑定值 核心就一条:值进 SQL,只通过
Parameters.Add
或
Parameters.AddWithValue
,且绝不拼进
CommandText
字符串里。 使用场景:增删改查所有含用户输入的语句,包括
IN
子句、
ORDER BY
后的字段名(注意:字段名不能参数化,需白名单校验)。 参数差异:
AddWithValue
自动推断类型,但对
NULL
或空字符串可能误判为
varchar(1)
引发隐式转换;生产环境建议用
Add("@name", SqlDbType.NVarChar).Value = input
显式指定。
var cmd = new SqlCommand("SELECT * FROM products WHERE category = @cat AND price < @max", conn); cmd.Parameters.Add("@cat", SqlDbType.NVarChar).Value = userInputCategory; cmd.Parameters.Add("@max", SqlDbType.Money).Value = decimal.Parse(userInputPrice);
ExecuteScalar
和
ExecuteReader
也要防注入吗 要。只要 SQL 字符串里混入了未消毒的用户输入,不管用哪个执行方法,漏洞都存在。区别只在于攻击后果不同:
ExecuteScalar
可能被用来偷单个字段(如密码哈希),
ExecuteReader
更容易拖库。 容易踩的坑: 以为“只读查询就安全”,结果写成
"SELECT * FROM logs WHERE ip = '" + Request.UserHostAddress + "'"
在存储过程中拼接动态 SQL(如
EXEC('SELECT * FROM ' + @table)
),此时需用
sp_executesql
+ 参数,而非
EXEC
把参数化当成“万能胶”,却在同一条语句里混用:参数化一部分、拼接另一部分(如表名拼接 + 字段值参数化) 为什么 ORM 不等于自动免疫 Entity Framework、Dapper 这类工具默认对
.Where()
、
.Query()
等接口做参数化,但它们不拦截你主动写的原始 SQL。 典型翻车点: Dapper 的
connection.Query("SELECT * FROM users WHERE id = " + id)
—— 没有
@
符号,就是裸拼 EF Core 的
context.Users.FromSqlRaw("SELECT * FROM users WHERE name LIKE '%" + keyword + "%'")
——
FromSqlRaw
不处理参数,
FromSqlInterpolated
才安全 用 EF 动态构建表达式树时,误把用户输入塞进
Expression.Constant
当作字段名,实际应走白名单映射 最常被忽略的复杂点:多层封装后,SQL 构建逻辑可能散落在服务层、仓储层甚至自定义扩展方法里,人眼很难追踪哪一行悄悄拼了字符串。只要没看到
@
占位符和显式
Parameters
添加,就得怀疑。

相关文章