我正在开始为我正在开发的项目构建REST API,这让我对使用RoR构建API的最佳方法进行了一些研究.我很快就发现,默认情况下,模型对世界开放,只需在URL末尾添加".xml"并传递适当的参数即可通过URL调用.
那么下一个问题来了.如何保护我的应用以防止未经授权的更改?在做一些研究时,我发现了几篇文章attr_accessible
,attr_protected
以及如何使用它们.我发现的特定网址是在07年5月(这里)发布的.
和ruby一样,我确信自那时起事情已经发生了变化.所以我的问题是,这仍然是在RoR中保护REST API的最佳方法吗?
如果不是你在"新项目"或"现有项目"情景中建议什么?
有几种用于验证API请求的方案,它们与由restful_authentication或acts_as_authenticated等插件提供的正常身份验证不同.最重要的是,客户端不会维护会话,因此没有登录的概念.
HTTP身份验证
您可以使用基本的HTTP身份验证.为此,API客户端将使用常规用户名和密码,并将其放入URL中,如下所示:
http://myusername:mypass@www.someapp.com/
我相信restful_authentication支持开箱即用,因此您可以忽略某人是否通过API或浏览器使用您的应用程序.
这里的一个缺点是,您要求用户在每个请求中明确地输入他们的用户名和密码.通过SSL执行此操作,您可以确保安全.
不过,我认为我从未见过使用它的API.对我来说这似乎是一个不错的主意,特别是因为当前的身份验证方案支持开箱即用,所以我不知道问题是什么.
API密钥
启用API身份验证的另一种简单方法是使用API密钥.它本质上是远程服务的用户名.当有人注册使用您的API时,您可以为他们提供API密钥.这需要与每个请求一起传递.
这里的一个缺点是,如果有人获得别人的API密钥,他们可以作为该用户发出请求.我认为通过使所有API请求都使用HTTPS(SSL),您可以稍微抵消这种风险.
另一个缺点是用户在任何地方都使用相同的身份验证凭据(API密钥).如果他们想撤销对API客户端的访问权限,他们唯一的选择是更改其API密钥,这也会禁用所有其他客户端.这可以通过允许用户生成多个API密钥来减轻.
API密钥+密钥签名
不推荐使用(有点) - 请参阅下面的OAuth
使用密钥签署请求显然更复杂.这就是亚马逊网络服务(S3,EC2等).基本上,您为用户提供了2个密钥:他们的API密钥(即用户名)和他们的密钥(即密码).API密钥随每个请求一起传输,但秘密密钥不是.相反,它通常通过添加另一个参数来用于对每个请求进行签名.
IIRC,亚马逊通过将所有参数应用于请求并通过参数名称对它们进行排序来实现此目的.然后,使用用户的密钥作为散列密钥对该字符串进行散列.在发送之前,此新值将作为新参数附加到请求.在亚马逊方面,他们做同样的事情.它们采用所有参数(签名除外),对它们进行排序,并使用密钥进行哈希处理.如果这与签名匹配,则他们知道请求是合法的.
这里的缺点是复杂性.无论是API开发人员还是客户端,让这个方案正常工作都是一件痛苦的事.期待来自客户端开发人员的大量支持电话和愤怒的电子邮件,他们无法让事情发挥作用.
OAuth的
为了解决密钥+秘密签名的一些复杂性问题,出现了一个名为OAuth的标准.核心OAuth是密钥+秘密签名的一种风格,但其中大部分是标准化的,并且已被包含在许多语言的库中.
通常,API生产者和消费者使用OAuth要比使用OAuth更容易,而不是创建自己的密钥/签名系统.
OAuth还固有地对访问进行分段,为每个API使用者提供不同的访问凭据.这允许用户有选择地撤销访问而不影响其他消费应用程序.
特别是对于Ruby,有一个OAuth gem,为OAuth的生产者和消费者提供开箱即用的支持.我已经使用这个gem来构建API并且也使用OAuth API并且给我留下了深刻的印象.如果您认为您的应用程序需要OAuth(而不是更简单的API密钥方案),那么我可以轻松地推荐使用OAuth gem.
如何保护我的应用以防止未经授权的更改?
attr_accessible
并且attr_protected
对于控制在ActiveRecord模型上执行批量分配的能力都很有用.你肯定想使用attr_protected来防止表单注入攻击; 请参阅使用attr_protected或我们会破解您.
此外,为了防止任何人能够访问您的Rails应用程序中的控制器,您几乎肯定需要某种用户身份验证系统并before_filter
在您的控制器中放置一个以确保您有一个授权用户发出请求在允许执行请求的控制器操作之前.
有关更多有用的信息,请参阅Ruby on Rails安全指南(Rails文档项目的一部分).