0%

Security token service

微服务架构和REST API是现在非常热门的技术话题,采用微服务架构之后带来的一个棘手问题是安全和身份认证(Authentication)。这里所指的身份认证,既包括用户的身份,更强调程序和服务的身份,也就是微服务之间调用的信任关系。

认证(Authentication)授权(Authorization)以及审计(Accounting)合称为AAA认证3A认证3A认证在计算机系统和网络应用程序中基本上无处不在。

现代应用程序的一般架构如下:
现代应用程序的一般架构

一些项目在进行微服务架构设计的时候,可能会采用私有网络的方式来保护被拆分的服务,或者配置类似Kerberos的认证系统。这样的做法比较简便,在进行原有整体架构的迁移时可以尽快上线。然而从宏观角度来看,这样的安全模式有一定的局限性,尤其对底层网络架构的依赖会带来不便。如果其中的某个服务需要暴露给外部网络或者互联网,则需要引入其它的解决方案。通常意义上认为微服务是 SOA 架构的一个子集,而关于微服务和 SOA 的区别也有很多的讨论。随着云计算成为主流,容器技术的普及和无服务架构的日趋流行,服务的粒度和和边界定义变得比较灵活,因而要求上层服务与底层计算及网络架构有相对低的耦合度。另外企业混合云的兴起也要求分布在多个云里的服务能协同工作,这对于上面的安全模式也是一大挑战。

Token and STS

最简单的身份验证是使用用户名和密码,包括App Id和App Secret,这也是最普及、最广为接受的一种身份验证方案。但众所周知保存和传递密码都是有很大的安全隐患,而且在大多数的通信过程中也没有必要去传递密码,比较成熟的解决方案是基于数字签名的的令牌(token)。从广义的角度来理解,我们曾今使用过的Session IDs/ Cookies也是一种token,不同的是它没有使用数字签名,浏览器端、服务器端对它的处理与现在使用的基于数字签名的的token也完全不同。

Security Token Service (STS, 安全令牌服务)是一种签发和验证token的网络服务,扮演着客户端和被访问资源之间的中介者的角色。STS是中心化的服务,它被双方共同信任,和数字证书的CA(Certificate Authority,数字证书认证机构)类似,其已知网址被认为是可信任的信息发布源。STS 可能实现 REST 协议,也可能支持浏览器跳转协议。下面是一些具体的的STS服务:

使用STS进行认证的流程如下:
sts-workflow
其基本步骤为:

  1. Client向STS发送认证请求,描述所申请的token信息。
  2. STS通过Client发送的密码或者数字签名等信息进行验证,验证通过后返回相应的token。
  3. Client向Resource Provider发出资源访问请求,并同时在请求中带上所获取的token,一般将其附在http header中。
  4. Resource Provider直接或者间接通过STS来验证所收到的token。
  5. Token验证通过后,Resource Provider执行所请求的操作并返回结果给 Client。

在工程实践中,根据实际的需求和情况,以上步骤可能会有各种变化或者调整,例如:

  1. 在 STS 颁发 token 的时候,授权过程可能会有用户的参与,比如常见的OAuth 2.0 协议中会出现Consent页面,用户可以勾选需要授权的具体信息。
  2. 出于性能考虑,验证token的过程往往不需要和STS直接交互。Resource Provider可以缓存STS的公钥,直接对token进行验证。
  3. Resource Provider可以选择信任多个STS,并且可以由Client根据当前业务逻辑来选择,比如很多应用同时支持微信登录、微博登录等。
  4. 在微服务系统中,STS可能并不是由第三方提供,而是自己内部实现。

STS 公钥发布

Resource Provider在验证客户端发送的token时,可以直接通过公钥来验证。这样可以避免每次验证token时访问STS,从而影响稳定性和性能。这个公钥可以从本地文件、分布式缓存等地方读取。但这种做法总有一定的运维负担,而且STS的公钥也有可能更新。由于公钥本来就是可以对外公开的,所以业界常用的做法是STS的提供者在某一个已知(well-known)的网络地址上发布公钥数据来供需要校验token的程序下载。下面是几个STS的公钥地址的例子:

从网址可以看出这些 URL 是由微软和谷歌所提供的,在HTTPS的前提下是可以被信任的。这里再次强调 well-known 的重要性,也就是说 token 的校验程序本身独立而静态地知道所信任的 STS 的公钥地址,可以在自己的代码或者配置文件中hard code这些URL。上面的几个公钥地址例子是面向公共网络和第三方服务设计的,所以任何可以连接到互联网的程序都可以通过这些URL获取公钥。

另外以上的这些 URL实际上是各个公共STS实现的 OpenID Connect 协议的一部分(基于OAuth 2.0),也可以在其对应的Discovery Document中获得,比如:

JWT

JSON Web Token,简称JWT,是目前应用得最广泛的基于数字签名的token格式,其具体的规格定义在 RFC 7519文档中。 JWT由一个头部,消息主体和一个数字签名连接在一起组成,在实际传输时候分别用 base64 对各部分编码。在由STS签发的JTW中,数字签名是由STS使用私钥对消息主体进行哈希运算而来的。
sts-workflow

推荐的 JWT 工具是 https://jwt.io,上面有在线解码和签名验证工具,并且收集了各种编程语言的 JWT 库。
如果JWT是由微软的AAD签发的,建议使用https://jwt.ms

如何构建STS

Cloud-based

微软的AAD(Azure Active Directory)是使用的最为广泛的STS服务。AAD提供的服务还包括Single sign-on、MFA、用户/组管理以及与本地Active Directory同步等功能。AAD还支持OAuth、OpenID等标准协议。

AAD是一个基于云的多租户(multi-tenant)的身份认证系统。如果你已经有了Azure账号,那么你已经有AAD了。如果还没有Azure账号或者想新建一个,可以使用下面的链接来创建。这个过程是免费的,也不需要国际信用卡,你只需要有Microsoft Account就可以。

https://portal.azure.com/#create/Microsoft.AzureActiveDirectory
create AAD tenant

此外,如果你已经在使用如下的微软云服务,那么你也会自动获得一个AAD:

  • Microsoft Office 365
  • Microsoft Dynamics CRM Online
  • Microsoft Intune

AAD创建好了之后可以在Azure Portal中进行管理:
https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade
也可以去专门的Azure Active Directory admin center去管理AAD:
https://aad.portal.azure.com


AAD的一些Endpoint URL如下:

URL中的tenant可以是 AAD tenant的名称(微软自己的tenant为microsoft.onmicrosoft.com,也可以使用自己绑定的域名),或者tenant的ID(微软自己的tenant ID为72f988bf-86f1-41af-91ab-2d7cd011db47)。此外开发者还可以使用sts.windows.net这个域名来访问AAD提供的服务,但推荐使用login.microsoftonline.com。
AAD是世界上应用最广泛的企业级身份认证系统,开发者可以借助Microsoft identity platform来更好的使用AAD。

自己搭建

IdentityServer是一款开源的OpenID Connect和OAuth 2.0框架。最新的IdentityServer4是使用ASP.NET Core 2开发的,开发者可以基于IdentityServer4来搭建自己的STS服务。

IdentityServer官方有一个Demo site其源代码也是开源的。开发者可以参考它以便更快的搭建自己的STS服务。
使用Windows Identity Foundation也可以创建自己的STS服务,但相比IdentityServer要复杂和麻烦很多。

Reference