[the] 海报说,如果我们不使用客户端 SSL 认证,服务器并不真正知道它在与谁交谈。
那不是我说的:) 这就是我说的:
除非您使用 TLS 客户端身份验证,否则单独的 SSL 不是 REST API 的可行身份验证机制。
单独是这里的关键词。还:
如果您不使用 TLS 客户端身份验证,则需要使用基于摘要的身份验证方案(如 Amazon Web Service 的自定义方案)或 OAuth 甚至 HTTP 基本身份验证(但仅通过 SSL)。
换句话说,TLS 客户端身份验证是对 REST API 客户端进行身份验证的一种方式。因为最初的 SO 问题是关于 SSL 的,所以我提到如果您仅依赖 TLS,TLS 客户端身份验证是唯一的“内置”身份验证形式。因此,如果您使用 TLS,并且您没有利用 TLS 客户端身份验证,则必须使用其他形式的身份验证来对您的客户端进行身份验证。
有很多方法可以对 REST 客户端进行身份验证。TLS 客户端身份验证只是其中之一(TLS 的唯一“内置”身份验证,通常非常安全)。然而,TLS 是一种网络级协议,大多数人认为对于许多最终用户来说配置过于复杂。因此,大多数 REST API 产品选择更易于使用的应用程序级协议,例如 HTTP,因为它对大多数人来说更易于使用(例如,只需设置一个 HTTP 标头)。
因此,如果您要使用 HTTP 标头路由,则必须使用标头值来验证 REST 客户端。
在 HTTP 身份验证中,您有一个标头 ,Authorization
和它的值(标头名称相当不幸,因为它通常用于身份验证,而不是经常用于访问控制,即授权)。标Authorization
头值是服务器用来执行身份验证的值,它(通常)由三个令牌组成
- HTTP 身份验证方案名称,后跟
- 空格(几乎总是一个空格字符),后跟
- 特定于方案的文本值。
一种常见的 HTTP 身份验证方案是该Basic
方案,它非常……嗯……基本 :)。特定于方案的文本值只是以下计算值:
String concatenated = username + ":" + raw_password;
String schemeSpecificTextValue = base_64_encode(concatenated.toCharArray());
因此,您可能会看到相应的标题如下所示:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
服务器知道如何解析该值。它说“嘿,我知道Basic
方案,所以我将采用尾随文本值,base64对其进行解码,然后我将获得用户名和提交的密码。然后我可以查看这些值是否与我存储的值匹配。”
这本质上是Basic
身份验证。因为这个方案特别包括提交的原始密码 base64 编码,所以除非您使用 TLS 连接,否则它不被认为是安全的。TLS 保证(大部分)窥探者无法拦截标头(例如通过数据包检查)并查看密码是什么。这就是为什么您应该始终将 TLS 与 HTTP 基本身份验证一起使用。即使在公司内部网环境中。
当然,还有其他更安全的 HTTP 身份验证方案。一个示例是使用基于摘要的身份验证的任何方案。
基于摘要的身份验证方案更好,因为它们的方案文本值不包含提交的密码。相反,计算某些数据(通常是其他标头字段和值)的基于密码的散列,并将结果放入Authorization
标头值中。服务器使用它在本地存储的密码计算相同的基于密码的哈希值。如果服务器的计算值与请求的标头值匹配,则服务器可以认为请求已通过身份验证。
这就是为什么这种技术更安全的原因:只传输散列 - 而不是原始密码本身。这意味着即使通过明文(非 TLS)连接也可以使用此技术对请求进行身份验证(但当然,如果请求数据本身不敏感,您只想这样做)。
一些基于摘要的身份验证方案:
Amazon 和其他类似的 REST 比 OAuth 1.0a 更安全,因为它们始终验证整个请求 - 包括请求实体有效负载(即 HTTP 标头之后的所有内容)。OAuth 1.0a 仅针对与使用或有效负载application/x-www-form-urlencoded
的 REST API 无关的内容(目前大多数 REST API)执行此操作。application/xml
application/json
有趣的是,OAuth2不是基于摘要的——它使用了我认为不太安全的东西,称为“不记名令牌”(在许多情况下确实很好,但仍然不如银行、军事和政府通信中使用的摘要方案)。