采用自定义`redirect_to`方法的缺点和支持

为了在每次params包含redirect_uri值时将用户重定向到自定义网页,我正在评估以这种方式使用自定义redirect_to方法 (通过@kiddorails ):

 class ApplicationController < ActionController::Base def custom_redirect_to(url) redirect_to (params[:redirect_uri].present? ? params[:redirect_uri] : url) end end def create @post = Post.new(params) if @post.save custom_redirect_to @post else render 'new' end end 

但是,我想知道可能的缺点并获得采用上述解决方案的支持。

允许通过URL参数设置重定向目标而不进行任何validation对您的用户来说可能是危险的,因为它使捕获尝试更容易。

攻击者可以向您的用户发送链接,例如

http://my-trusted-site.com/some/action/path?redirect_uri=malicious-site-that-looks-like-trusted-site.com

,许多用户只会看到域部分,并且无法在点击该链接后意识到他们最终的位置。

因此,Open Web Application Security Project(OWASP) 认为这是一个漏洞 :

当Web应用程序接受可能导致Web应用程序将请求重定向到不受信任的输入中包含的URL的不受信任的输入时,可能会出现未经validation的重定向和转发。 通过将不受信任的URL输入修改为恶意站点,攻击者可能会成功启动网络钓鱼诈骗并窃取用户凭据。 由于修改后的链接中的服务器名称与原始站点相同,因此网络钓鱼尝试可能具有更可靠的外观。 未经validation的重定向和转发攻击也可用于恶意创建一个URL,该URL将通过应用程序的访问控制检查,然后将攻击者转发给他们通常无法访问的特权函数。

在执行重定向之前,请务必仔细检查redirect_uri参数。

但是,由于正确的validation很棘手并且容易出错,因此更好的想法是不首先接受URI参数,而是允许某些关键字指定用户将被重定向的位置。

 class ApplicationController < ActionController::Base protected def dynamic_redirect_to(default_route, options) options.stringify_keys! redirect_to options.fetch(params[:redirect_to], default_route) end end 

您现在可以提前定义任意数量的允许关键字,这些关键字可以用作?redirect_to=参数:

 def create @post = Post.new(params) if @post.save dynamic_redirect_to post_path(@post), edit: edit_post_path(@post) else render 'new' end end 

如果设置了?redirect_to=edit则会将用户重定向回编辑页面。 如果未设置参数或包含未指定的关键字,则会将其重定向到默认的post_path(@post)

我同意janfoeh上面所说的话。 但是为了实现您的要求,我在Rails的重定向代码中进行了攻击,以使其更简单。

使用以下命令创建文件config / initializers / redirecting.rb

 require 'abstract_controller/base' module ActionController module Redirecting extend ActiveSupport::Concern include AbstractController::Logger include ActionController::RackDelegation include ActionController::UrlFor def _compute_redirect_to_location(options) if redirect_url = session.delete(:redirect_uri) options = redirect_url end case options # The scheme name consist of a letter followed by any combination of # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") # characters; and is terminated by a colon (":"). # See http://tools.ietf.org/html/rfc3986#section-3.1 # The protocol relative scheme starts with a double slash "//". when /\A([az][az\d\-+\.]*:|\/\/).*/i options when String request.protocol + request.host_with_port + options when :back request.headers["Referer"] or raise RedirectBackError when Proc _compute_redirect_to_location request, options.call else url_for(options) end.delete("\0\r\n") end end end 

在你的app / controllers / application_controller.rb中

 class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. before_action :set_redirect_uri protect_from_forgery with: :exception def set_redirect_uri session[:redirect_uri] = params[:redirect_uri] if params[:redirect_uri].present? end end 

还有瞧! 现在您可以继续使用原始redirect_to ,并且只要在url中提供了redirect_uri ,它就会在会话中设置该url并自动覆盖。 🙂

注意 :我只在调用session[:redirect_uri]时清除session[:redirect_uri] 。 您可以根据需要轻松修改该行为以重置此会话。