如何在不使用预准备语句的情况下清理 SQL
2022-09-03 01:24:23
对于某些sql语句,我不能使用预准备语句,例如:
SELECT MAX(AGE) FROM ?
例如,当我想改变桌子时。有没有一个实用程序可以在Java中清理sql?红宝石中有一个。
对于某些sql语句,我不能使用预准备语句,例如:
SELECT MAX(AGE) FROM ?
例如,当我想改变桌子时。有没有一个实用程序可以在Java中清理sql?红宝石中有一个。
正确,预准备语句查询参数只能在使用单个文本值的情况下使用。不能将参数用于表名、列名、值列表或任何其他 SQL 语法。
因此,您必须将应用程序变量插入 SQL 字符串中,并相应地引用该字符串。请使用引号来分隔表名标识符,并通过将其加倍来转义引号字符串:
java.sql.DatabaseMetaData md = conn.getMetaData();
String q = md.getIdentifierQuoteString();
String sql = "SELECT MAX(AGE) FROM %s%s%s";
sql = String.format(sql, q, tablename.replaceAll(q, q+q), q);
例如,如果您的表名是字面意思是 ,并且您的 RDBMS 标识符引号字符是 ,则应包含如下字符串:table"name
"
sql
SELECT MAX(AGE) FROM "table""name"
我也同意@ChssPly76的评论-最好是用户输入实际上不是文字表名,而是代码映射到表名的能指,然后将其插入到SQL查询中。这可以让您更加确信不会发生 SQL 注入。
HashMap h = new HashMap<String,String>();
/* user-friendly table name maps to actual, ugly table name */
h.put("accounts", "tbl_accounts123");
userTablename = ... /* user input */
if (h.containsKey(userTablename)) {
tablename = h.get(userTablename);
} else {
throw ... /* Exception that user input is invalid */
}
String sql = "SELECT MAX(AGE) FROM %s";
/* we know the table names are safe because we wrote them */
sql = String.format(sql, tablename);
不可能。你能做的最好的事情就是使用 String#format()。
String sql = "SELECT MAX(AGE) FROM %s";
sql = String.format(sql, tablename);
请注意,这并不能避免 SQL 注入风险。如果 是用户/客户端控制的值,则需要使用 String#replaceAll()
对其进行清理。tablename
tablename = tablename.replaceAll("[^\\w]", "");
希望这有帮助。
[编辑]我应该补充一点:不要将其用于可用于的列值。只需继续以通常的方式将其用于任何列值即可。PreparedStatement
[编辑2]最好不要让用户/客户端能够以它想要的方式输入表名,但最好在 UI 中显示一个包含所有有效表名(可以通过 )的下拉列表,以便用户/客户端可以选择它。如果选择有效,请不要忘记在服务器端签入,因为可能会欺骗请求参数。DatabaseMetaData#getCatalogs()