本站首页    管理页面    写新日志    退出


«August 2025»
12
3456789
10111213141516
17181920212223
24252627282930
31


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7577996
建立时间:2006年5月29日




[Ruby on Rails]Post/Get分派
软件技术

lhwork 发表于 2007/2/8 10:04:26

一、前言 出于数据安全性考虑,某些破坏性链接应该使用post请求,比如一个删除记录的请求。除了脚本确认以外,服务端还需要post验证,因为脚本是可以绕过的。想像你的页面上有一个删除链接,只作了客户端脚本确认(老的scaffold生成代码有这问题),被google找到了,它一个请求就会让你的数据丢失。rails对于这类请求的处理,是通过verify方法,默认的scaffold生成代码有如下内容: <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->  # 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中的,代码如下: <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->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  endend由于ApplicationController里面的方法会被子类继承到,所以必须严格处理访问级别。使用如下: <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->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'  endend注意a_post,b_post要被保护起来防止直接调用。index.rhtml里面演示了使用get和post的情况: <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><%= 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时,生成的代码如下: <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><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生成的: <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->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'  endend可以看到,它添加了verify,但action过多,需要在verify中维护一份对应方法名,稍不留神就容易出现漏洞。我把它修改如下: <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->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  endend相应地,还需要把new.rhtml中的action从create修改到new,把edit.rhtml中的action从update修改到edit。这样的修改把必须使用post请求的action隐藏起来,而相应的get操作是不修改或删除记录的,如果以post请求,才会自动调用这些保护的方法。


阅读全文(2714) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.063 second(s), page refreshed 144761514 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号