RESTful Web 服务认证

Posted

技术标签:

【中文标题】RESTful Web 服务认证【英文标题】:Restful web service authentication 【发布时间】:2011-04-05 06:34:51 【问题描述】:

我有一个 Restful Web 服务 API,被不同的 3rd 方使用。该 API 的一部分受到限制(您需要用户名/密码才能访问它)。我想知道实现身份验证的最佳方式是什么?

我使用的是 https,所以通信是加密的。我有两个想法:

在用户开始使用(受限)服务之前,它使用 POST 发送用户名/密码(因为使用了 https,凭据已加密)。登录成功后,服务器发回与该用户名匹配的随机一次性值(nonce)。当发出下一个请求时,除了用户名之外,客户端还会发送先前返回的 nonce。服务器匹配用户名和随机数,并在请求的数据旁边返回新的随机数。每个新请求都使用新的 nonce。基本上,这是 Digest 访问身份验证的轻量级版本。 由于此 API 是从第 3 方使用的,用户名/密码可用于每个(受限)请求。由于正在使用 https,因此它们将被加密。这种方法的缺点是它不符合 Restful 标准(将始终使用 POST)。

我更接近于选择第一种方法(它符合 Restful,相对容易实现,无需更改任何内容即可使用 XML、json 或 html),但我想看看您的意见是什么?您有什么建议:第一种、第二种或第三种方法?

顺便说一句,我在服务器端使用 Python。

【问题讨论】:

【参考方案1】:

亚马逊网络服务做得很好,请查看那里的方法以获得一些想法。本质上,他们让客户端使用他们的密码加密一个特殊的 http 标头。

这是链接:

http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html

【讨论】:

任何衡量标准的最佳答案。如果您可以在这里对算法本身进行一个很好的介绍,我相信您很快就会获得大量的赞成票!我认为,最重要的一点是:“您首先使用您的秘密访问密钥创建一个签名密钥。签名密钥的范围仅限于特定区域和服务。此外,签名密钥在创建后 7 天到期。因为签名密钥的范围和生命周期是有限的,如果签名密钥被泄露,您的数据面临的风险会更小。”【参考方案2】:

我在 API 中看到的一种方法(以及当前实现它的方法)是创建一个名为 Session 的 RESTful 资源,该资源是通过 POST 创建的它提供了用户名和密码。

这基本上是我实现它的方式:

POST /sessions  Username: "User", Password: "Password" 

创建一个限时会话并返回包含会话密钥值和到期时间的会话资源。为了方便 API 客户端的实现,您可能还希望将其作为 cookie 值返回。

DELETE /session/id

立即使会话过期,使其无法再使用。这用于显式注销。

然后我让用户通过查询参数附加会话密钥,尽管您也可以允许它通过 cookie 值提交,我建议允许两者。

我更喜欢的是它非常简单。

显然,您的场景将在某种程度上决定您的会话应该如何管理,也许它们没有时间限制并且无限期地持续,并且也许它们被散列或加密以增加安全性。

如果您在任何地方都使用 HTTPS,您可能不需要太担心。但是,如果您想使用 HTTP,您将需要使用诸如散列和密钥之类的东西,并说出一个时间戳来为每个请求生成一个安全密钥。通过这种方式,您可以通过 HTTPS 共享密钥,然后切换到 HTTP 以进行进一步调用。即使有人设法从请求中嗅出密钥,它也几乎会立即过期并且无用。

免责声明:我不是安全专家 ;-)。

【讨论】:

如果您在服务器上使用会话,则您的 API 不是 RESTful,因为服务器有状态。每个请求都应包含所有必要的数据,并且服务器不应依赖会话。将会话数据保存在 JSON Web 令牌中,客户端在每个请求的标头中发送该令牌。例如,您可以在其中打包一个序列化的用户对象(我就是这样做的)。 这似乎有点迂腐,而且还假定身份验证严格“RESTful”很重要。但是,如果您的应用程序有必要或很重要以这种方式执行操作,则 JWT 之类的方法确实可以解决此问题。【参考方案3】:

这里没有理由不只使用 HTTP 身份验证。

也就是说,通过 POST 获取时间块 nonce 的概念可以很好地发挥作用。但这就是为什么您首先需要跳过那个额外的圈子的动机。

在对原始密码使用 bcrypt 哈希时考虑了这种技术,因为验证用户的实际费用(如果您不知道,可以调整 bcrypt 以花费大量实时来执行哈希函数)。选择提供选项让服务“登录”一次使用密码,该密码将通过 bcrypt 进行昂贵的验证过程,然后将获得时间阻塞令牌以换取未来绕过 bcrypt 过程的请求.

在 bcrypt 进程的情况下,使用 HTTP 身份验证,该服务将使用普通密码和令牌工作。这样用户就可以始终使用密码来提供服务,但这只会变得昂贵。所以他们可以这样做,但他们不应该这样做。该服务不关心客户端使用哪种身份验证技术。

nonce 服务是为了提高吞吐量而提供的。

除此之外,它是标准的 HTTP 身份验证,但采用了新方案。

【讨论】:

不使用 HTTP 身份验证的一个原因是浏览器会在每个请求中自动发送该身份验证,从而使您受到 CSRF 攻击。不过,使用自定义授权方案是可以的。或者使用自定义标题。【参考方案4】:

假设该服务从未在浏览器中使用并且通信无论如何都是加密的,我认为第二种方法的变体没有任何危害:添加 X-Headers 以在每个请求中发送用户名/密码,例如:

GET /foo HTTP/1.1
Host: www.bar.com
X-MyUsername: foo
X-MyPassword: bar

另一个想法是使用 HTTP Basic Auth 并发送一个Authorization: Basic base64(user:password)-Header。也就是说,如果连接始终是加密的。

【讨论】:

这种情况下如何实现'login'和'logout'? 我认为在这种情况下没有“登录”或“注销”,因为您在每个请求中都发送用户名/密码。 由于跨站请求伪造,Basic Auth 仍然没有那么好。 您绝对不想发送未加密的永久密码。作为一般经验法则,您甚至希望尽量减少重新发送加密密码,并改用临时令牌(就像会话密钥一样)。

以上是关于RESTful Web 服务认证的主要内容,如果未能解决你的问题,请参考以下文章

Yii2高速构建RESTful Web服务功能简单介绍

RESTful 用户认证服务

使用带有摘要身份验证、jquery ajax 调用的 RestFul PHP Web 服务

2022就业季|Spring认证教你,如何使用 Spring 构建 REST 服务

Restful安全认证及权限的解决方案

使用Spring Security和OAuth2实现RESTful服务安全认证