【问题标题】:SQL Injection and ActiveRecordSQL 注入和 ActiveRecord
【发布时间】:2018-11-02 21:55:38
【问题描述】:

这对 SQL 注入安全吗:

Guest.where(:event_id => params[:id])

我发送params[:id] 没有进行任何类型的清理。

一般来说,所有这些 activerecord 方法都安全吗? (如wherejoins等)

如果不是,那么确保安全的最佳做法是什么?另外,请问我应该注意任何警告/边缘情况吗?

谢谢

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:

    ActiveRecord 的所有查询构建方法,例如 wheregrouporder 等,都可以安全地防止 SQL 注入 只要您不向它们传递原始 SQL字符串。这很容易受到 SQL 注入:

     Model.where("event_id = #{params[:id]}")
    

    当您将字符串传递给这样的查询构建方法时,该字符串将直接插入到生成的 SQL 查询中。这有时很有用,但确实会增加注入漏洞的危险。另一方面,当您传递值的散列时,如下所示:

     Model.where(event_id: params[:id])
    

    ...然后 AR 会自动引用您的值,保护您免受 SQL 注入。

    【讨论】:

    • 引用不能防止 SQL 注入。使用参数化查询确实 - 就像在 DB(ODBC 或其他)驱动程序级别传递的 real 参数一样,而不是编写调用 DB 使用的任何语句执行的 SQL 脚本。 v4 SQL Server 适配器至少容易受到此错误的影响。对于参数化查询,不需要引用
    • @PanagiotisKanavos,感谢您的评论。我的回答的重点是,当您使用 ActiveRecord 的查询构建方法(如第二个示例)时,supposed 构建一个不可能进行 SQL 注入的查询。如果不是这样,您应该在 ActiveRecord 错误跟踪器上开一张票。
    • 查询构建由适配器执行,而不是 ActiveRecord 本身。这个特定的适配器实际上创建了一个 SQL 字符串,它在执行动态 SQL 字符串之前声明和分配参数 - 将注入点从查询本身移动到参数分配。当最终用户输入 ? 或笑脸等表情符号时,这会导致有趣的失败。一个简单的 ODBC 调用就可以避免这个问题,甚至不需要清理或引用。这让我想知道,其他适配器如何处理服务器调用?
    • @PanagiotisKanavos ActiveRecord 的哪个内部组件实际构建查询与 OP 的问题无关。最终用户应该能够使用 AR 从数据库中获取数据,而没有任何 SQL 注入的危险,只要他们使用此答案中推荐的样式即可。如果这不是真的,那么 AR 错误跟踪器是提出问题的正确位置,而不是在这里。
    • .order 上的一些有用阅读:stackoverflow.com/questions/17859880/…
    【解决方案2】:

    是的,您的代码在数据库上运行之前已被安全地清理。 Rails 通过自动清理输入来保护您免受 sql 注入。

    THE EXCEPTION是字符串插值:

    Guest.where("event_id = #{params[:id]}") # NEVER do this
    

    请改用以下 2 个选项之一:

    Guest.where(:event_id => params[:id]) # if you want pure ruby, use this
    # OR
    Guest.where("event_id = ?", params[:id]) # if you prefer raw SQL, use this
    

    查看Rails Guide on security 了解有关 sql 注入以及其他常见攻击的更多信息。

    【讨论】:

    • 在您的第二个选项中,rails 会清理 params[:id] 吗?
    • 对 SQL 注入的唯一真正防御是真正的参数化查询。清理只能捕获有限数量的情况,而参数化根本没有这个问题——参数在驱动程序(例如 ODBC)级别作为不同的数据片段传递,它们绝不是脚本的一部分。清理和引用只是解决方法
    • @PanagiotisKanavos 添加一个关于如何使用 ActiveRecord 实现参数化查询的链接会很棒!
    • 使用字符串插值时,sql注入高
    【解决方案3】:

    如果你真的需要使用原始sql,你可以使用quote来防止SQL注入

    这是一个从here复制的例子

    conn = ActiveRecord::Base.connection
    name = conn.quote("John O'Neil")
    title = conn.quote(nil)
    query = "INSERT INTO users (name,title) VALUES (#{name}, #{title})"
    conn.execute(query)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-06
      • 2019-12-06
      • 2012-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多