证明与计算(6): 身份认证与授权

目录:

** 0x00 引子
** 0x01 用户名和密码
** 0x02 密码管理器的基本原理
** 0x03 多因素认证
** 0x04 双因素认证(two-factor-auth)的基本原理。
** 0x05 [OpenID] vs [OAuth]
** 0x06 [IDToken] vs [JWT, JWS, JWE]

0x00 引子

每天,你使用用户名和密码登录网站。
每天,你使用手机验证码重置密码。
每天,你使用微信扫码登录其他软件。
每天,你使用微信授权第三方小程序访问你的个人信息。
每天,你可能会对如何记住众多密码感到棘手。

作为开发者,你应该对安全地做“身份认证”和“授权”,有十分清晰的认识。

0x01 用户名和密码

那么,如何安全地保存密码?

  1. 客户端,为每个用户,使用密码学安全的伪随机数生成器(Cryptographically secure pseudorandom number generator)生成随机密码password。通过https等安全通道传输username、password到服务端。
  2. 服务端,为每个用户,生成一个独立的随机盐salt.
  3. 使用标准的加密哈希函数计算密码和盐的的哈希: hashValue=hash(password+salt)
  4. 加密哈希函数可以是:Argon2, bcrypt, scrypt, or PBKDF2 中的一种,不要自己发明哈希函数。
  5. 在数据库中保存匹配的<username, hashValue, salt>

以及,如何安全地校验密码?

  1. 客户端,通过https、ssh等安全通道传输username、passowrd到服务端。
  2. 服务端,从数据库中取出<username, hashValue, salt>数据
  3. 使用和保存时一样的hash函数计算 hashValue‘=hash(password+salt)
  4. 将计算结果hashValue‘和保存的hashValue比较,如果一致则校验通过,否则失败。

[1] 密码学安全伪随机数生成器
[2] Cryptographically secure pseudo-random number generator, CSPRNG
[3]
[4] Salt
[5] Origin of the term "salt" in computer security
[1] hashing-security

0x02 密码管理器的基本原理

密码很多怎么办?用户可以选择使用密码管理器来管理自己的密码。那么,密码管理器的基本原理是怎样的呢?

  1. 使用一个包含字母,数字,特殊字符的8位以上的强主密码(masterpassword)。
  2. 使用主密码+用户名等只有你自己知道的信息,通过一个密码哈希函数去生成一个盐(salt)。所谓密码哈希函数就是是满足单向性质(计算哈希容易,反向破解很难,具体来说是NP难度),强碰撞防御的哈希函数。
  3. 有了主密码和盐,然后可以使用PBKDF2,Bcrypt, Scrypt ,Argon2中的一种Key Derived function(KDF)来生成一个密钥 aesKey = kdf(masterpassword,salt),此时有3个重要的数据:masterpassword, salt,aesKey,这3个数据不会上传到云端。
  4. 每当注册一个新站点需要一个新密码时,使用密码管理器生成每个站点用的随机字符串强密码,一般是 xxxx-xxxx-xxxx-xxxx格式,形成<website,xxxx-xxxx-xxxx-xxxx>数据。这个生成过程必须要用密码安全的随机数生成器。
  5. 密码管理器使用步骤3生成的aesKey,采用AES对称加密算法去加密第4步生成的站点密码数据,上传加密后的密码数据到云端。
  6. 在其他硬件上登录密码管理器客户端后(最好登录客户端的密码与主密码应该不一样),客户端同步加密后的数据。
  7. 需要密码时输入主密码(masterpassword),使用主密码+用户名+同样的单向哈希函数生成盐(salt),通过KDF实时生成aeskey,再用aeskey去解密加密后的数据的到<website,xxxx-xxxx-xxxx-xxxx>。注意,这里用到的主密码是你自己记住的,盐(salt)和aesKey是实时在本地生成的,这也是密码管理器可安全使用的一个关键因素,别人即使获得了加密后的数据,他没有你的主密码,用户名等私人信息,他是很难破解的。这也是为什么主密码本身应该足够强,需要包含字母,数字,特殊字符以及8位以上的原因。
  8. 如果不同步到云端,那么切换到其他设备时,你要自己手工拷贝加密后的密码数据到新设备的密码管理器里。
  9. 同步到云端的密码管理器有LastPass,不同步到云端的密码管理器有1Password。如果你用的是Mac系统,使用safari浏览器内置的密钥管理器记住密码,并使用icloud同步到iphone,也是属于会同步到云端的密码管理器,只是它只支持苹果自己的系统。

