【问题标题】:Is this a secure method of escaping a SQL query parameter?这是转义 SQL 查询参数的安全方法吗?
【发布时间】:2012-05-25 13:22:46
【问题描述】:

在我的工作中,过去的传统是通过不安全地将参数连接到查询字符串中来形成 SQL 查询。当然,这会导致 SQL 注入漏洞。这并不是一个大问题,因为发生这种情况的所有 Java 软件都运行在所有用户都被信任的封闭网络上。此外,查询是从具有数据库访问权限的客户端应用程序执行的,因此用户在技术上无论如何都可以执行恶意查询。

不过,计划在新版本的数据库层中支持准备好的语句。同时,我在现有数据库层(仅支持从 SQL 字符串执行查询,没有准备好的语句或参数转义选项)之上编写了一个小库,允许通过转义字符串参数来编写安全的参数化查询.

作为这个库的一部分,我编写了以下方法来转义字符串文字。我转义了与 PHP 的 addlashes 函数相同的字符,但我尝试通过检测补充(32 位)字符来避免其多字节字符漏洞:

private String escapeString(String str)
{
    List<Character> toEscape = Arrays.asList('\'', '"', '\\', '\0');

    StringBuilder result = new StringBuilder();
    for(int i = 0; i < str.length(); ++i)
    {
        char c = str.charAt(i);

        if(i < str.length() - 1 && c >= '\uD800' && c <= '\uDBFF')
        {
            char next = str.charAt(i + 1);

            if(next >= '\uDC00' && next <= '\uDFFF')
            {
                // Two-char supplementary character. Escape neither.
                result.append(c);
                result.append(next);
                ++i;
                continue;
            }
        }

        if(toEscape.contains(c))
        {
            // Special character. Add escaping \.
            result.append('\\');
        }

        // Copy character itself.
        result.append(c);
    }

    return result.toString();
}

我的问题是这种转义查询的方法是否足够安全(而且我没有监督任何事情或犯了实施错误)。可以假设输入字符串是有效的 UTF-16。这将与 MySQL 和 Oracle 一起使用的 DBMS。

【问题讨论】:

  • 数据库连接和数据库表中使用的字符集/编码也很重要,因为在方案之间“翻译”字符时可能会引入问题。如果您可以确保它们始终与 Java 的本机表示相同,则可能会减少攻击面。
  • 不要打扰:The Daily WTF 充满了字符串转义不佳的示例。而是尽快走参数化查询路线。此外,更改代码并不难。另见Give me parameterized SQL, or give me death
  • 您需要担心的不仅仅是sql注入。如果不使用绑定变量(无论如何在 Oracle 上),您的 sql 缓存将被浪费,因为您不断地硬解析每个“新”语句。
  • 我非常清楚参数化 SQL 是非常可取的。但是,这是一种建立在现有数据库层之上的临时措施,可以在更新所述层(不支持参数化查询)之前使用。

标签: java mysql sql oracle security


【解决方案1】:

如果没有 ORM、准备好的语句或存储过程,我会谨慎对待任何字符串 SQL 清理例程。

【讨论】:

  • 存储过程本身就有风险。如果它们写得不好,你可以达到与 java sql 注入相同的效果。
  • @tom 想详细说明您所说的“写得不好”是什么意思?除非该过程通过连接用户提供的值来动态创建 SQL 语句,否则我倾向于不同意。
  • @Frank 你指出的正是我的意思。我见过通过连接元素然后使用execute immediate 来构建选择的存储过程。正确的方法显然是使用绑定变量(或者根本不使用execute immediate),但初级开发人员并不总是这样做。因此需要进行代码审查!
【解决方案2】:

没有。

假设您有一个整数字段,他们将 PIN 输入其中:

"SELECT columns FROM table WHERE PIN = " + sanitizedstring

然后输入: 1234 或 1 = 1

现在你的“pin”总是被接受,没有使用任何有趣的字符。

这也适用于除 int 之外的字段(因为是的,您可以在将其交给 SQL 之前验证 int 输入实际上是 int。)

【讨论】:

  • 我发布的方法不打算由图书馆用户直接使用。它在内部用于处理字符串类型的转义(我以不同的方式处理整数)。该库的可见 API 更类似于 PHP 的 PDO。
猜你喜欢
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 2012-07-13
  • 1970-01-01
  • 2021-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多