摘要: 介绍 SCRAM是密码学中的一种认证机制,全称Salted Challenge Response Authentication Mechanism。 SCRAM适用于使用基于『用户名:密码』这种简单认证模型的连接协议。 SCRAM是一个抽象的机制,在其设计中需要用到一个哈希函数,这个哈希函数是

介绍

SCRAM是密码学中的一种认证机制,全称Salted Challenge Response Authentication Mechanism。
SCRAM适用于使用基于『用户名:密码』这种简单认证模型的连接协议。
SCRAM是一个抽象的机制,在其设计中需要用到一个哈希函数,这个哈希函数是客户端和服务端协商好的,包含在具体的机制名称中。比如SCRAM-SHA1,使用SHA1作为其哈希函数。

前言

基于『用户名:密码』这种简单认证模型的协议中,客户端和服务端都知道一个用户名(username)对应一个密码(password)。在不对信道进行加密的前提下,无论是直接使用明文传输『username:password』,还是给password加个哈希的方法都low爆了,很容易被黑客攻击。一个安全性高的认证机制起码应该是具备双向认证的,即:

  1. 服务端需要验证连接上来的客户端知道对应的password
  2. 客户端需要知道这个声称是服务端的人是真正的服务端

我们来看看SCRAM是怎么做的。

初始

  1. 服务端使用一个salt和一个iteration-count,对password进行加盐哈希(使用H表示哈希函数,这里就是SHA1,iteration-count就是哈希迭代次数),得到一个password[s]:

    _password[s] = H(password, salt, iteration-count)_
  2. 服务端拿这个password[s]分别和字符串『Client Key』和『Server Key』进行计算HMAC摘要,得到一个key[c]和一个key[s]:

    _key[c] = HMAC(password[s], "Client Key")_
    
    _key[s] = HMAC(password[s], "Server Key")_
  3. 服务端保存username、H(key[c])、key[s]、salt和iteration-count,没有保存真正的password

一次认证

  1. 客户端发送client-first-message给服务端,包含username和client-nonce,其中client-nonce是客户端随机生成的字符串
  2. 服务端返回客户端server-first-message,包含salt,iteration-count和client-nonce|server-nonce,其中server-nonce是服务端随机生成的字符串
  3. 客户端发送client-final-message给服务端,包含client-nonce|server-nonce和一个proof[c]。这个proof[c]就是客户端的身份证明。首先构造出这次认证的变量Auth如下:

    _Auth = client-first-message, server-first-message, client-final-message(without proof[c])_
    
    然后使用从服务端获取的salt和iteration-count,根据已知的password计算出加盐哈希password[s],然后根据password[s]得到key[c],再拿这个key[c]和Auth变量经过如下计算得到:
    
    _proof[c] = key[c] XOR HMAC(H(key[c]), Auth)_
  4. 服务端使用其保存的H(key[c])和Auth计算HMAC摘要,再和proof[c]进行异或,得出key[c],再对这个key[c]进行哈希,和其保存的H(key[c])进行比较是否一致。如果一致,则客户端的认证通过,服务端接下来会构造一个proof[s]用来向客户端证明自己是服务端:

    _proof[s] = HMAC(key[s], Auth)_
  5. 客户端使用password[s]得到key[s],然后使用相同算法计算key[s]和Auth的HMAC摘要,验证服务端发送过来的proof[s]是否和计算出来的一致,从而认证服务端的身份。

几个问题

Q:proof[c]为什么不能是和proof[s]一样使用HMAC(key[c], Auth)算得?

A:服务端没有保存key[c],而是保存H(key[c]),这是因为如果服务端的key[c]泄露,那么黑客可以轻易构造出proof[c],从而伪装成客户端了。

Q:那么直接使用HMAC(H(key[c]), Auth)呢?

A:同样,如果服务端的H(key[c])泄露,黑客又可以轻易构造出proof[c],从而伪装成客户端了。因此必须要加上key[c]的异或,从而证明客户端知道key[c]的值。

Q:但是如果服务端的H(Key[c])泄露,再通过网络泄露了proof[c]和Auth,就可以根据proof[c]和HMAC(H(key[c]), Auth)异或得到key[c]了?

A:是的,所以如果要求更高的安全性,还是推荐使用信道加密。

Q:nonce的作用?

A:client-nonce和server-nonce都是随机生成的字符串,这主要是为了每次认证都有个不同的Auth变量,以防止被重放攻击。

安全性分析

分析下以下几种情况下SCRAM的安全性:

  • 网络流量被监听:
    如果某次认证的网络流量被监听,黑客可以拿到salt、iteration-count和Auth,但是无法伪装成服务端,因为没有key[s],无法生成proof[s],完成不了最后一次认证。
  • 服务端被脱裤:如果服务端被脱裤,黑客可以拿到username、H(key[c])、key[s]、salt和iteration-count,但是生成不了key[c],因此无法生成proof[c],不能伪装成客户端。
  • 如果很不幸的网络流量被监听,服务端又被脱裤,那么对不起,被爆菊了,要应对这种情况,只能使用信道加密了。

参考文献

    1. Improved Password-Based Authentication in MongoDB 3.0: SCRAM Explained - Pt. 1
    2. Improved password-based authentication in MongoDB 3.0: SCRAM Explained (Part 2)
    3. 维基百科:Salted Challenge Response Authentication Mechanism
    4. 阿里云MongoDB云服务

最新文章

  1. NET Core-TagHelper实现分页标签
  2. 简单的例子了解自定义ViewGroup(一)
  3. Python之Django【基础篇】
  4. win95+ie3-win10+ie11 浏览器执行漏洞
  5. iBeacon开发
  6. Libev学习笔记3
  7. ASP.NET MVC中对Model进行分步验证的解决方法
  8. javascript this指针指向?
  9. ArcEngine开发中StartEditing和StartEditOperation的区别
  10. Python中使用Mysql(安装篇)
  11. uva11059(最大乘积)
  12. Python系列之 - 字符编码问题
  13. java日期转化,三种基本的日期格式
  14. 【BZOJ4005】[JLOI2015] 骗我呢(容斥,组合计数)
  15. 破解网页右键被禁止js
  16. 直接用<img> 的src属性显示base64转码后的字符串成图片【原】
  17. L252 小组作业
  18. 邮件服务器日志:/var/log/maillog
  19. python learning Process and Thread.py
  20. Tomcat 配置加密的服务器连接器

热门文章

  1. Hosts 文件的作用
  2. 程序级的AOP到底好不好?
  3. How to convert a QString to unicode object in python 2?
  4. windows下Java调用mysql的客户端备份和恢复
  5. 转 HTTP.SYS 详解
  6. Android - 传统蓝牙通信聊天
  7. bzoj2957楼房重建
  8. 转:HL7 Tools suite
  9. java web jsp
  10. webpack和webpack-dev-server安装配置