必须将DAdmin.GetList中字符串拼接的criteria.Condition改为参数化查询,删除string.Format("and Name like '%{0}%'", name)等危险写法,确保Common.GetPageData底层调用SqlCommand.Parameters.Add()并显式指定参数类型,同时立即限制数据库账号权限至最小必要范围。

直接改 DAdmin.GetList 里的拼接逻辑
你看到的 DAdmin.GetList 方法里用字符串拼接构建 criteria.Condition,这是最危险的源头。不要试图在 Action 层过滤参数,那只是掩耳盗铃——攻击者绕过前端、直接发 POST 或 GET 就能触发漏洞。
必须把拼接逻辑换成参数化查询。原代码中:criteria.Condition += string.Format("and Name like '%{0}%'", name) 这种写法必须删掉。
- 改用
SqlParameters:把name和loginName作为参数传入,而不是拼进 SQL 字符串 - LIKE 模糊匹配要手动加通配符:参数值应为
"%" + name + "%",而不是在 SQL 字符串里写'%{0}%' -
Common.GetPageData<T>必须支持参数化查询 —— 如果它底层仍用string.Format拼 SQL,那整个封装就无效
别依赖 ActionFilter 做“全局过滤”
网上流传的所谓“SQL 注入过滤 Attribute”,比如遍历所有 Action 参数、把单引号替换成两个单引号,是典型伪安全方案。它解决不了根本问题,还容易漏判、误杀、干扰正常业务(比如用户真要搜 O’Reilly)。
这类 Filter 在 MVC 5 中尤其不可靠:
- 只作用于 Controller 层参数,对 Model Binder 自动绑定的复杂对象(如嵌套类、集合)基本不生效
- 无法覆盖
Request.Form、Request.QueryString等原始输入,攻击者可绕过 Model Binding 直接构造请求 - 替换后可能破坏业务语义:把
1' OR '1'='1变成1'' OR ''1''=''1,但某些旧版数据库驱动仍会解析执行
检查 Common.GetPageData 是否真正参数化
很多项目把“封装了 DAL 层”当成安全背书,其实只要底层还是 string.Concat 或 string.Format 拼 SQL,再漂亮的封装也是纸老虎。
打开 Common.GetPageData 实现,重点看这几处:
- 是否调用了
SqlCommand的Parameters.Add()?不是cmd.CommandText = "select ... where x = '" + value + "'" - 是否用了
SqlParameter构造函数显式指定类型(如new SqlParameter("@name", SqlDbType.NVarChar)),而非仅传值 - 是否把
criteria.Condition当作完整 SQL 字符串交给ExecuteReader?如果是,说明整个分页框架本身就有注入风险
如果发现它仍是拼接模式,修复优先级高于任何上层改动 —— 否则所有 Controller 都在裸奔。
临时补救:强制启用最小数据库权限
在代码修复完成前,必须立刻降权。MVC 5 应用常默认用 sa 或 db_owner 账号连库,这是给攻击者递刀。
立即操作(SQL Server):
- 新建专用账号(如
webapp_reader),只授予SELECT权限,禁用INSERT/UPDATE/DELETE/DROP/EXECUTE - 确认连接字符串中用的是这个新账号,不是 Windows 认证或 sa
- 若业务真需要写操作,拆分账号:读用只读账号,写走另一套带严格参数校验的接口(且写账号仅授对应表的 CRUD 权限)
这种权限控制不是“锦上添花”,而是最后一道物理防线 —— 很多注入 payload 因缺乏执行权限而失效,比如 exec xp_cmdshell 或 union select load_file()。
真正麻烦的从来不是怎么写 Filter,而是找到所有拼 SQL 的地方;更麻烦的是,那些你以为“已经修好”的地方,其实还在用老方式执行查询。

