[1] Password Manager
[2] 1password
[3] lastpass

0x03 多因素认证

我们知道密码在认证身份中的重要作用,但实际上密码只是验证身份的一个因素。身份认证实际上分为:

  1. 只验证密码的单因子认证,验证的是一个人“只有自己知道”的知识。
  2. 除了验证密码,还验证只有你个人持有的东西,例如手机,u盾,微信扫码认证,Google设备验证器等。验证的是一个人“只有你拥有的”设备。这就形成了双因子认证
  3. 进一步,还可以通过生物特征验证你是谁。例如,指纹,人脸识别等,银行客户端和支付宝等就会有这种认证。那么就形成了三因子认证

0x04 双因素认证(two-factor-auth)的基本原理。

双因素认证的核心目的是确认只有用户拥有的设备,例如忘记密码后通过手机验证码可以快速重置密码,密码+手机就构成了一个双因素认证。而像Google Authenticator则是一个双因素认证的App。双因素认证的基本过程是怎样的呢?

  1. 个人手机上安装一个生成双因素认证码的App,例如:Google Authenticator App。
  2. 登陆需要支持双因素认证的网站,该网站生成一个内含共享密钥(shared_secret)的二维码,这个步骤叫做初始安装,每个要使用双因素认证的网站都需要和用户的Google Authenticator做这个安装步骤。
  3. 手机上的Google Authenticator通过扫描的方式,安全地将网站共享给个人的密钥导入App。
  4. 手机上的Google Authenticator通过HMAC(shared_secret, 当前Unix时间/30秒取整)生成一个20字节的值。
  5. 对这20字节的值再做处理,最后得到一个6位数字整数,这个整数是一个一次性密码。
  6. 在网站上输入这6位数字整数的一次性密码。
  7. 网站上使用和Google Authenticator共享的密钥shared_secret,同样计算HMAC(shared_secret, 当前Unix时间/30秒取整),并处理后得到同样的6位一次性密码。
  8. 网站通过校验用户输入的一次性密码和自己生成的一次性密码,确认用户确实拥有这台手机。
  9. 共享密码只在第一次的时候需要通过扫码的方式从网站共享给了个人手机上的验证器。
  10. 这里生成一次性密码的算法叫做Time-Based One-Time Password Algorithm,也就是TOTP。

[1] 2-Step Verification with Google Authenticator
[2] Github: Google Authenticator
[3] How Google Authenticator Works
[4] HOTP: An HMAC-Based One-Time Password Algorithm
[5] TOTP: Time-Based One-Time Password Algorithm

0x05 [OpenID] vs [OAuth]

每个站点都需要一个用户名密码,于是你会有一堆的用户名密码需要保管,因此从安全的角度来说你需要一个可靠的密码管理器。

但是!但是另外一种做法是你可以减少注册的用户名和密码,通过减少用户名密码的数量来解决用户的痛点,更重要的是在安全的基础上带来更强的能力。

如果我们只要注册一个公共的账号(用户名/密码),让其他网站都能做到下面两个目的:

  1. 身份验证(Identity, authenticate):不需要知道用户的密码就可以验证用户的身份,从而提供登录服务。
  2. 授权(authorization):网站A的用户能够在不提供密码给网站B的情况下,安全地授权给网站B在限定时间内去访问用户在网站A上指定资源的权限。

可以看到authenticate和authorization,很接近的两个单词,代表了两件不同的事:A授权给B使用某个资源,但是网站A并不能验证当前访问资源的是A还是B。

