【问题标题】:SQL Injection, simplest solutionSQL注入,最简单的解决方案
【发布时间】:2010-11-28 16:10:26
【问题描述】:

如果我只是用双引号替换所有传入的单引号,我不确定有人会如何破坏我的 SQL。有人可以为我提供 Oracle 和 SQL Server 示例吗?谢谢。

string sql1 = "select * from users where user_id = '" + "O'Reily".Replace("'", "''").Replace("\", "") + "'";

==> "select * from users where user_id = 'O''Reily'

string sql2 = "select * from users where user_id = '" + "O'''Reily".Replace("'", "''").Replace("\", "") + "'";

==> "select * from users where user_id = 'O''''''Reily"

更新:斜杠“\”是应用程序中的受限字符,在查询中使用之前将被删除。双破折号可以很容易地添加到这个受限字符列表中。

【问题讨论】:

  • 单引号的问题不如“--”和“;”。尽可能限制用户文本输入。
  • 强制性小鲍比桌:xkcd.com/327
  • Bobby 可以使用这个解决方案。单引号将被转义为双引号,并且永远不会执行 drop。
  • ‘--’ 和 ‘;’ 在字符串文字中是没有意义的,当然应该允许。像这样限制任意的事情是迷信:适当地逃避事情,你不需要担心它们;未能正确逃脱,他们不会救你。

标签: sql sql-server oracle tsql plsql


【解决方案1】:

您提出的解决方案容易受到包含\' 字符串的影响,这将结束您引用的部分并允许注入其他命令。

您希望尽可能使用 SQL 准备语句,这应该无处不在。基本上,你用特定的占位符为你的数据编写你的 sql,然后通过一个单独的、非解释的通道将这些数据传递给 sql server。

几个链接:

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html

http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html

http://mattbango.com/notebook/web-development/prepared-statements-in-php-and-mysqli/

【讨论】:

    【解决方案2】:

    参数化你的变量。严重地。所有现代环境都有这样做的设施,您不必担心像 \' 这样的转义序列,它会在您的方案(在 Oracle 中)变成 \'' ,它成为转义引号和常规(终止)引号。

    还有很多其他技巧可以解决这个问题,我没有一一列举,因为它们没有帮助。

    再次:参数化你的变量。严重地。如果您不学习如何使用参数化,您将成为另一个被黑的统计数据。

    编辑:阅读保罗回答中的链接,这是另一个:http://unixwiz.net/techtips/sql-injection.html

    无论你认为你的字符串卫生有多聪明,你都做错了。 特别是如果您必须处理多个后端。

    用字符串编写查询是我会直接解雇员工的少数几件事之一……这样的程序员给公司带来的风险比他们带来的任何其他事情都要大(尤其是在我们做出很明显,我们不会在第一天就接受这样的代码,并提供一个实体框架,让这些事情变得不必要)。

    【讨论】:

    • +1 绝对同意这是您在创建解决方案时感到聪明(错误)的情况之一。
    • 我们有一家安全渗透公司试图入侵我们的网站。因为我们使用参数,所以它们无法通过字符串操作获得任何结果……但我在我们的日志中看到了很多我后来尝试过的怪异构造。 令人惊讶主题有多少变化。
    • 谢谢,我知道这是正确的方法。我一直在某种程度上认为,参数化数据无论如何都是在做某种正则表达式/字符串操作。
    • 参数化不进行字符串操作,这是好处之一。相反,参数与命令字符串一起发送,就像您的语言中函数调用的参数一样。在服务器端解析参数时,命令字符串已经应用了所有转义并且参数具有真实类型。这意味着“O'Dell”作为参数实际上是“O'Dell”而不是“O''Dell”被转义。这也意味着500是整数参数中的整数,而不是“500”。整数参数将拒绝“ABCD”,就像您的语言中的函数一样。
    【解决方案3】:

    为了防止 SQL 注入,您真正应该做的是使用绑定的位置或命名参数,而不是将 SQL 构造为内联用户输入的字符串。这如何完成取决于您的应用程序如何访问数据库。例如,下面是使用 JDBC 在 Java 中的样子:

    不好:

    String updateString = "UPDATE COFFEES SET SALES = 75 " + 
                          "WHERE COF_NAME LIKE 'Colombian'";
    stmt.executeUpdate(updateString);
    

    好:

    PreparedStatement updateSales = con.prepareStatement(
            "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
    updateSales.setInt(1, 75); 
    updateSales.setString(2, "Colombian"); 
    updateSales.executeUpdate():
    

    我从这里借用了这个例子: http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html

    【讨论】:

    • 这真的会阻止我输入 updateSales.setString(2, "; DELETE YOUR_DATA;--"
    • rexem:是的。例如,Oracle 将通过一个解析阶段来检查 SQL 的语法。此时,它不会查看绑定变量的内容。 SQL 解析不成功就无法执行。在“好”示例中,参数被定义为绑定变量,永远不会被解析为 SQL 语句的一部分,也永远不会被执行。作为“副作用”,语句可以重复用于不同的绑定变量值,从而减少解析和数据库负载。
    • +1 如果支持使用绑定变量。我认为在 php 中没有支持。但是 java、c#、c/c++、……大多数语言都可以。因为 sql 是与值分开解析(或解释)的,所以这是防止 sql 注入的唯一安全措施。
    【解决方案4】:

    有一些涉及攻击者利用应用程序截断输入的技巧:

    http://www.rampant-books.com/t_super_sql_154_ideas_prevent_injection.htm

    【讨论】:

    • 感谢这是一个很好的链接,但它依赖于将字符串数据修剪为固定宽度,然后剥离已实施的修复。此外,asp 代码中输入的长度与输出到数据库的长度不匹配。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 2013-11-12
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多