在RESTful路由模型中防止可发现性

时间:2011-03-11 22:40:44

标签: ruby-on-rails ruby-on-rails-3 rest routes

我的数据库中有一个模型,其“show”操作可以在以下URL中查看:

mysite.com/project/12
mysite.com/project/14

我的系统设置方式,有几种定义的方法可以访问它们:

  • 具有此路线的任何访客(已注册或未注册)均可访问我设置的自定义路线。例如,此自定义路由可能是mysite.com/companyname/projectid,公司可能会将自己传递给想要访问的某些人。请注意,此自定义路由会运行单独的控制器操作,该操作会设置一些内部分析,然后重定向到show操作。
  • 由注册用户的主页链接时直接访问。

我想限制以mysite.com/project/14开头的能力,然后只需更改ID,从而查看任何项目。我怎么能这样做?

澄清

我对这个问题的目标不仅仅是混淆记录ID,以便更难发现某些记录。相反,我希望只有两种允许访问project/12的方法:

  1. 用户点击我们在其主页上提供的链接(如何确保此链接单独到达项目12?)
  2. 用户或简单访问者通过另一个(特定)控制器操作重定向到此处。
  3. 不应该直接输入project/12。目前,我认为最好的方法是通过上述两种方法传递project#show动作获取的代码。我只是不知道如何实现这个,如果有潜在的缺点。

4 个答案:

答案 0 :(得分:2)

最简单的方法是将项目与用户或帐户相关联,然后在浏览非公共路径时要求进行身份验证。如果您设置了关联,则可以执行以下操作:

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

这将确保给定用户只能找到他们拥有的项目。

如果您不想要授权,并且只是想要混淆,那么您将无法在路径中单独使用“id”(因为它是连续的)。您可以将'id'与存储在模型中的随机密钥配对(/ projects / 1?key = 1234),也可以使用GUID而不是id。

答案 1 :(得分:2)

无论你想出什么 - 由于这个简单的要求,它最终会因为默默无闻而变得安全:

  

用户点击我们提供的链接   他们的主页(我怎么能确保这一点   链接单独到达项目12?)

但是,您可以做的是直接猜测项目的正确URL。

我的想法是为每个项目提供一个独特的“令牌” - 如果您没有以项目的所有者身份登录,那么您必须使用该令牌来访问它。

例如,在您的项目模型中,您可以拥有:

class Project
  before_create :set_public_token

  protected
    def set_public_token
      # Randomizes a 20-digit long hex code
      self.token = ActiveSupport::SecureRandom.hex(20)
    end
end

然后,在你的项目的show动作中你需要有这个:

class ProjectsController < ApplicationController
  def show
    @project = Project.find(params[:id])
    # Obviously you would changed signed_in? to whatever method
    # you have that verifies someone is logged in
    if !signed_in? || @project.owner_id != current_user.id
      raise "Unauthorized Access" if @project.token != params[:token]
    end
  end
end

然后项目的所有者可以将他们项目的“公共”链接分享给他们想要访问它的人,这看起来像这样:

www.example.com/projects/14?token=3jks83kasdkt84h6cd86

同样,任何人使用该网址都可以访问该项目,我认为您无法远离这一点 - 但这使得这样做更加困难。

这与许多密码重置功能的工作方式相同。有权访问密码重置令牌的人可以在您请求密码后重置密码。但是知道使用什么标记会使你年龄增长(使标记更长,以使暴力更难)。

我个人就是如何处理它,以及我过去如何看待这种事情(photobucket,github上的私人要点等)

答案 2 :(得分:1)

好了,现在再次尝试,我有点理解。

首先在您的公共控制器操作中,您要执行以下操作:

def public_redirect
  session[:authorized_for] = params[:id]
  redirect_to resource_show_path(params[:id])
end

现在在您的私人控制器中:

def show
  @resource = current_user.resources.find params[:id]
  if @resource # authorized
    respond_with @resource # ok
  elsif session[:authorized_for] == params[:id] #redirected from public route
    @resource = Resource.find params[:id]
    respond_with @resource # ok
  else
    raise NotAuthorizedException # not ok, do something
  end
end

这取决于会话。这当然是可以攻击的,但是要弄清楚公共路线要困难得多。请参阅http://guides.rubyonrails.org/security.html#sessions

您可以将会话技术重用于其他类似需求(例如,您无法从控制器验证用户的主页链接等。

答案 3 :(得分:0)

我有一个类似要求的项目。现在我首先觉得有必要说这是默默无闻的安全 - 因此根本没有太大的安全性。但是对于一些可以没问题的应用程序。

我的模型上有一个创建回调,它生成一个随机字符串(或数字),用作我的ID - 因此不可能很难猜测另一个资源的路径。