OpenID和OAuth正是解决这个问题的两个标准协议,但是他们各自解决的问题不同,我们先梳理下它们之间的关系。

  1. OAuth解决的是如何授权的问题。OAuth经历了OAuth 1.0和 OAuth2.0。
  2. OpenID解决的是如何验证身份的问题。OpenID经历了OpenID1.0,OpenID2.0,最新的标准是OpenID Connect(OIDC)。 OpenID 1.0和OpenID 2.0是和OAuth独立的体系,但是OpenID Connect是以OAuth 2.0为基础的协议,可以看作是OAuth的一个应用。

因此,总的来说只要理解了OAuth 2.0的基本原理,就可以理解OpenID Connect。那么就理解了“授权”和“身份验证”两件事最新的是怎么做的即可。

现在,理解下OAuth 2.0的基本做法,先定义几个关键角色:

  1. 资源持有者(Resource Owner)
  2. 资源服务器(Resource Server)
  3. 终端用户(Client)
  4. 授权服务器(Authorization Server)

我们来看Client是如何获得Resource Owner授权,从而在有效期内使用Resource Server上特定资源的:

  1. Alice在网站R上有一堆资源。
  2. Bob想要在网站S上使用Alice在网站R上的资源。
  3. Bob向Alice请求获得授权。
  4. Alice使用用户名密码登陆网站R。
  5. 网站R返回给Alice一个授权码(Authentication Code)。
  6. Alice向Bob返回授权码。
  7. Bob使用授权码向网站R请求获得授权令牌(Access Token)。
  8. 网站R返回给Bob返回授权令牌。
  9. Bob发送授权令牌给网站S。
  10. 网站S使用Access Token在有效期内访问Alice在R上的特定资源。

基本过程就是这样的,Bob在这里未必是指另一个人,而可能是一台机器,一个浏览器,一个客户端。OAuth 2.0上解决不同的安全需求也会在协议步骤上有不同的变种。核心原理就是:

  1. Bob必须通过只有Alice持有的用户名和密码授权获得一个AccessToken。
  2. 这个AccessToken有过期时间和能访问的特定资源限制。

而前面说了OAuth 2.0只规定了如何授权。通过授权可以做的事情很多,包括在授权的基础上实现身份认证。如果每个OAuth 2.0的使用者可以自己在OAuth 2.0的基础上做这个事情。另一方面,OpenID 1.0和OpenID 2.0虽然目的是身份验证,但是协议本身的过程和OAuth多少有些冗余重复。OpenID Connect就是直接对使用OAuth 2.0做身份认证提供了标准。

OpenID Connect的基本过程如下:

  1. 终端用户(End User, EU)需要在网站S上登录,网站S叫做依赖方(Relying Party,RP)。
  2. 网站S向终端用户的开放身份认证提供商(OpenID Provider, OP)请求身份认证。
  3. 开放身份认证提供商对终端用户进行身份认证,例如要求终端用户输入OpneID的用户名密码等。
  4. 开放身份认证提供商返回身份认证令牌(IDToken)给网站S,以及一个授权令牌(AccessToken)。
  5. 网站S使用AccessToken向开放身份认证提供商发送一个请求,以获得终端用户的UserInfo。
  6. 这样网站S就完成了对终端用户的身份认证,获得了其<IDToken, UserInfo>信息。

小结:

  1. OAuth2.0完成授权,OpenID Connect基于OAuth2.0完成身份认证。
  2. 关键字:AccessToken,IDToken。

[1] wiki:OpenID
[2] OAuth
[3] OAuth 2.0
[4] The OAuth 2.0 Authorization Framework
[5] The OAuth 2.0 Authorization Framework: Bearer Token Usage
[6] OpenID Connect

0x06 [IDToken] vs [JWT, JWS, JWE]

在OpenConnect里面,IDToken是身份认证传递的最重要的数据。那么一个IDToken的结构是怎样的呢?

在OpenConnect里面,IDToken采用了JSON Web Token (JWT)格式,这个格式大概如下的JSON格式:

