vlambda博客
学习文章列表

Oauth2.0:Claims进行数据级别的访问控制

Claims声明进行数据级别的访问控制

如果说使用OAuth范围执行粗粒度授权,分离不同应用程序的访问权限,能够达到功能级的授权,那么使用声明,可以进行细粒度的授权。

举个例子来说,我们可以使用Scope控制用户是否可以列出发票的API,很明显,粗粒度范围告诉我们是否可以执行该API,但是不能告知API哪些发票可以列出。这些与用户紧密相关的数据的权限,可以使用OAuth令牌的声明进行数据级别的访问控制。

了解什么是声明

要了解什么是声明之前,我们需要从属性开始,属性是的用户的一组所有物。我们通常将属性分为两类:主体属性和上下文属性。

主体属性

无论用户如何登录,主体属性对于用户的正确反映。

这些属性是相对静态的因素,它们保持不变,而不管用户的位置、设备等动态的信息。例如用户名,名称,年龄,鞋子大小等。如果主体是在一个企业当中,还会关联一些职位的属性。通常这些属性会在用户访问之前就被授予。例如,如果新员工加入公司的财务团队,企业可以通过在新员工第一天在企业标识系统中分配财务的属性来授权该员工访问其财务应用程序。同样的,对于面向消费者的应用程序,当用户购买服务的特定订阅级别时,可以向其分配与访问相关的用户配置文件属性。

登录期间的身份验证方法和业务流程,您可能会收到不同的主体属性。例如,如果用户使用Google登录,则Google将提供某些属性;当使用Active Directory登录时,可能会出现其他属性。由验证服务决定以规范化的形式提供这些属性,并确保相关的主体属性会被提供。

上下文属性

另一方面,告诉我们一些有关在什么情况下主体属性被建立。

这些因素可以包括用户的地理位置、用户是否在公司防火墙内部或外部、或者用户的设备是否被认证为遵守某些安全配置标准访问的时间验证使用的身份验证机制的强度因素等等。这些因素是在身份验证时动态获取的,而不是用户身份配置文件的一部分。如果这些因素被身份提供者获取,就可以安全令牌中的声明的形式提供给应用程序。

声明 Claims

了解了属性之后,我们就需要看看声明。只有当我们信任发布属性的一方,或者换句话说:如果我们信任声称属性一方,属性才有意义。

我们先用自然语言来阐述下,什么是声明:

一项声明的形式如下:

韩梅梅说,李磊有一匹马;

”李磊“——是主题 Subject

“拥有一匹马”——是一种主张/属性 Attribute

韩梅梅——是主张方Issuer

如果我们相信韩梅梅,那么我们就可以相信关于马的说法。

所以,关于声明更正式的定义是:

Claim = Subject+Attribute+Issuer

OAuth中的声明

有了以上定义,我们可以轻松地应用到OAuth/OIDC中,在OIDC中声明是一级公民。我们最碰到到Claims声明的地方就是在ID令牌中,通常以Json Web令牌(JWT)的形式呈现,但它们可以通过格式的令牌呈现并用在任何地方:

{

sub:[email protected]

name:yy

iat:1546300800

exp:1893456000

iss:https://oneauth.cn

subscriber_id: ABC_123

phone_number:+86 133 1234 1234

}

这个JWT包含以下声明:“name”, “iat”, “exp”, “subscriber_id”, “phone_number”.

它还有一个主体“sub”和一个签发者“iss”,JWT通常由一个私钥来进行签名,以证明该签发者与其对外公示的身份与JWT签发者的身份内容相匹配。此令牌的接收者通过“iss”字段来验证该令牌的发行方是否是其信任的主机,并使用该主机提供的公钥验证该令牌是否确实由其方发出。一旦完成以上验证,我们就可以依赖令牌中的声明并根据信息采取行动。

OIDC描述了ID令牌的标准声明,但是声明基础设施并不局限于这些令牌。访问令牌可以使用相同的结构,即使用JWT以外的其他格式。

在设计需要更细粒度授权的系统时,这就让声明的作用变得非常强大。

重新审视Scope

我们知道作用域在为客户机授权访问中的作用,用于功能级别的授权。

但是在引入了声明,基于声明的系统中,作用域Scope有了更为重要的作用,可以扮演着更深层的角色。

