感谢您在我引导我进入 Ruby 和 Rails 过程中提供的帮助。
在 Rails API 中 ActiveRecord::Base ,有一个关于条件的部分,旨在简单地介绍与 ActiveRecord 交互的语法。但他们使用的示例包含一个(对我而言)非常有趣的关于 Ruby/Rails 中输入清理的入门知识:
class User < ActiveRecord::Base
def self.authenticate_unsafely(user_name, password)
where("user_name = '#{user_name}' AND password = '#{password}'").first
end
def self.authenticate_safely(user_name, password)
where("user_name = ? AND password = ?", user_name, password).first
end
def self.authenticate_safely_simply(user_name, password)
where(:user_name => user_name, :password => password).first
end
end
按照此示例代码,他们解释说:
"The authenticate_safely and authenticate_safely_simply both will sanitize the user_name and password before inserting them in the query, which will ensure that an attacker can’t escape the query and fake the login (or worse)."
我完全明白这种输入清理对于防止注入(inject)攻击是一件好事。我不明白的是,鉴于没有调用特殊方法来预处理输入数据,这种隐式清理是在哪里以及如何发生的。各种示例方法似乎具有几乎相同的语义,但由于它们的解析方式,形式上的变化对安全性产生了巨大影响。我假设这些形式上的变化实际上类似于在包含转义字符的字符串周围使用单引号和双引号之间的区别。但是任何人都可以通过一般性的术语(或者更确切地说:在逻辑层面上,而不是在解释器内部)理解幕后实际发生的事情来帮助我变得更聪明、更快吗?
此外,这些差异在多大程度上取决于 Rails 特定的构造,而不是底层的 Ruby?
谢谢!
最佳答案
输入清理是 Active Record 提供的一项功能,称为 prepared statements or parameterized statements .
大多数数据库访问库本身都提供此功能,但是 Active Record 选择使用字符串修饰机制来模拟此功能。请参阅 active_record/relation/query_methods.rb
中的 build_where
并回溯到 sanitize_sql_for_conditions
(通过其 sanitize_sql
别名)在active_record/base.rb
中。 (非常感谢 mu is too short 的研究。)
您不再采用在应用程序中将查询字符串构建为字符串的旧式做法,而是使用带参数的静态模板查询。当您调用查询时,您提供参数,Active Record 将构造一个安全查询供 SQL 引擎执行。
您可以自己完成此任务 - 无数 PHP 程序员选择避开他们的类似 PDO database access layer 。然而,许多程序员无法正确理解这一点:there are roughly 1500 SQL Injection flaws过去三年发现的和我本地的CVE database显示自 MITRE 开始跟踪以来,超过 5000 个容易受到 SQL 注入(inject)攻击的程序实例。几乎所有这些问题都完全是由于人们选择手动编写自己的 SQL 代码并且没有正确清理他们的输入。 (我没有亲自检查每一个,但我不记得在 ORM 或数据库访问层中看到任何允许 SQL 注入(inject)攻击的缺陷。但为了保守起见,我选择了“几乎所有”。)
堆垛机同胞Jeff Atwood equates old-style SQL queries as the goto
of database programming :
Non-parameterized SQL is the GoTo statement of database programming. Don't do it, and make sure your coworkers don't either.
关于ruby - Rails 中输入的隐式清理 : Why do these examples from the API work the way they do?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9576665/