{
 "iss": "http://server.example.com",
 "sub": "248289761001",
 "aud": "s6BhdRkqt3",
 "nonce": "n-0S6_WzA2Mj",
 "exp": 1311281970,
 "iat": 1311280970,
 "name": "Jane Doe",
 "given_name": "Jane",
 "family_name": "Doe",
 "gender": "female",
 "birthdate": "0000-10-31",
 "email": "[email protected]",
 "picture": "http://example.com/janedoe/me.jpg"
}

有了JWT,从安全上来说,对JWT有两种操作需求:

  1. 签名
  2. 加密

首先,签名的结构包含3部分:Head.Payload.Signature

  1. Head: {"kid":"...", "alg":"..."},alg表示签名使用的加密算法,还有很多其他可选字段
  2. Payload: 就是上面的JWT的
  3. Signature: 使用加密算法对Payload签名

然后把这三分部通过下面的公式用点号拼接在一起:
BASE64URL(UTF8(Head)).BASE64URL(Payload)).BASE64URL(Signature).

所以解码的时候,只要先用Base64解码,再对签名做校验即可。

其次,加密的结构包含5部分: Head.Key.Vector.Payload.Tag,基本做法如下的两步加密:

  1. 使用对称加密算法Key和初始化向量Vector,对Payload加密
  2. 使用非对称加密算法对Key加密。

所以这5部分实际上分别是:

  1. Head: {"alg":"...", "enc":"..."}。enc是对称加密算法,alg是非对称加密算法。
  2. Encrypted Key,使用非对称加密算法alg对Key加密
  3. Initialization Vector,对称加密算法的初始化向量
  4. CipherText,使用Key+Initialization Vector对Payload加密
  5. Authentication Tag,校验码

然后把这五部分通过下面的公式用点号拼接在一起:
BASE64URL(UTF8(Head)).BASE64URL(EncryptedKey).BASE64URL(InitializaionVector).BASE64URL(CipherText).BASE64URL(AuthenticationTag)

最后,如果你想同时对JWT签名+加密,可以这么做:

  1. 使用JWS对JWT签名
  2. 把步骤1的签名数据作为JWE的Payload

小结一下,IDToken,JWT、JWS、JWE的关系是:

  1. JWT是IDToken的一种。
  2. JWT可以使用JWS签名。
  3. JWT可以使用JWE加密。
  4. JWT可以同时使用JWS+JWE签名和加密。

最后说一句,身份验证和授权机制,在封闭的内部系统里都可以自己做一套,标准化的目的是提供不同服务商之间的互通性,减少巴别塔。理解基本原理可以自由构建,但是理解标准则是另一个目标。

[1] Understanding IDToken
[2] jwt.io
[3] rfc-7519: JSON Web Token (JWT)
[4] rfc-7515: JSON Web Signature (JWS)
[5] rfc-7516: JSON Web Encryption (JWE)

--end--

原文地址:https://www.cnblogs.com/math/p/id-auth.html

时间: 2024-07-28 22:03:56

证明与计算(6): 身份认证与授权的相关文章

Kubernetes之(十五)身份认证,授权,准入控制

目录 Kubernetes之(十五)身份认证,授权,准入控制 ServiceAccount 创建serviceaccount 自定义serviceaccount 自建证书和账号进行访问apiserver RBAC简介 Kubernetes RBAC演示 RBAC的三种授权访问 Kubernetes之(十五)身份认证,授权,准入控制 API Server作为Kubernetes网关,是访问和管理资源对象的唯一入口,其各种集群组件访问资源都需要经过网关才能进行正常访问和管理.每一次的访问请求都需要进

Kubernetes身份认证和授权操作全攻略:上手操作Kubernetes授权

