【问题标题】:Bad Code: Why is this dangerous? [duplicate]糟糕的代码:为什么这很危险? [复制]
【发布时间】:2011-03-16 23:25:02
【问题描述】:

可能重复:
Can I protect against SQL Injection by escaping single-quote and surrounding user input with single-quotes?

     String badInput = rawInput.replace("'","''");
     ResultSet rs = statement.executeQuery("SELECT * FROM records WHERE col1 = '"+badInput+"'";

有没有办法对这段代码进行类似“Bobby Tables”的攻击?

【问题讨论】:

  • 说真的,使用PreparedStatement 很难吗? 为什么人们坚持坚持使用串联 SQL?
  • 我完全同意,@Randolpho - 我在这里采取了更多的魔鬼拥护者的立场,因此也为改变我可能遇到的遗留代码获得了更好的论据。 :)
  • 啊,我明白了。我只是不明白为什么过去 10 年(或更长时间)编写软件的人会使用除了正确参数化的 SQL 之外的任何东西。我责备糟糕的书籍和博客文章。
  • 当您检查 O'Malley 先生的记录时会发生什么?换句话说,撇号可以是合法字符。
  • @Epaga:查看 Avid 的论文(在他关于重复问题的帖子中提到)。它提到的一个邪恶黑客是使用 unicode 单引号,它实际上不是单引号,但 sql 引擎会很乐意翻译它以提供帮助。

标签: java sql security sql-injection


【解决方案1】:

根据所有必须解释命令的过程中的不同步骤,可能会传递%27(例如)并将其作为单引号,通过您的替换传递而不被注意。

但是即使可以涵盖所有这些情况,并且对于这一个问题实际上是安全的,它的不足之处在于它不能统一实施。其他人可能会出现并想要添加AND int1 = var1,并注意到您已经考虑过 SQL 注入,因此他们只是按照您的确切方式修改代码

String badInput = rawInput.replace("'","''");
String badInteger = rawInteger.replace("'","''");
ResultSet rs = statement.executeQuery("SELECT * FROM records WHERE" +
 "int1 = " + badInteger + " OR col1 = '"+badInput+"'");

...只有整数,它不再是你想要保护自己的引号!在这里,很明显任何事情都可能出错。因此,虽然这是一个需要有人实施得不好的问题,但我认为这是设计中最大的问题——它只涵盖了一小部分情况。

最好只说“以下是一个变量。无论它包含什么,都将其视为一个值,并且不要尝试将它的一部分用作代码并执行该代码。”

【讨论】:

    【解决方案2】:

    你可以试试:

    badInput = "\\'; drop records; --";
    

    如果您的转义字符恰好设置为'\'

    【讨论】:

      【解决方案3】:

      如果没有设置NO_BACKSLASH_ESCAPES 选项,我相信在 MySQL 中是可以做到的。

      \'); DROP 
      

      或类似的东西。您的代码将使' 加倍。第一个 ' 将被反斜杠转义,第二个将关闭允许 SQL 注入的字符串。

      为了安全起见,我通常更喜欢坚持准备好的陈述。

      【讨论】:

      • MySQL 通常不允许您堆叠查询。您将 m$-sql 开发与 msyql 开发混淆了。苹果和橙子。
      • 很好,但还有其他方法可以利用它。
      【解决方案4】:

      我不是安全专家,但char() 不会有效绕过您的安全措施吗?

      例如:从记录表中获取所有内容

      SELECT * FROM records WHERE col1 = char(39,97,39)
      

      例如 2:将信息写入不带单引号的文件

      SELECT * FROM records WHERE col1 = concat(char(39),char(97),char(100),char(109),char(105),char(110),char( 39)) into outfile concat(char(39),char(97),char(100),char(109),char(105),char(110),char( 39))
      

      来源:SQL Injection Cheat Sheet

      【讨论】:

      • 注意输入周围的单引号。这些命令会变成简单的字符串。还是我错过了什么?
      • 您可以使用char()转换引号,从而跳过替换功能!
      • 是的,如果引号受到限制,此方法确实有效,您还可以使用十六进制编码0x4142,即AB。但是,如果变量用引号括起来,那么这不是问题。
      【解决方案5】:

      因为只有一个黑客才能发明一种方法来绕过我们今天无法想到的替代品。 (其中一层访问数据库的小bug???)

      【讨论】:

        【解决方案6】:

        我最近向我的兄弟介绍了准备语句。在他当前的项目中实施后,他发现

        • 他可以摆脱所有乱七八糟的逃跑
        • 他可以摆脱所有混乱的字符串连接
        • 他的代码运行得更快。

        为什么会有人使用prepare?

        【讨论】:

        • 虽然它没有回答问题:阿门! :)
        【解决方案7】:

        这很容易引发注入攻击。

        【讨论】:

          【解决方案8】:

          也许吧。取决于 replace 方法的实际作用,尤其是当它遇到 unicode 代理对或组合标记时 - 以及类似地,您的数据库访问技术如何处理此类对。如果 replace 在 char 级别上工作,那么如果攻击者向您提供了一个有效的高代理项,后跟一个单引号字符,您可能会用一对单引号替换该单引号 - 实际上,附加一个单引号在之后可能会通过编码并被解释为无效代理对的内容之后的引号,留下一个裸的单引号字符。

          也许吧。

          您是否足够了解该替换方法的 unicode 特征以及您的代码和数据库连接另一端的 SQL 执行引擎之间的每个中间字符串处理库?

          你觉得幸运吗?

          使用参数化查询。

          【讨论】:

            猜你喜欢
            • 2014-02-28
            • 1970-01-01
            • 1970-01-01
            • 2020-08-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-10
            相关资源
            最近更新 更多