换句话说,如果没有声明,作用域只是一个字符串列表,其中包含作用域标记或作用域名称。比如:scope=“invoice_read invoice_write openid email”。通过这种方式,将scope参数用作访问范围,这是一种不错的方式,也就是说,它列出了客户需要访问的API的权限。我们在粗粒度授权中给出了每一个Scope的含义,以决定是否允许客户端查询API。

但是,正如开始所讨论的,即使令牌中存在invoice_read的作用域,我们也不知道应该允许它读取哪个发票(invoice)。

因此,OpenID Connect对此进行了进一步的定义,将作用域定义为一组声明的集合。因此,“email” Scope令牌定义为“email”和“email is verified”声明。声明具有与其关联的值,而作用域标记只是一个名称,这意味着作用域只是一组声明的打包。请求一个作用域的结果是,有能是零个、或者多个请求被发出并出现在令牌中。

这种定义的方式可以推广到任意作用域和声明,当涉及API访问时,这将变得非常有用。


回顾一下我们对于发票服务invoice API的设计,假设我们有以下作用域:

invoice_list

invoice_read

invoice_write

如前上设计,仅基于此信息授权特定请求是不够的。API需要知道哪些发票是可以被允许列出来的,但是在令牌中列出实际的发票id不是一种可行的方式,但是假设我们有一个声明,它是accoun_id,它是与用户财务信息相关联的帐户。我们现在可以将其映射到作用域上,如下所示:

Scope 与之关联的CLaims
invoice_list
account_id, role=customer
invoice_read account_id, role=customer
invoice_write account_id=" * ", role=operator

如果请求了这些作用域中的任何一个,则同时生成的令牌将包含所需的声明以及该用户的关联值。现在API可以很容易地知道请求的操作是否被授权or是个越权的请求。

我们现在可以做出这样一个约定。API知道,如果role=customer,它需要检查声明中的account_id 的值,看看应该为哪个帐户提供发票。如果role=operator,它允许写入。这降低了许多风险。API不再需要依赖于来自不可靠来源的数据,而是可以在执行任务时安全地对帐户和范围信息进行操作。这使得第三方几乎不可能在请求中注入不同的帐户id,而且API也不必查找其有关用户的其他数据。

这个例子对作用域和声明进行了简化说明,但显示了如何使用声明的本质。

描述上下文登录信息

不仅仅是API访问权限控制将受益于令牌中的声明。当使用OpenID Connect时,客户机(应用程序)可能还对了解用户的详细信息感兴趣。在许多情况下,它需要了解用户进行身份验证的上下文的细节。

如前所述,上下文属性将提供此信息,使用OpenID Connect ID令牌,客户机不仅可以确定谁登录,还可以确定何时以及如何登录,这些是与openid作用域隐式关联的标准声明的一部分。

sub:谁登录的

auth_time:登录发生的时间

acr:认证上下文类引用的缩写,它规定了登录的方式。

非常常见的是,应用程序需要知道身份验证是否是最近发生的,或者是否发生在SSO中,也就是说,用户有没有交互。在决定是否应显示敏感数据时,这一点也非常重要。了解用户如何登录也很重要,因为这有助于决定允许用户执行哪些操作。使用强身份验证登录的用户可以允许更改其帐户详细信息,而未使用强身份验证的用户可能只能查看等等。

小结

声明是令牌的内容。它们由颁发者断言,在本例中是OAuth或OpenID Connect服务器。它们提供了一种强大的机制来帮助API和客户机做出合格的授权决策。声明基于OpenID Connect标准,并提供了一种机制来帮助API在请求的授权中更加细粒度。

-End-


关于OneAuth

OneAuth是国内首款基于引擎的现代化的身份安全云,以连接人与科技为使命,集成了主流标准认证协议,基于“一切皆可引擎驱动”的现代软件工程思想,驱动软件工程化架构安全标准建设,满足未来十年数字经济的稳定、安全和高效需求。为政府、金融和各类数字化转型企业,提供面向多场景(员工、合作方、客户)的身份解决方案,保障无边界网络/混合云复杂场景下人和科技的安全连接。

欢迎注册,体验现代身份引擎

www.oneauth.cn