REST和身份验证变体


70

我目前正在研究.net的REST库,我想听听有关我拥有的一个开放点的一些意见:REST和身份验证。

这是与库一起使用的RESTful接口的示例:

[RestRoot("/user")]
public interface IUserInterface
{
  [RestPut("/")]
  void Add(User user);

  [RestGet("/")]
  int[] List();

  [RestGet("/get/{id}")]
  User Get(int id);

  [RestDelete("/delete/{id}")]
  void Delete(int id);
}

然后,服务器代码仅实现该接口,客户端可以通过工厂获得相同的接口。或者,如果客户端未使用库,则标准HTTP请求也可以使用。

我知道,有使用HTTP基本身份验证或将令牌发送到需要经过身份验证的用户的请求的主要方法。

第一种方法(HTTP基本身份验证)具有以下问题(部分特定于Web浏览器):

  • 密码随每个请求一起发送-即使使用SSL,也会有某种“不好的感觉”。
  • 由于密码是与请求标头一起发送的,因此本地攻击者很容易查看发送的标头以获取密码。
  • 密码在浏览器的内存中可用。
  • 没有使用户“会话”过期的标准方法。
  • 使用浏览器登录会中断页面​​的外观。

第二种方法的问题更多地集中在实现和库使用上:

  • 每个需要认证的请求URI必须具有用于令牌的参数,该参数非常重复。
  • 如果每个方法实现都需要检查令牌是否有效,则还有很多代码要编写。
  • 该界面将变得不那么具体如[RestGet("/get/{id}")][RestGet("/get/{id}/{token}")]
  • 将令牌放在何处:URI的末尾?后根?别的地方?

我的想法是将令牌作为参数传递给URL,例如http:/server/user/get/1234?token=token_id

另一种可能性是将参数作为HTTP标头发送,但是我猜这会使普通HTTP客户端的使用变得复杂。

令牌将作为每个请求的自定义HTTP标头(“ X-Session-Id”)传递回客户端。

然后可以从接口中完全提取该令牌,并且任何需要身份验证的实现都可以询问令牌(如果给定)属于哪个用户。

您是否认为这会严重违反REST或您有更好的主意?

Answers:


64

我倾向于认为身份验证详细信息属于标头,而不是URI。如果您依赖将令牌放置在URI上,则应用程序中的每个URI都需要进行编码以包含令牌。这也会对缓存产生负面影响。令牌不断变化的资源将不再能够被缓存。与资源有关的信息属于URI,而不属于与应用程序有关的数据(例如凭据)。

看来您必须将Web浏览器定位为客户端?如果是这样,您可以使用HTTP摘要访问身份验证进行调查或向客户端颁发自己的SSL证书来唯一地标识和验证它们。另外,我认为会话cookie不一定是一件坏事。特别是在必须与浏览器打交道时。只要您隔离cookie处理代码并使应用程序的其余部分不依赖它,就可以了。关键是仅将用户的身份存储在会话中,而没有其他存储。不要滥用服务器端会话状态。

如果您将浏览器以外的客户作为目标客户,则可以采用多种方法。我对使用Amazon的S3身份验证机制感到幸运。

当然,这都是非常主观的。纯度和遵循REST有时是不切实际的。只要您最小化和隔离此类行为,应用程序的核心仍然可以是RESTful。我强烈建议RESTful Web服务作为REST信息和方法的重要来源。


在S3示例中,他们与客户端共享加密密钥-这很不好,不是吗?
Gill Bates

像任何类型的共享秘密密码术一样,双方都必须保持密钥的保密性。在这方面,对称密码学也并不差。
laz 2014年

15

我同意workmad3,如果需要维持会话的生存时间,则应该创建一个会话资源。使用用户凭据(基本身份验证或正文内容中的凭据)在该资源上发布的内容将返回唯一的会话ID。在/ session / {id}上删除将注销用户。

如果要控制会话的到期时间。创建新会话(在会话资源上发布)时,服务器将在响应上设置cookie(使用标准的set-cookie标头)。Cookie将包含有效时间。cookie字符串应在服务器上加密,因此只有服务器才能打开该cookie。对服务器的每个后续请求都将在cookie标头中发送会话cookie。(如果您的客户端是浏览器,它将自动为您完成)。服务器需要针对每个请求“更新” cookie,即使用新的到期时间(扩展会话的超时)创建新的cookie。当用户在会话资源上调用delete时,请记住清除cookie。

如果希望您的应用程序更安全,则可以将客户端IP存储在cookie本身中,这样,当请求到达时,服务器可以验证它是从“原始”客户端发送的。但是请记住,当涉及代理时,此解决方案可能会出现问题,因为服务器可能会将所有请求“视为”来自同一客户端。


我在这里看不到代理问题。只是由于某些客户端看起来是相同的事实而降低了增加的安全性。Cookies也应该是httpOnly
maaartinus

4

我看到的其余身份验证将会话视为用于创建,销毁等的REST资源,然后将会话ID往返传递。我见过的人倾向于为此使用会话cookie,因为这是真正保护它的唯一方法。如果您在URL中传递会话ID,您将无法真正验证来自正确客户端的会话ID。

但是,身份验证对于REST是一个棘手的问题,因为它要求某种形式的状态保持在URL外部,这违反了URL的REST原理,即代表状态所需的全部内容。


如果不在安全的网络内部使用它,并且由于使用UUID进行会话,它将始终使用SSL,因此它的来源应该不是问题。是什么阻止某人伪造cookie?
Fionn

3
我不会说让URI代表状态所需要的就是REST的原理。相反,让资源可寻址,并且请求中包含的所有应用程序状态似乎是一种更好的陈述方式。
laz

您可以使用MAC保护cookie,例如,服务器拥有一个秘密,并将以下会话令牌分发给客户端:<sessionid> _ <mac>其中mac被构造为SHA1(<session_id> _ <secrect>)当客户端发送令牌<session_id> _ <mac>时,服务器必须检查<sessionid> _ <secret>是否等于<mac>
ordnungswidrig 2010年

18
在这些讨论中,区分应用程序状态(会话状态)和资源状态很重要。在RESTful架构中,资源状态存储在服务器端,而应用程序状态存储在客户端。[
infoq.com/articles/mark-baker-hypermedia

1
@maaartinus:目前(由于这个问题是“很早以前”提出的),我不再考虑使用任何会话数据作为URL的一部分,这似乎合乎逻辑,但从第二个角度看,风险太大了。
Fionn
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.