PostgreSQL动态查询防SQL注入:Dapper参数化为何失效?
PostgreSQL动态查询中Dapper参数化失效的原因及解决办法
你遇到的问题核心不是动态查询本身的锅,而是你在拼接SQL时没正确使用Dapper的参数化机制,直接把_Chapter的原始值拼进了SQL字符串里,等于绕过了Dapper的防护。
Dapper的参数化防注入原理,是靠把SQL语句和参数值分开传递给数据库——数据库会先解析SQL结构,再把参数值当成纯数据代入,不会把参数里的字符当成SQL逻辑的一部分。但如果你直接用字符串拼接(比如把_Chapter的值用+或者$拼进SQL),那传入的恶意内容(比如01' or 8519=8519--)就会被当成SQL的一部分执行,自然触发注入。
举个典型的错误写法(不管用不用Dapper都会中招):
// 错误:直接拼接参数值到SQL var sql = $"SELECT * FROM foo WHERE chapter = '{_Chapter}'"; var result = connection.Query(sql);
正确的做法是全程用参数占位符,哪怕是动态拼接SQL片段也一样:
情况1:简单动态条件
直接用Dapper的参数占位符(PostgreSQL推荐用:前缀):
var sql = "SELECT * FROM foo WHERE chapter = :Chapter"; var result = connection.Query(sql, new { Chapter = _Chapter });
情况2:多条件动态拼接SQL
用StringBuilder拼SQL框架,参数单独用DynamicParameters传递:
var sqlBuilder = new StringBuilder("SELECT * FROM foo WHERE 1=1"); var parameters = new DynamicParameters(); if (!string.IsNullOrEmpty(_Chapter)) { sqlBuilder.Append(" AND chapter = :Chapter"); parameters.Add("Chapter", _Chapter); } // 其他条件同理... var result = connection.Query(sqlBuilder.ToString(), parameters);
如果你的FilterFooBar是PostgreSQL的PL/pgSQL函数,那函数内部的动态查询也要遵循同样逻辑——别拼接参数值,用USING子句传参数:
错误的函数写法(存在注入)
CREATE OR REPLACE FUNCTION FilterFooBar(_Chapter text) RETURNS SETOF foo AS $$ DECLARE sql text; BEGIN -- 错误:直接拼接参数到SQL字符串 sql := 'SELECT * FROM foo WHERE chapter = ''' || _Chapter || ''''; RETURN QUERY EXECUTE sql; END; $$ LANGUAGE plpgsql;
正确的函数写法(安全参数化)
CREATE OR REPLACE FUNCTION FilterFooBar(_Chapter text) RETURNS SETOF foo AS $$ DECLARE sql text; BEGIN sql := 'SELECT * FROM foo WHERE chapter = $1'; -- 用USING传递参数,避免拼接 RETURN QUERY EXECUTE sql USING _Chapter; END; $$ LANGUAGE plpgsql;
总结一下:Dapper的参数化方案本身是靠谱的,只要你别手动拼接用户输入的内容到SQL里,所有变量都通过参数占位符传递,不管是不是动态查询,都能有效防止SQL注入。
内容的提问来源于stack exchange,提问作者Faraaz
相关产品推荐
相关产品推荐

