【问题标题】:Escaping SQL Strings in Java在 Java 中转义 SQL 字符串
【发布时间】:2012-05-18 07:58:39
【问题描述】:

背景:

我目前正在为企业 CMS 数据库(业务对象)开发 Java 前端。目前,我正在构建一个功能以允许用户构建自定义数据库查询。我已经实施了一些措施,以确保用户只能使用已批准用户访问的可用列和运算符的子集进行选择(例如,可以选择 SI_EMAIL_ADDRESS,而不能选择更强大的字段,如 SI_CUID)。到目前为止,事情进展顺利,但现在是时候保护此功能免受潜在的 SQL 注入攻击了。

问题:

我正在寻找一种方法来转义用户输入字符串。我已经看过 PerparedStatement,但是我不得不使用第三方 API 来访问数据库。这些 API 对我来说是不可变的,直接数据库访问是不可能的。各个方法采用表示要运行的查询的字符串,从而使 PreparedStatement 无效(据我所知,它必须针对直接数据库连接运行)。

我考虑过使用 String.replace(),但如果可能的话,我不想重新发明轮子。此外,我与开发 PerparedStatement 的安全专家相差甚远。

我还查看了 PerparedStatement 的 Java API 参考,希望能找到某种 toString() 方法。唉,我一直找不到类似的东西。

非常感谢任何帮助。提前谢谢你。

参考资料:

Java - escape string to prevent SQL injection

Java equivalent for PHP's mysql_real_escape_string()

【问题讨论】:

    标签: java sql business-objects


    【解决方案1】:

    当然,使用 PreparedStatement 会更容易、更安全。

    ANSI SQL 要求字符串文字以单引号开头和结尾,单引号的唯一转义机制是使用两个单引号:

    'Joe''s Caffee'
    

    所以理论上你只需要用两个单引号替换一个单引号即可。但是,也存在一些问题。首先,一些数据库(例如 MySQL)也(或仅)支持反斜杠作为转义机制。在这种情况下,您也需要将反斜杠加倍。

    对于 MySQL,我建议使用MySQLUtils。如果您不使用 MySQL,那么您需要检查要使用的确切转义机制是什么。

    【讨论】:

      【解决方案2】:

      您仍然可以使用准备好的语句。见这篇文章:get query from java sql preparedstatement。此外,根据该帖子,您或许可以使用Log4JDBC 来处理此问题。

      这些选项中的任何一个都应该让您不必担心转义字符串以防止 SQL 注入,因为准备好的语句会为您完成。

      【讨论】:

      • 你的第一个链接非常有趣。我担心隐式定义的 toString() 方法的潜在未定义行为。企业架构师已经做出了令人印象深刻的努力来确保数据库本身被很好地隐藏(他们应该这样做)。我什至不知道它正在运行什么 DBMS,或者将来是否会更改。
      • 实际上,仔细想想,PreparedStatement 甚至没有可公开访问的构造函数。因为我没有 JDBC 连接对象,所以我不确定我什至可以如何获得 PreparedStatment 对象。嗯。
      • 是的,我知道这将是一个难题。我没有使用过 Log4JDBC,但它看起来可能能够根据准备好的语句为您生成 SQL。
      • 如果你不能使用准备好的语句,另一个答案是正确的——你应该能够使用双撇号来转义撇号。另一种选择是在插入文本之前对文本进行 URL 编码。您可以使用java.net.URLEncoder 进行编码并使用java.net.URLDecoder 稍后再次解码。当然,如果这样做,您必须记住每次提取数据时都要解码。
      【解决方案3】:

      尽管在 Java 中没有标准的方法来处理 PHP 的 mysql_real_escape_string() 我所做的是链接 replaceAll 方法来处理避免任何异常所需的每个方面。这是我的示例代码:

      public void saveExtractedText(String group,String content) { try { content = content.replaceAll("\", "\\") .replaceAll("\n","\n") .replaceAll("\r", "\r") .replaceAll("\t", "\t") .replaceAll("\00", "\0") .replaceAll("'", "\'") .replaceAll("\"", "\\"");

          state.execute("insert into extractiontext(extractedtext,extractedgroup) values('"+content+"','"+group+"')");
      } catch (Exception e) {
          e.printStackTrace();
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-24
        • 2012-08-30
        • 1970-01-01
        • 1970-01-01
        • 2016-03-07
        相关资源
        最近更新 更多