这位发布者说如果我们不使用客户端SSL认证,服务器就不知道自己正在与谁通信。
这不是我说的 :) 我说的是:
除非您使用TLS客户端身份验证,否则仅靠SSL不是REST API的可行身份验证机制。
alone 是关键词。另外:
如果您不使用TLS客户端身份验证,则需要使用某种摘要基于身份验证方案(例如Amazon Web Service的自定义方案)或OAuth甚至只在SSL上启用HTTP Basic身份验证。
换句话说,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 (Transport Layer Security) 保证(大多数情况下)窥探者无法拦截报头(例如通过数据包检查)并查看密码信息。这就是为什么您应该始终在HTTP Basic认证中使用TLS。即使在公司内部网络环境中也是如此。
当然还有其他更安全的HTTP身份验证方案。一个例子是任何使用基于摘要的身份验证的方案。
基于摘要的身份验证方案更好,因为它们的方案文本值不包含提交的密码。相反,计算特定数据的基于密码的哈希值(通常是其他标头字段和值),并将结果放入Authorization
标头值中。服务器使用存储在本地的密码计算相同的基于密码的哈希值。如果服务器计算出的值与请求的标头值匹配,则可以考虑请求已得到身份验证。
这种技术之所以更安全,是因为仅传输哈希 - 而不是原始密码本身。这意味着即使在明文(非TLS)连接上也可以使用此技术进行请求身份验证(当然,只有在请求数据本身不敏感时才应这样做)。
一些基于摘要的身份验证方案:
与OAuth 1.0a相比,像Amazon和其他类似的方案对REST来说更加安全,因为它们始终对整个请求进行身份验证,包括请求实体负载(即HTTP头之后的所有内容)。OAuth 1.0a仅适用于application/x-www-form-urlencoded
内容,而这不适用于使用application/xml
或application/json
负载的REST API(这是大多数REST API这些天)。
有趣的是,OAuth2 不是基于摘要的 - 它使用我认为不太安全的“承载令牌”(在许多场景中它们是可以的,但仍然不如银行、军事和政府通信中使用的摘要方案好)。