一、前言
出于数据安全性考虑,某些破坏性链接应该使用post请求,比如一个删除记录的请求。
除了脚本确认以外,服务端还需要post验证,因为脚本是可以绕过的。想像你的页面上有一个删除链接,只作了客户端脚本确认(老的scaffold生成代码有这问题),被google找到了,它一个请求就会让你的数据丢失。
rails对于这类请求的处理,是通过verify方法,默认的scaffold生成代码有如下内容:
<!----> # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => :post, :only => [ :destroy, :create, :update ],
:redirect_to => { :action => :list }
只有post请求时,destroy才会被允许,如果是get,就会被重定向到list。
二、实现我自己实现了一个method_dispatch,当请求一个/test/a时,如果是get,则会直接执行TestController#a;如果是post,则会执行TestController#a_post,a_post应该是protected,这样不会直接暴露给客户,get/post就严格区分开来了。
method_dispatch现在是直接实现在ApplicationController中的,代码如下:
<!---->class ApplicationController < ActionController::Base
protected
def self.method_dispatch(*methods)
before_filter :do_method_dispatch, :only => methods.flatten.map(&:to_sym)
end
private
def do_method_dispatch
if request.post? && respond_to?("#{action_name}_post")
eval("#{action_name}_post")
return false
end
end
end
由于ApplicationController里面的方法会被子类继承到,所以必须严格处理访问级别。
使用如下:
<!---->class TestController < ApplicationController
method_dispatch :a
def index
end
def a
render :text => 'get a'
end
def b
render :text => 'get b'
end
protected
def a_post
render :text => 'post a'
end
def b_post
render :text => 'post b'
end
end
注意a_post,b_post要被保护起来防止直接调用。
index.rhtml里面演示了使用get和post的情况:
<!----><%= link_to "Get a", :action => 'a' %>
<%= link_to "Post a", {:action => 'a'}, {:post => true} %><br />
<%= link_to "Get b", :action => 'b' %>
<%= link_to "Post b", {:action => 'b'}, {:post => true} %><br />
rails在处理有:post => true参数的link_to时,生成的代码如下:
<!----><a href="/test/a" onclick="var f = document.createElement('form');
this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href; f.submit();return false;">Post a</a>
经测试上面代码工作情况良好,使用get访问/test/a时,显示get a;使用post访问时,显示post a。使用get访问/test/b时,显示get b;使用post时,显示get b,因为b并没有使用method_dispatch。
三、应用下面的posts_controller.rb是scaffold生成的:
<!---->class PostsController < ApplicationController
def index
list
render :action => 'list'
end
# GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => :post, :only => [ :destroy, :create, :update ],
:redirect_to => { :action => :list }
def list
@post_pages, @posts = paginate :posts, :per_page => 10
end
def show
@post = Post.find(params[:id])
end
def new
@post = Post.new
end
def create
@post = Post.new(params[:post])
if @post.save
flash[:notice] = 'Post was successfully created.'
redirect_to :action => 'list'
else
render :action => 'new'
end
end
def edit
@post = Post.find(params[:id])
end
def update
@post = Post.find(params[:id])
if @post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
redirect_to :action => 'show', :id => @post
else
render :action => 'edit'
end
end
def destroy
Post.find(params[:id]).destroy
redirect_to :action => 'list'
end
end
可以看到,它添加了verify,但action过多,需要在verify中维护一份对应方法名,稍不留神就容易出现漏洞。
我把它修改如下:
<!---->class PostsController < ApplicationController
method_dispatch :new, :edit, :destroy
def index
list
render :action => 'list'
end
def list
@post_pages, @posts = paginate :posts, :per_page => 10
end
def show
@post = Post.find(params[:id])
end
def new
@post = Post.new
end
def edit
@post = Post.find(params[:id])
end
def destroy
render :inline => <<-EOS
Are you sure?
<%= link_to "Yes", {}, :post => true %>
<%= link_to "No", :action => 'edit', :id => params[:id]%>
EOS
end
protected
def destroy_post
Post.find(params[:id]).destroy
redirect_to :action => 'list'
end
def edit_post
@post = Post.find(params[:id])
if @post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
redirect_to :action => 'show', :id => @post
else
render :action => 'edit'
end
end
def new_post
@post = Post.new(params[:post])
if @post.save
flash[:notice] = 'Post was successfully created.'
redirect_to :action => 'list'
else
render :action => 'new'
end
end
end
相应地,还需要把new.rhtml中的action从create修改到new,把edit.rhtml中的action从update修改到edit。
这样的修改把必须使用post请求的action隐藏起来,而相应的get操作是不修改或删除记录的,如果以post请求,才会自动调用这些保护的方法。
相关推荐
ROR环境 Ruby version 1.9.3 (java) RubyGems version 1.8.24 Rack version 1.4 Rails version 3.2.12 JavaScript Runtime therubyrhino (Rhino) Active Record version 3.2.12 Action Pack version 3.2.12 ...
ror实例ror实例ror实例
NULL 博文链接:https://xuxiangpan888.iteye.com/blog/266696
RoR性能优化经验谈,牛人对ror的优化,值得大家阅读
ror中文资料ror中文资料
单个组织记录由以下JSON结构表示: { "id":"https://ror.org/013cjyk83", "name":"PSL Research University", "email_address":null, "ip_addresses":[ ], "established":2010, "types":[ "Education" ], ...
ROR 架构介绍及了解
基于RoR的博客系统,代码风格简单清晰,前后太完善,适合初学者。
神经网络ror resenet模型 cifar10准确率89% cifar100准确率72%
之前本人在windows 上搭建ROR环境,屡屡受挫,上网查资料、加入ruby on rails的qq群,关注ruby社区等,没有得到一套完整的正确的方法,很多朋友说不要在windows 弄ROR,很费力。的确很费力,后来在朋友的帮助下,...
RoR选题方向—源代码
家蚕Ror2基因的克隆与表达分析,刘伟,陈菲,Ror家族属于受体酪氨酸激酶中的孤儿受体,在进化上非常保守。本研究克隆了家蚕Ror2基因BmRor2的ORF序列,BmRor2基因的ORF为1924 bp,编码638
mysqlDriver4ror.rarmysqlDriver4ror.rarmysqlDriver4ror.rarmysqlDriver4ror.rar
破解版本的JAR包,放到本地磁盘,ECLIPUS直接用,到JVM设置直接加 -noverify -javaagent:D:\javarebel.jar
excel lib ror ruby
freemis 基于ror框架的mis<br/>ruby on rails的一个很好实例
使用 Ruby on Rails 学习测试...cd ~/workspace/tdd_with_ror gem install bundler --version=1.7.9 bundle install bundle exec rake db:create db:migrate 运行测试并按照说明进行操作 bundle exec rspec 享受!
我自己再开发时的笔记
插件,可以不用到那个网站上去下了,还有mysql-front备份文件,大家可以直接导入。 博文链接:https://msdn.iteye.com/blog/44807
Source.Insight.v3.50.0027-ROR.rar