这是本系列文章中的第三篇,前两篇文章分别介绍了Kubernetes访问控制以及身份认证.本文将通过上手实践的方式,带你理解Kubernetes授权这一概念. 在文章正式开始之前,我们先快速回顾一下我们实操过程中的环境和场景.我们正在处理生产环境中的集群,其中每个部分都与命名空间相关联.现在,组里新来了一位同事叫Bob,我们在上篇教程中帮助Bob以engineering命名空间管理员的身份加入集群.并且他已经获得私钥以及签名证书来访问集群. 如果你还没有完成上述操作,请查看上篇教程,运行其中的命令

angular 身份认证问题

最普遍的身份认证方式就是用用户名(或 email)和密码做登陆操作.这就意味要实现一个登陆的表单,以便用户能够用他们个人信息登陆.这个表单看起来是这样的: <form name="loginForm" ng-controller="LoginController" ng-submit="login(credentials)" novalidate> <label for="username">Usern

Asp.net Core认证和授权:Cookie认证

这里我只是记录下自己在学习中的点滴和一些不懂的地方 Cookie一般是用户网站授权,当用户访问需要授权(authorization)的页面,程序会判断是否已经授权,并认证 添加认证代码:引入命名空间:Microsoft.AspNetCore.Authentication.Cookies; 添加服务 publicvoidConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion

超级狗是集软件授权、课件保护和身份认证于一身的加密狗。

超级狗是加密狗家族中最新一代软件保护和授权产品.它提供了强大的软件.课件防盗版功能以及灵活的软件授权功能,保护软件开发商的知识产权与核心技术,确保开发商的市场收入. 超级狗将软件保护与授权技术化繁为简.通过易于理解.易于上手的外壳保护工具.许可设计工具,以及在线授权工具,软件开发商可以轻松地实现高强度的软件保护和多种授权模式. 在保持SafeNet一贯高品质.高稳定性.高安全性的基础之上,超级狗还提供了基于时间.功能控制的许可模式,同时拥有更友好.直观的用户界面和更简单的操作流程. 超级狗可以帮

asp.net core 使用identityServer4的密码模式来进行身份认证(2) 认证授权原理

原文:asp.net core 使用identityServer4的密码模式来进行身份认证(2) 认证授权原理 前言:本文将会结合asp.net core 认证源码来分析起认证的原理与流程.asp.net core版本2.2 对于大部分使用asp.net core开发的人来说. 下面这几行代码应该很熟悉了. services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { o

基于oauth授权框架其中获取令牌需要发送Http身份认证的请求

1.首先我们基于curl的请求参数示例: curl http://localhost:8080/oauth/token -X POST -u client:fucksecurity -d "grant_type=refresh_token&refresh_token=1a1fb46e-8ab4-4a3b-84c4-e70892eaa570"其中的 -u 表示的是身份认证的用户名和密码.后来尝试过Jquery的$.ajax的username和password去传这个两个对象,发现

.NET Web的身份认证

百度一下”asp.net身份认证“,你会得到很多相关的资料,这些资料通常上来就会介绍诸如”Form认证“”Windows认证“等内容,而没有给出一个完整的流程.初学者对此往往一头雾水,我也曾经被坑过很多回,于是写下此文,算是复习. 现代的Windows Server系统都是基于严格的用户机制的,当你想操作服务器时肯定需要账号密码验证的.当我们把开发好的Web应用程序部署在服务器后,用户通过浏览器访问该站点,实际上就是该用户通过HTTP操作这台服务器的过程,本质上也是用户操作服务器(至少是读)的过

哈希表 之 接入与身份认证技术概述

1 概述 随着信息化的高速发展,对国家.组织.公司或个人来说至关重要的信息越来越多的通过网络来进行存储.传输和处理,为获取这些关键信息的各种网络犯罪也对应急剧上升. 当前,网络安全在某种意义上已经成为一个事关国家安全.社会经济稳定的重大问题.得到越来越多的重视. 在网络安全中.身份认证技术作为第一道,甚至是最重要的一道防线.有着重要地位,可靠的身份认证技术能够确保信息仅仅被正确的"人"所訪问.身份认证技术提供了关于某个人或某个事物身份的保证.这意味着当某人(或某事)声称具有一个特别的身