six*_*ude 6 java postgresql sql-injection
在构建 sql 查询和更新以提交到我的数据库之前,我需要清理一些用户输入的数据。
我知道最好使用准备好的语句,但这不是一个选项。不幸的是,我坚持要转义所有用户提供的 Input。
看起来 Postgres JDBC 库附带了一个工具来进行字符串转义。见org.postgresql.core.Utils.escapeLiteral(..)(见下文)。我希望因为 Postgres 附带了它,所以使用起来是安全的。经过几个小时的谷歌搜索和查看 SQL 备忘单后,我无法找到一个可以打破这个的例子。
以下看起来足够安全吗?
public class FruitDb {
private Connection connection;
public void findFruit ( String /* user enterable field */ fruitColor ) {
String query = "SELECT * FROM fruit WHERE fruit_color = " + quote( fruitColor );
Statement statement = connection.createStatement();
statement.executeQuery( sql );
}
private String quote( String toQuote ) {
return "'" + Utils.escapeLiteral( null, s, true ).toString() + "'";
}
}
Run Code Online (Sandbox Code Playgroud)
对于那些感兴趣的人来说,这里是Utils.escapeLiteral. 对我来说看起来相当安全......
package org.postgresql.core;
class Utils {
...
/**
* Escape the given literal <tt>value</tt> and append it to the string builder
* <tt>sbuf</tt>. If <tt>sbuf</tt> is <tt>null</tt>, a new StringBuilder will be
* returned. The argument <tt>standardConformingStrings</tt> defines whether the
* backend expects standard-conforming string literals or allows backslash
* escape sequences.
*
* @param sbuf the string builder to append to; or <tt>null</tt>
* @param value the string value
* @param standardConformingStrings if standard conforming strings should be used
* @return the sbuf argument; or a new string builder for sbuf == null
* @throws SQLException if the string contains a <tt>\0</tt> character
*/
public static StringBuilder escapeLiteral(StringBuilder sbuf, String value, boolean standardConformingStrings)
throws SQLException
{
if (sbuf == null)
{
sbuf = new StringBuilder(value.length() * 11 / 10); // Add 10% for escaping.
}
doAppendEscapedLiteral(sbuf, value, standardConformingStrings);
return sbuf;
}
private static void doAppendEscapedLiteral(Appendable sbuf, String value, boolean standardConformingStrings)
throws SQLException
{
try
{
if (standardConformingStrings)
{
// With standard_conforming_strings on, escape only single-quotes.
for (int i = 0; i < value.length(); ++i)
{
char ch = value.charAt(i);
if (ch == '\0')
throw new PSQLException(GT.tr("Zero bytes may not occur in string parameters."), PSQLState.INVALID_PARAMETER_VALUE);
if (ch == '\'')
sbuf.append('\'');
sbuf.append(ch);
}
}
else
{
// REMOVED. I am using standard encoding.
}
}
catch (IOException e)
{
throw new PSQLException(GT.tr("No IOException expected from StringBuffer or StringBuilder"), PSQLState.UNEXPECTED_ERROR, e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
类似问题:
是的,使用 escapeLiteral() 和 escapeIdentifier() 是安全的。
事实上,escapeLiteral() 和 escapeIdentifier() 是 libpq 中定义的 PQescapeLiteral() 和 PQescapeIdentifier() 的补充。
主要区别是 JDBC 的 escapeLiteral() 不考虑数据库连接来验证字符编码。然而,Java的内部编码是Unicode并转换为数据库字符编码。因此,这并不重要。
我注意到的另一个区别是字符串如何转义为 SQL Literal。PQescapeLiteral 为字符串添加引号,但 escapeLiteral() 没有。例如,abc'xyz使用 PQescapeLiteral() 变成 'abc''xyz',但它变成了abc''xyz(注意结果周围没有引号)
escapeIdentifier() 就像 PQescapeIdentifier() 一样添加引号。例如abc"xyz成为"abc""xyz"
CERT 前 10 名安全编码实践 #7(清理输出)建议清理所有变量,无论之前的检查/验证如何。人们可以通过使用预备查询来避免使用 escapeLiteral(),但不能使用 escapeIdentifier(),因为预备查询无法分隔参数化标识符。IE
SELECT user_specified_col FROM tbl;
Run Code Online (Sandbox Code Playgroud)
或者
SELECT * FROM tbl ORDER BY user_specified_col;
Run Code Online (Sandbox Code Playgroud)
开发人员必须严格验证“user_specified_col”,但他们必须清理参数,以防验证不当。即输出净化必须独立完成。
| 归档时间: |
|
| 查看次数: |
1984 次 |
| 最近记录: |