`
andyhu1007
  • 浏览: 199312 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Rails每周一题(七): Security Guide(中)

阅读更多

上篇 中介绍了对session的攻击方法以及应对策略,在此篇继续介绍其它一些对网站的攻击方法以及应对策略。在阅读本文的过程中,你会发现,其实避免很多安全问题并不困难。只是很多时候,我们并没有把安全问题这个概念放在心里。

 

 

跨站请求伪造CSRF

 

跨站请求伪造在网页上注入恶意代码或者一些恶意链接,来访问用户已被认证的网站。如果session未过期,攻击者就可以进行一些恶意的操作。

 

 

 

csrf

 

 

 

我们知道在用户访问网站时,cookie里面都会带有session id。而有争议的一点是,当这个请求来自另外一个域时,session id也会被附在cookie上。 让我们来看看一个攻击的例子:

 

1. Bob浏览一张被黑客恶意改造过的网页,此网页有一个image element,但是此element并不指向一张图片,而是链接至Bob的项目管理站点:

<img src="http://www.webapp.com/project/1/destroy">

 

2. 假设此时Bob在www.webapp.com上的session仍然有效。

3. 当Bob浏览此页面时,它会试图从www.webapp.com导入图片。同时,会附带发送带有正确session id的cookie。

4. www.webapp.com确认了用户信息,并执行了相应操作。

5. 图片未显示,同时Bob也未注意到任何攻击的发生。

 

应对策略:

 

1. 适当使用GET和POST。当操作会对数据状态进行更改,或者用户需要对操作负责时,使用POST请求。当然,在RESTful下,还有PUT和DELETE请求。通过正确应用HTTP verbs,可以避免上述问题的出现。

 

    在Rails里面,可以通过在controller里面增加类似代码:

 

 

verify :method => :post, :only => [:transfer], :redirect_to => {:action => :list} 

 

   但是黑客还是可以通过更加复杂的攻击方法来绕过这个限制,比如:

 

 

<a href="http://www.harmless.com/" onclick=" var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = 'http://www.example.com/account/destroy'; f.submit(); return false;">To the harmless survey</a> 

 

2. 上面问题的解决方法是通过在所有非GET请求中包含一个security token -- 在服务器端会检查此security token。在Rails2.0以及后来的版本中,只要在application controller里面加入如下一行即可:

 

 

protect_from_forgery :secret => "123456789012345678901234567890..." 
 

加入这行后,Rails会在所有由Rails生成的form和Ajax请求中 包含security token,这个security token通过当前session和服务端的secret计算而得。如果security token验证没有通过,会抛出ActionController::InvalidAuthenticityToken异常。(注意,在使用 CookieStore session存储机制时,不需要secret。)

 

 

重定向

 

重定向至陷阱网站。

 

假如我们的controller中有这样一个action:

 

def legacy 
   redirect_to(params.update(:action=>'main')) 
end 

 

这个action是一个遗留action,它现在做的工作只是把对它的访问转向到main action。

 

此时,如果攻击者用这样一个url对此action发起请求。

 

http://www.example.com/site/legacy?param1=xy&param2=23&host=www.attacker.com 

 

那么legacy action会把请求重定向至www.attacker.com。请注意url最后的host参数。

 

应对策略:

 

通过一个白名单(白名单,而不是黑名单)对legacy action的参数进行过滤。

 

 

文件相关攻击

 

文件上传

 

—  不要让上传文件覆盖重要文件,并且注意异步处理媒体文件。

 

假设我们把上传文件存于目录“/var/www/uploads",然后用户上传了一个名字叫做“../../../etc/passwd”的文件。

 

那么passwd文件就有被覆盖的危险。(当然,Ruby解释器需要有相应的权限进行此操作才可以。从这里看出让web server,数据库等其他一些程序在一个低权限的用户上跑是多么重要。)

 

应对策略:

 

对文件名进行验证。参考attachment_fu plugin 的例子:

 

def sanitize_filename(filename)  
   returning filename.strip do |name| 
     # NOTE: File.basename doesn't work right with Windows paths on Unix  
     # get only the filename, not the whole path  
     name.gsub! /^.*(\\|\/)/, ''  
     # Finally, replace all non alphanumeric, underscore  
     # or periods with underscore  
     name.gsub! /[^\w\.\-]/, '_'  
   end 
end 

 

 

拒绝服务

 

同步处理上传文件的一个很大的缺点在于它使网站易于被拒绝服务 所攻击。假如攻击者同时上传很多文件,服务器可能会被拖垮。

 

应对策略:

 

异步处理上传文件。在服务器端保存文件后,在后台安排一个进程对文件进行处理。

 

 

上传可执行文件

 

不要把上传文件置于Rails的public目录下 -- 如果这个目录是Apache的home目录。

 

Apache Web服务器有个特点,就是它会执行DocumentRoot目录下的有特定扩展名的文件,比如PHP和CGI文件。假设攻击者上传了一个file.cgi文件,那么当他下载这个文件时,这个文件就会被执行。

 

应对策略:

 

如果Rails的public目录是Apache的home目录,就不要在此目录下存储上传文件。至少把文件存于下一级目录。

 

 

文件下载

 

不要让用户下载任意文件。

 

send_file('/var/www/uploads/' + params[:filename])

 
上面这段代码可以让用户下载任意文件。假如用户输入的文件名是 “../../../etc/passwd”,那么passwd文件就会被下载。

 

应对策略:

 

验证被下载文件在合法的目录下

 

basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files')) 
filename = File.expand_path(File.join(basename, @file.public_filename)) 
raise if basename =! File.expand_path(File.join(File.dirname(filename), '../../../')) 
send_file filename, :disposition => 'inline' 

 

 

管理员站点的安全问题

 

Admin Site具有一些超权限,所以经常成为黑客的攻击目标。对于Admin Site,要采取一些额外的安全策略。

 

1. 为了防止Admin Site受到XSS的攻击,建议使用Safe ERB 插件阻止用户恶意代码的注入。

 

2. 如果做最坏的打算 -- 管理员的用户名和密码真的被盗了。那么我们可以采取什么措施防护?比如让一些特权操作需要一些特殊的密码。

 

3. 管理站点真的需要在任何地方都可以被访问么?限制管理站点只能从来自一些特殊IP的访问。

 

4. 把管理站点置于子域比如admin.webapp.com或者一个独立域,可以防止XSS的攻击。(相同来源策略)

 

 

Mass Assignment

 

— 如果不做一些预防措施,Modle.new(params[:model])允许攻击者设置任何数据库字段的值。

假设在注册时用户传上来的参数是这样的:

 

params[:user] #=> {:name => “ow3ned”, :admin => true} 
 

那么当程序处理时,会把这个用户置为一个admin用户。

 

应对策略:

 

保护一些字段,防止它被Mass Assignment:

 

 

attr_protected :admin 

 

但这是一个黑名单,如果你新加了一个受保护字段,必须不能忘记在列表上添加上。所以更好的方法是:

 

 

attr_accessible :name 
 

字段受保护之后,你只能给它单独赋值:

 

params[:user] #=> {:name => "ow3ned", :admin => true} 
@user = User.new(params[:user]) 
@user.admin #=> false # not mass-assigned 
@user.admin = true 
@user.admin #=> true 

 

更绝对的一种做法是,在初始的时候加上这么一句:

 

ActiveRecord::Base.send(:attr_accessible, nil) 

 

它会把所有model的白名单置空,你必须对每个model显示地指定attr_accessible名单。

 

 

帐户管理

 

restful_authentication插件的安全漏洞

 

假如我们使用了restful_authentication的激活策略:每个新注册用户都会收到一个激活链接,当访问了激活链接后,数据库里的激活码字段会被置为null。

 

激活链接例子:

 

http://localhost:3006/user/activate?id=xrfqlki3453325xdgl

 

程序处理:

 

User.find_by_activation_code(params[:id]) 

 

假如用户用这样URL访问:

 

http://localhost:3006/user/activate 
http://localhost:3006/user/activate?id= 
 

那么生成的sql就变成这样了:

 

 

SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1 

 

它会找到第一个已经被激活的用户。

 

账户的暴力破解

 

有些黑客采取暴力破解的方式来获取账号,而有时候我们的网站的一些小问题却帮了他们的忙。

 

我们可能在提示信息里面提供任何对黑客有用的信息,比如有些网站在用户输入正确用户名和错误密码时会提示:Your password is invalid,或者在用户名未找到时提示:the user name you entered has not been found。

 

应对策略:

 

正确的做法是只要用户提供的用户名和密码无法登陆,则提供提示信息:user name or password not correct。

 

同时,在发现来自同一个IP的多次失败登录行为之后,需让用户输入验证码进行登录。

 

账户劫持

 

1. 修改密码时要阻止CSRF的攻击。

 

2. 修改email地址或者进行其它一些操作时,需让用户提供密码。

 

日志

 

日志很多时候成为了一个很大的安全隐患,虽然在数据库里我们对密码进行了加密,但在日志里是明文。

 

应对策略:

 

在controller里面加上一行以阻止密码被日志所记录。

 

filter_parameter_logging :password 

 

正则表达式

 

注意^  $  和  \A  \z的区别。

 

比如我们用这样一个验证:

 

class File < ActiveRecord::Base 
   validates_format_of :name, :with => /^[\w\.\-\+]+$/ 
end 
 

那么当用户输入如下文件名时,能很容易地绕过这个验证:

 

file.txt%0A<script>alert('hello')</script> 

 

它会被URL解码为“file.txt\n<script>alert(‘hello’)</script>”。

 

这里的问题在于Ruby里面的正则表达式中^和$匹配的是行首和行尾

 

应对策略

 

正确的做法应该是:

 

 

/\A[\w\.\-\+]+\z/ 

 

权限放大

 

这个问题貌似是我们经常会忽略的问题。

 

比如有这样的句子:

 

@project = Project.find(params[:id]) 

 

那么当用户改变了一个参数之后,他就可以访问其它用户的信息。

 

应对策略:

 

@project = @current_user.projects.find(params[:id]) 
 

 

 

中篇完结。在本篇中,介绍了一些在创建程序的过程中,我们要注意的一些小问题。这些东西其实都不复杂,但如果我们忽视了,则会引起很大的安全问题。

 

 

 

待续,下篇 关于多种注入的威胁,比如sql注入,css注入等。

 

分享到:
评论

相关推荐

    Rails的精简版本Rails::API.zip

    Rails::API 是 Rails 的精简版本,针对不需要使用完整 Rails 功能的开发者。 Rails::API 移除了 ActionView 和其他一些渲染功能,不关心Web前端的开发者可更容易、快速地开发应用程序,因此运行速度比正常的 Rails ...

    Ruby On Rails 面试系列七,一个面试练习题

    这个面试练习题可能是为了测试应聘者对于Rails应用的构建、自动化任务管理、测试驱动开发(TDD)以及文件组织结构的理解。让我们逐一探讨这些知识点。 首先,`Rakefile`是Ruby中的构建工具,类似于其他语言的...

    Rails上的API:使用Rails构建REST APIAPIs on Rails: Building REST APIs with Rails

    在本篇内容中,我们将深入探讨如何利用Ruby on Rails(简称Rails)这一强大的Web应用程序框架来构建可伸缩且易于维护的RESTful API。Rails以其简洁优雅的语法、高效的开发速度以及良好的社区支持而闻名,这使得它...

    Ruby on Rails入门例子

    Ruby on Rails,简称Rails,是一种基于Ruby语言的开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本篇将通过一个入门实例,深入探讨Rails的基本概念和核心...

    rails指南 中文版

    Rails指南中文版是针对Ruby on Rails框架的一份详尽教程,旨在帮助开发者深入理解并熟练掌握这个强大的Web应用开发工具。Ruby on Rails(简称Rails)是一个基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-...

    rails_email_preview:在Rails中预览和编辑应用程序邮件模板

    安装加 到Gemfile: gem 'rails_email_preview' , '~&gt; 2.2.2' 添加一个初始化程序和路由: $ rails g rails_email_preview:install 在app / mailer_previews /中生成预览类和方法存根$ rails g rails_email_preview:...

    rails-basic-template:基本 Rails 模板

    Rails 基本模板参考: : Ruby on Rails Gemfile:定义应用程序正在使用的库的文件bundle install:基于Gemfile,安装所有库每次修改 Gemfile 时都应该运行bundle install gem 是 Ruby 的库RubyGems.org 是一个查找和...

    rails-ansible-presentation:有关Rails + Ansible的Deckset演示

    [适合] Rails :red_heart: Ansible [适合] Rails :red_heart: Ansible (有一点帮助) Rails部署 简单吧? 将应用程序放在服务器上。 捆绑宝石。 应用迁移。 重新启动服务。 Easy Rails部署 git push master ...

    rails-style-guide:社区驱动的Ruby on Rails样式指南

    本指南的目的是为Ruby on Rails 4开发提供一组最佳实践和样式说明。 它是对现有社区驱动的的补充。 本Rails风格指南推荐了最佳实践,以便实际的Rails程序员可以编写可由其他实际的Rails程序员维护的代码。 会使用...

    Ruby on Rails入门经典代码

    通过学习和实践压缩包中的"Ruby on Rails入门经典代码",新手不仅可以了解Rails的基本概念,还能掌握实际项目中的应用技巧,逐步成长为一名熟练的Rails开发者。记得不断探索、实践和学习新的Rails知识,以适应不断...

    rails_console_toolkit:可配置的 Rails 控制台助手

    安装将此行添加到应用程序的 Gemfile 中: gem 'rails_console_toolkit' 然后生成初始化程序: $ bin/rails generate rails_console_toolkit:install或手动编写: # config/initializers/console....

    webpack-rails, 将 web pack与你的Ruby on Rails 应用程序集成.zip

    webpack-rails, 将 web pack与你的Ruby on Rails 应用程序集成 不再维护webpack-rails 不再被维护。... web pack-railsweb pack 为你提供了将 web pack集成到现有的Ruby on Rails 应用程序中的工具。它很乐

    rails-dom-testing:从ActionView中提取DomAssertions和SelectorAssertions

    Rails :: Dom :: Testing 这个gem负责比较HTML DOM并断言Rails应用程序中存在DOM元素。 assert_dom_equal通过assert_dom_equal和assert_dom_not_equal进行比较。 元素通过assert_dom , assert_dom_encoded , ...

    Rails中应用Ext.tree:以中国的省市地区三级联动选择为例

    这篇博客文章“Rails中应用Ext.tree:以中国的省市地区三级联动选择为例”提供了一个实用的示例,教我们如何利用Ext.js库中的Tree组件来实现这种功能。 首先,让我们了解Rails和Ext.js的基本概念。Rails是基于Ruby...

    rails-guide-blog:为了刷新我对Ruby on Rails的了解,我正在从https建立这个博客

    《 Rails指南》中的当前步骤: : 与在控制器和视图之间传递数据的典型方式相反(直接使用实例变量),我将使用控制器中定义的属性访问器方法,以减少由于实例变量名称的拼写错误而导致NoMethodError出现nil的可能性...

    rails-developer-scanning:针对Rails开发人员的自动面试问题

    标题 "rails-developer-scanning" 指向的是一个针对Rails开发者设计的自动化面试工具,旨在帮助面试官或招聘者快速有效地评估应聘者的Rails技能。这个工具名为 "jyaasa_interviewer",通过RubyGem安装,使得面试过程...

    rails-controller-testing:将`assigns`和`assert_template`带回到您的Rails测试中

    Rails :: Controller :: Testing 这个gem将assigns给控制器测试的内容以及assert_template带回assigns控制器和集成测试的内容。 这些方法已中。 安装 将此行添加到您的应用程序的Gemfile中: gem 'rails-...

    vite_rails:Rails中的:high_voltage:Vite.js,为您JavaScript体验带来欢乐

    允许您使用为Rails应用程序的前端供电。 是将前端工具像Ruby一样进行编程,纯属喜悦! :smiling_face_with_heart-eyes: 或在运行的检查。 产品特点 :high_voltage: :light_bulb: 即时服务器启动 :high_voltage: ...

    rails有用的命令

    在Ruby on Rails框架中,命令行工具是开发者日常工作中不可或缺的一部分。Rails命令允许我们快速地构建应用程序、管理数据库、生成代码以及执行各种自动化任务。以下是一些关键的Rails命令及其详细解释: 1. **创建...

    rails-html-sanitizer

    如果您在非Rails应用程序中需要类似的功能,请考虑直接使用(这是处理内幕消毒的原因)。 安装 将此行添加到您的应用程序的Gemfile中: gem 'rails-html-sanitizer' 然后执行: $ bundle 或将其自己安装为: $...

Global site tag (gtag.js) - Google Analytics