前言
因为HTTP协议是开放的,可以任人调用。所以,如果接口不希望被随意调用,就需要做访问权限的控制,认证是好的用户,才允许调用API。
注:Cookie+Session 认证属于Form认证,并不属于HTTP标准验证。
Form认证:即表单认证,表单认证一般都会配合cookie+sessiond的使用,现在绝大多数的Web站点都是使用此认证方式。用户在登录页中填写用户名和密码,服务端认证通过后会将sessionId返回给浏览器端,浏览器会保存sessionId到浏览器的Cookie中。因为Http是无状态的,所以浏览器使用Cookie来保存sessionId。下次客户端发送的请求中会包含sessionId值,服务端发现sessionId存在并认证过则会提供资源访问。
目前主流的访问权限控制/认证模式有以下几种:
Basic(RFC7617)
- 传输:将凭据作为用户 ID/ 传输密码对,使用 Base64 编码。
- 是基于客户端类型最基本的认证方案
- 服务器只有在可以验证时才会为请求提供服务,申请的保护空间的用户名和密码 请求的资源。
- 特征:response:
Unauthorized
Authorization头中数据 Basic
请求头数据
- WWW-Authorization
- 认证方式 Basic
- realm
- 安全域
- Authorization
- 认证方式 Basic
- base64(username:password)
数据包
HTTP/1.1 401 Unauthorized
Date: Mon, 04 Feb 2014 16:50:53 GMT
WWW-Authenticate: Basic realm="WallyWorld"
//其中“WallyWorld”是服务器分配的用于标识保护空间的字符串。
SCRAM SHA-1的执行涉及四个消息的传输和处理;客户端和服务器各有两个。如上图所示,客户端通过发送 客户端第一消息开始该过程,并且响应于从客户端接收到格式正确的第一消息,服务器向客户端发送 服务器第一消息。客户端处理此消息,如果一切正常,则传输 客户端最终消息。正如预期的那样,服务器会处理此消息。在此任务结束时,服务器应该知道客户端是否成功通过身份验证。如果是,服务器发送 服务器最终消息,否则它会向客户端发送认证失败消息(或者可能不会)。随着 服务器最终消息的接收,客户端也能够对服务器进行身份验证
认证方法
- 客户端发送请求,服务器端接受请求后,判断如果请求的资源需要认证,则返回401状态,并在
response headers
中加入WWW-Authenticate
头部,要求客户端带上认证信息以后再发一次请求 - 客户端收到401返回信息后,重新向服务器发送请求,并在request headers中加入
Authoriaztion
头部,用来说明认证的用户名、密码、算法等信息 - 服务器端从用户那里取得
用户ID
与密码
-
但
用户ID与密码不得包含任何控制字符
-
包含冒号字符的用户ID是无效的
-
许多用户代理会在不检查
-
用户提供的用户 ID 是否包含冒号的情况下生成用户传递字符串; 然后,收件人会将输入的用户名的一部分视为密码的一部分
- 通过
冒号(:)
连接用户ID,来构造用户通行证,字符和密码 - 将用户密码编码为八字节序列
- 通过使用
base64
,使得方式转化为US-ASCLL
字符序列 - 服务器再次收到请求后,判断以上认证信息无误,返回200,并在response headers中加入Authorization-Info头部
缺陷
- 此认证方案的原始定义未能指定用于将用户密码转化为八位字节序列的字符串编码方案
- 大多数实现取决于特定的环境编码,例如:ISO-8859-1,UTF-8
- 出于向后兼容的原因,该规范继续保留未定义的默认编码,只要他与
US-ASCLL
兼容 - 假冒服务器很容易骗过认证,诱导用户输入用户名和密码。
- 即使密码被强加密,第三方仍可通过加密后的用户名和密码进行重放攻击。
为了传输安全,需要配合SSL使用。
代理授权
出现在RFC 7235上,还是属于basic认证
HTTP Proxy-Authorization
请求标头包含用于向代理服务器认证用户代理的凭证,通常在服务器响应407
Proxy Authentication Required
状态和Proxy-Authenticate
标题后。
如:Proxy-Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
实际举例
如下图,就是基本的http认证,浏览器弹出基本的对话框
如果认证失败,则返回如下
当请求成功的时候,返回的数据包如下
HTTP服务器在每次收到请求包后,根据协议取得客户端附加的用户信息(BASE64编码的用户名和密码),解开请求包,对用户名及密码进行验证,如果用 户名及密码正确,则根据客户端请求,返回客户端所需要的数据;否则,返回错误代码或重新要求客户端提供用户名及密码。
实现
Apache
要对Apache服务器上的目录进行密码保护, 你需要一个 .htaccess
和 a .htpasswd
文件.
该 .htaccess
文件格式通常看起来像这样:
AuthType Basic
AuthName "Access to the staging site"
AuthUserFile /path/to/.htpasswd
Require valid-user
该 .htaccess
文件引用一个 .htpasswd
文件,其中每行用冒号(“:”)分隔的用户名和密码. 你不能看到真实的密码因为它们是 encrypted (在这个例子中是使用了 MD5). 你可以命名.htpasswd 文件 为你所喜欢的名字, 但是应该保证这个文件不被其他人访问. (Apache通常配置阻止访问 .ht* 类的文件).
aladdin:$apr1$ZjTqBB3f$IF9gdYAGlMrs2fuINjHsz.
user2:$apr1$O04r.y2H$/vEkesPhVInBByJUkXitA/
Nginx
在nginx配置中,对需要保护的location你需要做如下配置:auth_basic指令提供密码保护域的名称;auth_basic_user_file
指令指定包含用户密文的证书的文件(与apache例子中一致)
在 nginx 中, 你需要指定一个保护区域和该 auth_basic 指令提供的保护区域名字. 然后该 auth_basic_user_file
指令指向一个.htpasswd 包含加密用户凭据的文件, 就像上面的 apache 例子.
location /status {
auth_basic "Access to the staging site";
auth_basic_user_file /etc/apache2/.htpasswd;
}
URL(已废弃)
如下:
https://username:password@www.example.com/
Bearer(RFC6750)
Bearer即Bearer Token
为了验证使用者的身份,需要客户端向服务器端提供一个可靠的验证信息,称为Token,这个token通常由Json数据格式组成,通过hash散列算法生成一个字符串,所以称为Json Web Token(Json表示令牌的原始值是一个Json格式的数据,web表示是在互联网传播的,token表示令牌,简称JWT)
关于JWT,师傅们可以看这篇文章入门
Bearer的关键点有以下:
- OAuth使客户端能通过获取的访问令牌来访问受保护的资源。
- Bearer验证中的凭证称为BEARER_TOKEN,或者是access_token,它的颁发和验证完全由我们自己的应用程序来控制,而不依赖于系统和Web服务器
- 特征:
Authorization :Bear
er
- 适用场景:分布式站点的单点登录(SSO)场景
数据包
GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM
认证方法
- 客户端:从资源服务器请求受保护的资源,并通过提供访问令牌进行身份的验证。
- 资源服务器:验证访问令牌,如果有效,则为请求提供服务
- 当客户端以使用
access_token
参数将访问的令牌添加到请求正文中,必须满足以下条件:- HTTP 请求实体标头包括设置为“application/x-www-form-urlencoded”的“Content-Type”标头字段。
- 协议主体遵守HTML定义的application/x-www-form-urlencoded”内容类型的编码要求。
- 请求实体主体是单部分的。
- 实体正文中编码内容必须完全由
ASCLL
字符组成 - 不得使用GET方法
POST /resource HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
access_token=mF_9.B5f-4.1JqM
- 使用
access_token
参数:其他参数必须以&
符号连接
GET /resource?access_token=mF_9.B5f-4.1JqM&p= HTTP/1.1
Host: server.example.com
缺陷
- 使用保留的查询参数的名称,与URI命名空间背道而驰
- 如果受保护的资源请求不包括身份验证凭证,或不包含允许访问受保护资源的访问令牌,资源服务器必须包含 HTTP “WWW-Authenticate”响应头字段;它也可以包含它以 响应其他条件。
- 必须使用Bearer,该方案必须后跟一个或多个 auth-param 值
- “scope”属性不能出现多次。该 “范围”值是为程序中使用,并不意味着要显示给最终用户。
- 回显的错误信息,容易被攻击者利用
- 攻击者会伪造或者修改现有令牌的内容,导致不正确的权限访问
JWT可以存在伪造攻击,举例如CTFhub 中的题目
防范
- 为了处理令牌重定向,授权服务器必须在令牌中包含预期接受者的身份。
- 授权服务器必须实现TLS,为了防止令牌泄露,必须使用TLS和提供机密性和完整性保护的密码套件来应用机密性保护。
- 不记名令牌不得存储在可以明文发送的 cookie 中
- 加强前后端的检验
Digest(RFC7616)
这次是摘要认证
- Digest 方案基于简单的质询-响应范例
- 一个可选的头域允许服务器指定算法用于创建未加密的摘要或摘要。该文件增加了SHA-256 和 SHA-512/256 算法。
认证方法
- 客户端请求受保护资源
POST http://127.0.0.1:8087/digest/auth HTTP/1.1
Accept: application/json
cache-control: no-cache
Postman-Token: 0d4e957a-f8ab-4b01-850f-4967ff10b8a0
User-Agent: PostmanRuntime/7.6.0
Connection: keep-alive
- 服务器返回 401 状态和 WWW-Authenticate 响应头(由于需要Digest认证,服务器返回了两个重要字段nonce(随机数)和realm)
HTTP/1.1 401
WWW-Authenticate: Digest realm="digest#Realm", qop="auth", nonce="MTU1NTMzMDg2MDA4MDo5MTdiMGI4ZmIwMDc2ZTgzOWU5NzA4YzEyZWEwNzlmMg=="
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
- 客户端接收到401状态表示需要进行认证,根据相关算法生成一个摘要,将摘要放到
Authoriization
的请求头中,重新发送命令给服务器
POST http://127.0.0.1:8087/digest/auth HTTP/1.1
Accept: application/json
User-Agent: PostmanRuntime/7.6.0 Authorization: Digest username="123", realm="digest#Realm", nonce="MTU1NTMzMDg2MDA4MDo5MTdiMGI4ZmIwMDc2ZTgzOWU5NzA4YzEyZWEwNzlmMg==", uri="/digest/auth", algorithm="MD5", qop=auth, nc=00000001, cnonce="eYnywapi", response="0568a40f79a6960114e21f6ef2b60807"
Connection: keep-alive
- 服务器从 Header 中取出 digest 摘要信息,根据其中信息重新计算新的摘要,然后跟客户端传输的摘要进行比较(就是比较 response 的值是否相等);因为服务器拥有与客户端同样的信息,因此服务器可以进行同样的计算,以验证客户端提交的 response 值的正确性。
HTTP/1.1 200
Expires: 0
Content-Type: application/json;charset=UTF-8
Content-Length: 22
** digest auth is success **
WWW-Authenticate响应头字段
realm
:显示给客户端的字符串
nonce
:服务端生成唯一的、不重复的随机值
//RFC2617示例 nonce = BASE64(time-stamp MD5(time-stamp ":" ETag ":" private-key))
//下面是spring-security的实现
long expiryTime = System.currentTimeMillis() + (long)(this.nonceValiditySeconds * 1000);
String signatureValue = DigestAuthUtils.md5Hex(expiryTime + ":" + this.key);
String nonceValue = expiryTime + ":" + signatureValue;
String nonceValueBase64 = new String(Base64.getEncoder().encode(nonceValue.getBytes()));
algorithm
: 默认MD5算法
qop
: auth/auth-int 会影响摘要的算法
stale
:密码随机数nonce过期
Authorization 请求头字段
response
: 客户端根据算法算出的摘要值
username
: 要认证的用户名
realm
: 认证域,可取任意标识值
uri
: 请求的资源位置
qop
: 保护质量
nonce
: 每次随返回的 401 响应生成的任意随机字符串
nc
: 16进制请求认证计数器,第一次 00000001
algorithm
: 默认MD5算法
cnonce
: 客户端密码随机数
Request-Digest 摘要计算过程
- 若算法是:MD5 或者是未指定
则 A1= <username>:<realm>:<passwd>
- 若 qop 未定义或者 auth:
则 A2= <request-method>:<digest-uri-value>
- 若 qop 为 auth
response=MD5(MD5(A1):<nonce>:<nc>:<cnonce>:<qop>:MD5(A2))
- 若 qop 没有定义
response=MD5(MD5(A1):<nonce>:MD5(A2))
摘要计算工具与计算方法
- DigestAuthUtils
- http Digest认证计算方法整理_TYINY的博客-CSDN博客
优点
- 密码并非直接在摘要中使用,而是 HA1 = MD5(username:realm:password)。可解决明文方式在网络上发送密码的问题。
- 服务器随机数 nonce 允许包含时间戳。因此服务器可以检查客户端提交的随机数 nonce,以防止重放攻击
缺点
- 将存储密钥用的SALT通知到客户端本身就是很不安全的行为,如SALT被截获就大大增加了别人破解密码的可能性
- 其次,由于这次做的产品本身属于标准化产品,登陆过程需支持标准DIGEST方式,无法限制其他客户端的行为,如采用此方式,必然在标准化测试与对接时面临问题。
HOBA(RFC7486)
HTTP 源绑定身份验证
- 是一种基于数字签名的HTTP 身份验证方法的设计
- 用于嵌入在 HTML 中的基于 JavaScript 的身份验证
- 是一个需要密码的 HTTP 身份验证方案的替代方案
- 因此避免了与密码相关的所有问题,例如泄漏服务器端密码数据库。
验证过程
- 客户端连接到服务器,并发出请求,然后服务器的响应的响应包括一个
WWW-Authenticate
标头字段 - 如果客户端未注册到
WEB
资源,并且试图强制访问。加入 过程被调用。这将创建一个密钥对并使 CPK服务器已知,以便服务器可以进行帐户需要的创建过程。 - 客户端使用来自
HOBA auth-scheme
参数,来创建和签署HOBA
代签名。 - 客户端创建的
HOBA
结果HOBA-RES
,作为sig
值 - 客户端在其下一个请求中包含
Authorization
头字段,使用HOBA”auth-scheme 并将 HOBA client-result 在名为“result”的 auth-param 中 - 服务器验证
HOBA
客户端结果
CPK准备阶段
客户端确定它是否已经需要进行身份验证的 Web 源的 CPK。如果客户端有CPK,客户端就会使用它;如果客户端没有CPK,它会在预期服务器要求一个 CPK 时生成一个。
签名阶段
在签名阶段,客户端连接到服务器,服务器请求基于 HOBA 的身份验证,客户端通过签名一个 blob 信息进行身份验证,
格式
HOBA-TBS = len ":" nonce
len ":" alg
len ":" origin
len ":" [ realm ]
len ":" kid
len ":" challenge
len = 1*DIGIT
nonce = 1*base64urlchars
alg = 1*2DIGIT
origin = scheme "://" authority ":" port
HOBA-TES是客户端签名过程的输入,本身过程中不会通过网络发送
包含以下内容:
- len:每个字段前面都有对应的长度值。长度与字段值之间用冒号分隔
- nonce:由 UA 选择的随机值,并且必须在包含在 HOBA-TBS 值之前进行 base64url编码。
- alg:指定正在使用的签名算法
- Origin:访问来源
- Realm:如果没有为身份验证指定此领域,则不存在
- Kid:关键标识符,必须是
HOBA
客户端中呈现给服务器的base64
编码值
HOBA-RES = kid "." challenge "." nonce "." sig
sig = 1*base64urlchars
- 必须属性:challenge max-age
- 可选属性:realm
HOBA-js机制
使用JavaScript的网站也可以执行源绑定身份验证,而无需涉及HTTP层。
- 需要属性:
WebCrypto
- 如果没有上述属性,HOBA-js 需要一个元素;HTML5 中的localStorage ,用于持久性的密钥存储
Window.localStorage - Web API 接口参考 | MDN
由于 JavaScript 的同源策略,子域中的脚本无法访问与其父域中的脚本相同的 localStorage。对于更大或更复杂的站点。
解决此问题的一种方法是使用会话 cookie,因为它们可以跨子域使用。也就是说,在 HOBA-js 中,用户可能使用单个知名域登录,然后在用户浏览站点时使用会话 cookie 。
Mutual(RFC 8120)
HTTP双向认证
先说一下优缺点
优点
-
在通信中根本不交换密码信息,避免了任何密码在网络传输中泄露的可能性,离线密码字典攻击无效
-
能够检测通信对方是否为伪造服务器,避免被网络钓鱼。
缺点
-
浏览器尚未原生支持
-
框架尚未内置,只能开发人员自己实现。
过程
- 客户端请求访问受保护的资源(目标URI:
GET localhost/resource
) - 目标URL收到请求后,检查请求头是否包含Authorization字段,如果不包含,则服务器将发起质询,返回401-INIT消息(即参数reason=initial的401 Unauthorized响应),响应头带有WWW-Authenticate字段,指定认证机制为Mutual并提供认证所需参数。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Mutual
realm="example_space_name",
version=1,
algorithm=SHA-256,
validation=http://localhost:8000,
auth-scope=localhost,
reason=initial
参数
Mutual
:表明认证方式为HTTP相互认证。
realm
:保护空间标识名称,告知客户端自动应用账密的范围,是 HTTP 认证框架(RFC 7235)定义的参数。
version
:表明服务器采用的相互认证协议的版本,用于避免未来版本不兼容的问题,目前只有一个版本,其值固定为1。
algorithm
:指定采用哪种算法计算kc1、ks1、vkc、vks,协议目前支持4种算法:iso-kam3-dl-2048-sha256、iso-kam3-dl-4096-sha512、iso-kam3-ec-p256-sha256、iso-kam3-ec-p521-sha512,算法详情定义在RFC 8121。
validation
:表明与服务器绑定的底层协议验证机制,客户端可以利用此机制来初步检查通信对方,以防止恶意服务器通过转发客户端凭据而向真实服务器冒充用户。当服务器底层是HTTP时,只能采用 host 验证机制,即参数值的格式为<scheme>://<host>:<port>,表明通过判断这三部分是否与真实服务器一致来检查通信对方。当服务器底层是HTTPS时,可以选择 tls-server-end-point 验证机制,即参数值为服务器TLS公钥证书散列值的八位字符串;或者选择 tls-unique 验证机制,即参数值为通道绑定材料。
auth-scope
:告知客户端自动应用会话秘钥的跨域范围。Single-server type:参数值的格式为<scheme>://<host>:<port>,例如:http://localhost:8000,表明scheme、host、port三个部分都相同时才自动应用会话秘钥,即不能跨域应用。Single-host type(缺省默认),参数值的格式为<host>,例如:localhost,表明只要host部分相同就可以跨域应用会话秘钥。Wildcard-domain type,参数值的格式为 *.example.com,表明只要一级域名相同就可以跨域应用会话秘钥。
reason:描述返回401的原因,initial表示请求中头没有包含Authorization字段。
- 客户端可以利用参数
validation
提供的方法来初步检查通信对方- 如果检查不通过,说明通信对方是恶意服务器,则停止通信,并提示用户。这样一来,恶意服务器将无法拿到客户端凭据,从而无法能向真实服务器冒充用户。
- 如果检查通过,则要求用户输入账密,然后发送一条密钥交换消息(req-KEX-C1)来启动身份验证。即在请求头Authorization字段中通过Mutual关键词传递user、kc1(客户端的密钥交换值)等参数,重新请求目标URL:
GET /resource HTTP/1.1
Host: localhost
Authorization: Mutual
realm="example_space_name",
version=1,
algorithm=SHA-256,
validation=host,
auth-scope=localhost,
user="jane",
kc1="4e2e272a28d1802ca10daf4496794697cf"
- 服务器收到req-KEX-C1消息,在其用户数据库中查找用户在realm="example_space_name"这一保护空间设置的账密,用于计算服务器的密钥交换值(ks1)。然后,服务器创建一个会话标识符(sid),用于标识紧随其后的消息集。最后,返回401-KEX-S1消息,即返回401 Unauthorized,在响应头WWW-Authenticate字段中通过Mutual关键词传递sid、ks1等参数。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Mutual
realm="example_space_name",
version=1,
algorithm=SHA-256,
validation=host,
auth-scope=localhost,
reason=initial
sid="4563806698",
ks1="daf4496794697cf8db5856cb6c1",
nc-max=400,
nc-window=128,
time=60
- 客户端、服务器各自使用密钥交换消息中的交换值计算会话秘钥。只有当双方使用相同的用户密码进行计算时,会话秘钥值才会相同。以后双方在每个请求\响应中都携带此会话秘钥,用于代替账密在网络中传递。
- 客户端发送req-VFY-C请求,即在请求头
Authorization
字段中通过Mutual
关键词传递sid、vkc(客户端计算的会话秘钥值)等参数,重新请求目标URI。
GET /resource HTTP/1.1
Host: localhost
Authorization: Mutual
realm="example_space_name",
version=1,
algorithm=SHA-256,
validation=host,
auth-scope=localhost,
user="jane",
vkc="wE4q74E6zIJEtWaHKaf5wv/H5Q"
- 服务器收到req-VFY-C请求,比较vkc是否与自己计算的会话秘钥值(vks)相同。
- 如果相同,表明对客户端身份和用户身份认证通过,则返回200-VFY-S消息,即返回保护资源作为响应,并在响应头的Authentication-Info字段中通过Mutual关键词传递vks等参数。
HTTP/1.1 200 OK
Authentication-Info: Mutual
version=1,
sid="4563806698",
vks1="wE4q74E6zIJEtWaHKaf5wv/H5Q"
# response body
- 如果不同,表明用户可能输错了密码,或客户端可能是冒牌的,或用户可能是冒牌的,则服务器返回401-INIT消息,与步骤2中的响应基本相同,区别是参数
reason=auth-failed
:表示身份验证失败。
- 客户端收到200-VFY-S消息,比较服务器返回的vks是否与自己的vkc相同。
- 如果相同,表明对服务器身份认证通过,则可以使用其返回的保护资源。
- 如果不同,表明服务器是冒牌的,或面临中间人攻击,则不使用其返回的响应,并提示用户。
Negotiate(RFC 4559)
这个找了半天,真离谱
最后查到这个东西应该是windows下的认证 NTLM和kerberos,那应该是HttpClient+NTLM认证
数据包特征
WWW-Authenticate: NTLM realm="SIP Communications Service", targetname="server.domain.com", version=4
NTLM认证
NTLM是NT LAN Manager的缩写,NTLM是基于挑战/应答的身份验证协议,是 Windows NT 早期版本中的标准安全协议。
基本流程
- 客户端在本地加密当前用户的密码成为密码散列
- 客户端向服务器明文发送账号
- 服务器端产生一个16位的随机数字发送给客户端,作为一个challenge
- 客户端用加密后的密码散列来加密challenge,然后返回给服务器,作为response
- 服务器端将用户名、challenge、response发送给域控制器
- 域控制器用这个用户名在SAM密码管理库中找到这个用户的密码散列,然后使用这个密码散列来加密chellenge
- 域控制器比较两次加密的challenge,如果一样那么认证成功,反之认证失败
Net-NTLMv1
Net-NTLMv1协议的基本流程如下:
- 客户端向服务器发送一个请求
- 服务器接收到请求后,生成一个8位的Challenge,发送回客户端
- 客户端接收到Challenge后,使用登录用户的密码hash对Challenge加密,作为response发送给服务器
- 服务器校验response
Net-NTLMv1 response的计算方法为
- 将用户的NTLM hash补零至21字节分成三组7字节数据
- 三组数据作为3DES加密算法的三组密钥,加密Server发来的Challenge
这种方式相对脆弱,可以基于抓包工具和彩虹表爆破工具进行破解。
Net-NTLMv2
自Windows Vista起,微软默认使用Net-NTLMv2协议,其基本流程如下:
- 客户端向服务器发送一个请求
- 服务器接收到请求后,生成一个16位的Challenge,发送回客户端
- 客户端接收到Challenge后,使用登录用户的密码hash对Challenge加密,作为response发送给服务器
- 服务器校验response
Hash
LM Hash
LM Hash(LAN Manager Hash) 是windows最早用的加密算法,由IBM设计。LM Hash 使用硬编码秘钥的DES,且存在缺陷。早期的Windows系统如XP、Server 2003等使用LM Hash,而后的系统默认禁用了LM Hash并使用NTLM Hash。
LM Hash的计算方式为:
- 转换用户的密码为大写,14字节截断
- 不足14字节则需要在其后添加0×00补足
- 将14字节分为两段7字节的密码
- 以
KGS!@#$%
作为秘钥对这两组数据进行DES加密,得到16字节的哈希 - 拼接后得到最后的LM Hash。
作为早期的算法,LM Hash存在着诸多问题:
- 密码长度不会超过14字符,且不区分大小写
- 如果密码长度小于7位,后一组哈希的值确定,可以通过结尾为
aad3b435b51404ee
来判断密码长度不超过7位 - 分组加密极大程度降低了密码的复杂度
- DES算法强度低
NTLM Hash
为了解决LM Hash的安全问题,微软于1993年在Windows NT 3.1中引入了NTLM协议。
Windows 2000 / XP / 2003 在密码超过14位前使用LM Hash,在密码超过14位后使用NTLM Hash。而之后从Vista开始的版本都使用NTLM Hash。
NTLM Hash的计算方法为:
- 将密码转换为16进制,进行Unicode编码
- 基于MD4计算哈希值
攻击
Pass The Hash
Pass The Hash (PtH) 是攻击者捕获帐号登录凭证后,复用凭证Hash进行攻击的方式。
微软在2012年12月发布了针对Pass The Hash攻击的防御指导,文章中提到了一些防御方法,并说明了为什么不针对Pass The Hash提供更新补丁。
Pass The Key
在禁用NTLM的环境下,可以用mimikatz等工具直接获取密码。
NTLM Relay
攻击者可以一定程度控制客户端网络的时候,可以使用中间人攻击的方式来获取权限。对客户端伪装为身份验证服务器,对服务端伪装为需要认证的客户端。
OAuth(RFC6749)
这个看了一下,,师傅写的很详细很全,,就直接摆上了
Spring Security OAuth 2.0 - 废物大师兄 - 博客园
Salted Challenge Response(RFC7804)
HTTP SCRAM 是一种 HTTP 身份验证机制,其客户端响应和服务器质询消息是基于文本的消息,包含一个或多个以逗号分隔的属性值对。SCRAM-SHA-1 是为了与 RFC 5802 实现的数据库兼容而注册的,这些实现还希望公开对相关服务的 HTTP 访问,但不建议将其用于新部署。为了互操作性,所有支持 SCRAM 的 HTTP 客户端和服务器必须实现 SCRAM-SHA-256 身份验证机制
SCRAM-SHA-1与SCRAM-SHA-256
查了许多资料,发现在MongoDB中使用最多。
数据包
Authorization: SCRAM-SHA-256 realm="testrealm@example.com",
data=biwsbj11c2VyLHI9ck9wck5HZndFYmVSV2diTkVrcU8K
消息序列
SCRAM SHA-1的执行涉及四个消息的传输和处理;客户端和服务器各有两个。如上图所示,客户端通过发送 客户端第一消息开始该过程,并且响应于从客户端接收到格式正确的第一消息,服务器向客户端发送 服务器第一消息。客户端处理此消息,如果一切正常,则传输 客户端最终消息。正如预期的那样,服务器会处理此消息。在此任务结束时,服务器应该知道客户端是否成功通过身份验证。如果是,服务器发送 服务器最终消息,否则它会向客户端发送认证失败消息(或者可能不会)。随着 服务器最终消息的接收,客户端也能够对服务器进行身份验证
加密值
- 客户端随机数:这是一个由客户端随机生成的值,理想情况下使用加密随机生成器。该值与客户端的用户名一起包含在Client First Message 中。请注意,每个身份验证会话的客户端随机数值必须不同。
- 服务器随机数:这类似于客户端随机数,它包含在服务器第一消息中。对于每个身份验证会话,此值必须不同,并且是加密安全的。
- Salt:Salt 是由服务器生成的加密安全随机数。这个 Salt 值和密码被输入到生成另一个值的单向加密函数中。回想一下背景部分,该值用于隐藏密码。Salt 包含在Server First Message 中。
- Iteration Count:这是由服务器生成的一个数值,表示上面提到的加密函数应该应用于 Salt 和密码以生成其输出的次数。该迭代计数值在Server First Message 中传输。
注意
SCRAM SHA-1 规范强烈 建议该协议应与另一个提供机密性的协议结合使用。换句话说,SCRAM SHA-1 消息应该通过加密通道进行交换。这个想法是为了防止窃听者在传输过程中提取这些消息的内容,然后使用其中包含的值发起离线字典攻击来提取密码。
Mongodb中的认证机制
Vapid(RFC7235)
什么是VAPID
要想发送推送通知,需要使用 VAPID 协议。
VAPID 是“自主应用服务器标识” ( Voluntary Application Server Identification ) 的简称。它是一个规范,它本质上定义了应用服务器和推送服务之间的握手,并允许推送服务确认哪个站点正在发送消息。这很重要,因为这意味着应用服务器能够包含有关其自身的附加信息,可用于联系应用服务器的操作人员。拥有像 VAPID 这样的标准就是向前迈出了一大步,因为这意味着最终所有浏览器都将遵循这个单一标准,即无论什么浏览器,开发者都可以使用 Web 推送进行无缝工作。
数据包
POST /p/JzLQ3raZJfFBR0aqvOMsLrt54w4rJUsV HTTP/1.1
Host: push.example.net
Push-Receipt: https://push.example.net/r/3ZtI4YVNBnUUZhuoChl6omU
Content-Type: text/plain;charset=utf8
Content-Length: 36
Authorization: Bearer
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3B
1c2guZXhhbXBsZS5uZXQiLCJleHAiOjE0NTM1MjM3NjgsInN1YiI6Im1haWx
0bzpwdXNoQGV4YW1wbGUuY29tIn0.i3CYb7t4xfxCDquptFOepC9GAu_HLGk
MlMuCGSK2rpiUfnK9ojFwDXb1JrErtmysazNjjvW2L9OkSSHzvoD1oA
Crypto-Key: p256ecdsa=BA1Hxzyi1RUM1b5wjxsn7nGxAszw2u61m164i3MrAIxH
F6YK5h4SDYic-dRuU_RCPCfA5aq9ojSwk5Y2EmClBPs
iChYuI3jMzt3ir20P8r_jgRR-dSuN182x7iB
关于其他文章
实在找不到关于分析的文章了,,,看一下应用的地方吧
PWA(Progressive Web App)入门系列:Push_王乐平 技术博客-CSDN博客
编程语言实现HTTP认证
- 用 PHP 进行 HTTP 认证
https://www.php.net/manual/zh/features.http-auth.php
- 用 JAVA 实现basic认证
https://ask.csdn.net/questions/768779
- 用java实现Bearer认证
HTTP Bearer认证及JWT的使用 - 搬砖滴 - 博客园
- 用java + SpringBoot实现 DIGEST 认证
HTTP的几种认证方式之DIGEST 认证(摘要认证) - wenbin_ouyang - 博客园
- 摘要认证:
https://www.cnblogs.com/lsdb/p/10621940.html
摘要认证,使用HttpClient实现HTTP digest authentication - 代码先锋网
- java实现双向认证
https://blog.csdn.net/HD243608836/article/details/109105469
- 实现NTLM认证
HttpClient+NTLM认证_耳东的慢生活的博客-CSDN博客
- C#实现SCRAM-SHA-1
https://www.codeproject.com/Articles/698219/Salted-Challenge-Response-Authentication-Mechanism
云厂商API认证方式
API 密钥认证(API Key Authentication):使用一个密钥对进行身份认证,通常由云厂商为每个用户分配一个唯一的 API 密钥,用于在 API 请求中进行身份验证。
OAuth 认证:OAuth 是一种开放标准的授权协议,允许用户授权第三方应用访问其受保护的资源。通过 OAuth 认证方式,用户可以授予应用有限的访问权限,而无需直接共享其密码。
证书认证(Certificate Authentication):该方式使用证书来验证 API 请求的身份。用户需要创建并上传相应的证书,然后在 API 请求中使用证书进行身份认证。
请求签名认证(Request Signing Authentication):该方式使用加密算法对 API 请求进行签名,并在请求中包含签名信息。服务器端根据请求中的签名信息验证请求的合法性。
集成服务认证(Service Account Authentication):通常用于与其他云服务集成时,采用预先分配的服务账号进行认证。服务账号具有独立的身份和权限。
参考文章
[RFC 2617] Digest 签名摘要式认证 - 链滴
Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry
图解HTTP.pdf
HTTP 身份验证框架(Basic 认证)_mbh的博客-CSDN博客_身份验证框架
HTTP Origin-Bound Authentication (HOBA)
HTTPS双向认证(Mutual TLS authentication) - API 网关 - 阿里云
Web应用中基于密码的身份认证机制(表单认证、HTTP认证: Basic、Digest、Mutual)_u012324798的博客-CSDN博客_基于密码的身份认证
8.7. NTLM 身份验证 ‒ Web安全学习笔记 1.0 文档
Salted Challenge Response Authentication Mechanism (SCRAM) SHA-1