用户密码的存储与 Python 示例

在各种线上应用中,用户名密码是用户身份认证的关键,它的重要性不言而喻。一方面,作为保护用户敏感数据的钥匙来说,一旦被破解,系统将敞开大门完全不设防。另一方面,密码这把钥匙本身就是非常敏感的数据:大多数用户会在不同应用中使用近似甚至完全相同的密码。一旦某一个应用的密码被破解,很可能坏人就此掌握了用户的“万能钥匙”,这个用户的其它应用也相当危险了。

这篇博文就重点讨论对于密码本身的存储的安全性考虑,而系统自身的安全性不在此文的范围之内。

对于如此重要的用户密码,究竟该怎样在系统中存储呢?

“君子不立危墙”,对于用户密码这个烫手山芋,一个极端的选择是系统完全不接触密码,用户的身份认证转交受信任的第三方来处理。例如 OpenID 这样的解决方案。系统向受信任的第三方求证用户身份的合法性,用户通过密码向第三方证明自己的身份。

这样一来,也就不用绞尽脑汁保证密码的安全了。这个作法对用户来说还有个额外的好处:再也不用为每个应用注册帐号了,同一个 OpenID 就可以登录所有支持 OpenID 的系统。

好虽好,可在今天这样一个裂土封国划地为营的网络战国时代,用户资源不但不能牢牢掌握在自己的手上,还要与别人分享,甚至要受制于人,这多少有点让人难以接受。(据称,现在全球有 27000 个 Web Site 支持 OpenID 登录,虽然还在持续增长中,但在茫茫“网海“中无疑还是属于小众)

既然网络大同时代还没来临,大部分应用还是要自己负责用户的认证,那密码该如何存储呢?按照安全性由低到高,有这样几种选择:

  1. 密码明文直接存储在系统中

    这种方法下密码的安全性比系统本身还低,管理员能查看所有用户的密码明文。除非是做恶意网站故意套取用户密码,否则不要用这种方式

  2. 密码明文经过转换后再存储

    与直接存储明文的方式没有本质区别,任何知道或破解出转换方法的人都可以逆转换得到密码明文

  3. 密码经过对称加密后再存储

    密码明文的安全性等同于加密密钥本身的安全性。对称加密的密钥可同时用于加密与解密。一般它会直接出现在加密代码中,破解的可能性相当大。而且系统管理员很可能知道密钥,进而算出密码原文

  4. 密码经过非对称加密后再存储

    密码的安全性等同于私钥的安全性。密码明文经过公钥加密。要还原密码明文,必须要相应的私钥才行。因此只要保证私钥的安全,密码明文就安全。私钥可以由某个受信任的人或机构来掌管,身份验证只需要用公钥就可以了

    实际上,这也是 HTTPS/SSL 的理论基础。这里的关键是 私钥的安全 ,如果私钥泄露,那密码明文就危险了。

以上 4 种方法的共同特点是可以从存储的密码形式还原到密码明文。

当你忘了用户密码后,网站可以很贴心地通过你注册的 email 提醒你原来的密码是什么,那它肯定就是用了上面的某种方法了。这时候你就得小心了:既然网站能知道密码明文,那网站的工作人员就有可能知道,攻入这个网站的黑客也有了还原你密码明文的可能。

所以密码最好是以不可还原明文的方式来保存。通常利用哈希算法的单向性来保证明文以 不可还原的有损方式 进行存储。

这类方法的各个具体操作方式按安全性由低到高依次为:

  1. 使用自己独创的哈希算法对密码进行哈希,存储哈希过的值

    哈希算法复杂,独创对理论要求很高。一般独创的哈希算法肯定没有公开经过时间检验的算法质量高,天才另算

  2. 使用 MD5 或 SHA-1 哈希算法

    MD5 和 SHA-1 已破解。虽不能还原明文,但很容易找到能生成相同哈希值的替代明文。而且这两个算法速度较快,暴力破解相对省时,建议不要使用它们。

  3. 使用更安全的 SHA-256 等成熟算法

    更加复杂的算法增加了暴力破解的难度。但如果遇到简单密码,用彩虹字典的暴力破解法,很快就能得到密码原文

  4. 加入随机 salt 的哈希算法

    密码原文(或经过 hash 后的值)和随机生成的 salt 字符串混淆,然后再进行 hash,最后把 hash 值和 salt 值一起存储。验证密码的时候只要用 salt 再与密码原文做一次相同步骤的运算,比较结果与存储的 hash 值就可以了。这样一来哪怕是简单的密码,在进过 salt 混淆后产生的也是很不常见的字符串,根本不会出现在彩虹字典中。salt 越长暴力破解的难度越大

    具体的 hash 过程也可以进行若干次叠代,虽然 hash 叠代会增加碰撞率,但也增加暴力破解的资源消耗。就算真被破解了,黑客掌握的也只是这个随机 salt 混淆过的密码,用户原始密码依然安全,不用担心其它使用相同密码的应用。

上面这几种方法都不可能得到密码的明文,就算是系统管理员也没办法。对于那些真的忘了密码的用户,网站只能提供重置密码的功能了。

下面的 python 程序演示了如何使用 salt 加 hash 来单向转换密码明文

import os
from hashlib import sha256
from hmac import HMACdef encrypt_password(password, salt=None):"""Hash password on the fly."""if salt is None:salt = os.urandom(8) # 64 bits.assert 8 == len(salt)assert isinstance(salt, str)if isinstance(password, unicode):password = password.encode('UTF-8')assert isinstance(password, str)result = passwordfor i in xrange(10):result = HMAC(result, salt, sha256).digest()return salt + result

这里先随机生成 64 bits 的 salt,再选择 SHA-256 算法使用 HMAC 对密码和 salt 进行 10 次叠代混淆,最后将 salt 和 hash 结果一起返回。

使用的方法很简单:

hashed = encrypt_password('secret password')

下面是验证函数,它直接使用 encrypt_password 来对密码进行相同的单向转换并比较

def validate_password(hashed, input_password):return hashed == encrypt_password(input_password, salt=hashed[:8])assert validate_password(hashed, 'secret password')

虽然只有简短几行,但借助 python 标准库帮助,这已经是一个可用于生产环境的高安全密码加密验证算法了。

总结一下用户密码的存储:

  • 上善不战而屈人之兵。如果可能不要存任何密码信息 让别人(OpenID)来帮你做事,避开这个问题
  • 如果非要自己认证,也只能存 不可逆的有损密码信息 。通过单向 hash 和 salt 来保证只有用户知道密码明文
  • 绝对不能存可还原密码原文的信息 。如果因为种种原因一定要可还原密码原文,请使用非对称加密,并保管好私钥

说完了密码的存储,后面有空会接着聊聊 密码的传输

密码传输问题

说了 密码的存储 问题,接下来再聊聊密码的传输问题。

对于在线系统,密码的传输要经过下面几个步骤:

  1. 用户在浏览器中输入原始密码:键盘 ——> 操作系统 ——> 浏览器内存
  2. 程序对原始密码进行转换:内存中的原始密码 ——> 内存中的转换后的密码
  3. 转换后的密码在线上传输:内存中转换后的密码 ——> 网络 ——> 系统

这其中每一步都可能泄露原始密码,当然也有相应的保护措施。

  • 密码输入
  • 密码转换
  • 密码在线传输
  • 常用服务分析
  • 小结
  • 其它

密码输入

千里之行始于足下,用户输入密码这第一步往往是最危险的。常用的攻击方法包括:

  • 偷看输入的密码

    在公共场合输入密码很容易被偷看,例如使用 ATM 机取款的时候。输入密码时密码明文用 * 代替就是为了防止偷窥。但这样正常用户也不能直接用眼睛确认输入密码是否正确,通常在设置新密码时就要输入两遍来确保输入无误。iPhone 在这点做了改进,每输入一个密码字符先显示半秒钟的明文再转成 * 显示,鉴于使用 iPhone 虚拟键盘输入时,按错键的概率还是比较高的,这个折中也是在可用性和安全性上做了妥协。还有些系统为了最大限度的防偷窥,在输入密码时屏幕没有任何输出,比如 Unix/Linux 的命令行登录界面。这样就连输入的密码长度都看不出来。

  • 用木马程序记录键盘输入

    现在比较流行的 QQ 或网络游戏的盗号就常用这种方式进行。安装杀毒软件来防盗号自不必说,还可以用屏幕软键盘输入密码,这样木马就记录不到键盘事件,只能通过分析鼠标点击和当时屏幕图象来破解密码。如果再进一步,软键盘的字符布局每次都随计产生,那就更加重了分析破解的难度。

  • 感染应用程序或使用钓鱼手法,直接得到内存中的密码值

    不管如何防范输入的过程,一旦密码到程序里,就会以明文的形式呈现在内存中,只要恶意软件模仿安全程序(或模仿网站的外观)直接套取密码就轻而易举。现在出现的假 ATM 机诈骗也是这种手法的衍生。还有一种,不是替换或模仿程序,而是用病毒感染原程序将内存中的值读到。要防范这种攻击,必须要对原程序的完整性和合法性进行验证,只有在验证通过后,才能进行正常的登录交互操作。这个验证可以用数字签名来实现。比如 Windows 7 中所有微软的可执行文件都带有微软的数字签名。在网站上则是 HTTPS 的验证。当然,这个验证过程还牵扯到人的判断,在社会工程学上,软件要配合一些强制的措施,才能保证人不会麻痹大意中招。比如浏览器在访问非信任机构签发的数字签名的 HTTPS 站点时,会警告并且阻止用户进行访问。Windows 7 现在所有的驱动程序也都必须要有微软的数字签名才能运行。

密码转换

原始密码会经过一些转换,才能在线上传输。这跟密码的存储类似。直接传输密码明文是最不安全的。而用简单的可逆变换,或者固定密钥加密也只是增加了破解难度。最好是每次服务器随机产生一个密钥,送给客户端进行加密。

如果使用 HTTPS,那所有通过 SSL 通道的信息都经过了随机密钥加密。自然也包括了密码。HTTPS 虽然安全,可它最大的问题是性能。连接初始时密钥的协商是通过非对称加密的体系进行的,这会造成连接较慢(密钥协商好后的数据加密是纯耗 CPU 的工作,在现在的硬件条件下,并不是瓶颈)。金融在线系统一般都使用 HTTPS ,但大部分在线应用出于性能的考虑,会选择使用 HTTP 交换随机密码的方式。

随机密钥由服务器生成并发送给客户端。客户端用此密钥将密码加密,送给服务器。这里不要求加密方法是可逆的。一个较安全的做法是客户端使用 MD5 或 SHA-1 算法对密码进行不可逆转换,再用密钥加密送到 Server。现在已经有很多 Javascript 的加密库可以在浏览器端进行这样的转换工作。

密码在线传输

如果只使用 HTTP 而不使用 HTTPS,那就算密码不被攻破,还是有可能发生重放攻击。当中间人截获了转换后的密码后,他不必知道密码明文就可以用转换后的密码通过服务器的认证。

现在最新的研究是利用量子力学所揭示的粒子对的超距相关性来进行量子加密传输。可以类比古代密信的火漆封口,一旦信件被拆开,火漆肯定被破坏。收信人就会知道。量子加密很耗资源,是为了军事等绝密级别信息传输准备的技术。用于量子加密传输的信息也只会是密钥。一旦双方确认了彼此的密钥,就可以使用普通通道来传输加密后的密文了。看上去量子加密传输很象终极解决方案,可最近也传出了针对量子加密的成功攻击的 案例 。

常用服务分析

这里用抓包方式分析一下常用的网络服务的密码传输,看看它们在安全性方面做的如何

网站 密码传输方式 安全性
bitbucket.org HTTPS 加密传输
微软 live.com HTTPS 加密传输
google.com HTTPS 加密传输
开心网 kaixin001.com HTTP Javascript 加密传输
西祠 xici.com HTTP Javascript 加密传输
csdn.net HTTP Javascript 加密传输
javaeye.com HTTP 明文传输
天涯 tianya.cn HTTP 明文传输
人人网 renren.com HTTP 明文传输

对那些既不支持 HTTPS 又不经过客户端加密,而是直接使用 HTTP 明文传送密码的网站,建议不要使用常用的密码来注册,避免安全隐患。

小结

密码的传输比 密码的存储 更加敏感和不安全,大致有三个层次的传输策略:

  1. 使用 HTTPS 加密传输,非常安全。HTTPS 对服务器性能要求高,也影响登录速度。一般用在高安全性的登录上面。Google 和微软的登录都强制使用 HTTPS 确保安全第一
  2. 使用随机密钥对密码进行变换后再传输,相对安全。密码明文很安全,但仍可能发生重放攻击。这种方式是性能和安全性的折中。一般的服务使用足亦,例如国内的开心网
  3. 不做任何修饰,直接将密码明文通过 HTTP 传输。这种方式实现起来非常简单,但却是对用户隐私和数据的不负责任。很可惜,国内几个著名网站都是采用这种简单方式。用户的应对之道就是不要在这些网站上使用常用的密码,例如你银行卡的密码。

其它

密码在传输过程中的泄露的途径很多,你很可能完全没有意识到密码正被窃听。比如最近的一个新闻,骗子用软件对电话按键音进行音频分析,进而得到用户的密码。大概我们在用电话银行时都没有想到,按键的声音居然也是我们密码传输的一种载体吧。

最近在使用浦发银行的 400 电话服务时,惊奇地发现当系统提示输入密码时,除了听到自己的按键音外,听筒里还有其它的按键音随机的响起。因为这些背景音的干扰,居然让人输入密码时有点手足无措(声音也是种 UI 界面,只是一直被忽略,其实它对用户的重要性一点也不比图形 UI 来的低)

略一思考,这不正是防止电话按键音泄露银行密码的安全措施吗。浦发连这点都想到了,真是魔高一层道高一丈!

来源:http://zhuoqiang.me/password-storage-and-python-example.html

用户密码的存储与密码传输相关推荐

  1. 用户密码加密存储十问十答,一文说透密码安全存储

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | 程序员赵鑫 来源 | cnblogs.com/xinzh ...

  2. 如何安全存储用户密码/数据库安全存储密码的方式

    总的来讲,目前公认比较安全的存储密码方式是PBKDF2, BCrypt 或 SCrypt 算法产生的密码. 历史上密码加密存储经历了如下几个阶段: 1. 单向hash(MD5) 做单向的hash加密, ...

  3. 加密文件忘记密码怎么解密_MyBatis 配置文件 用户密码加密存储

    properties配置文件 一般是使用properties保存配置文件内容,然后在mybatis配置文件中进行读取 在resource文件下新建db.properties文件 内容如下 # 数据库配 ...

  4. MyBatis 配置文件 用户密码加密存储

    文章目录 1. 创建db.properties 2. 配置mybatis-config.xml 3. 加解密工具类 4. 加解密依赖 5. 创建SqlSessionFactoryUtil类 6. db ...

  5. 12306:候补购票服务扩大到全部列车;G Suite 漏洞:部分密码明文存储

    (给技术最前线加星标,每天看技术热点) 转自:开源中国.solidot.cnBeta.腾讯科技.快科技等 [业界资讯] 0.12306:铁路候补购票服务扩大到全部旅客列车 据12306网站消息,5月2 ...

  6. mysql存储登录密码_当密码存储在选项文件中时,MySQL拒绝登录尝试

    第一: >我们正在运行MySQL 5.7.13. >操作系统是Red Hat Enterprise Linux 7.2. >首先使用Python / Connector 2.1.3发 ...

  7. 工信部提醒:用户及时设置 SIM 卡密码,丢失手机后第一时间挂失

    IT之家10月19日消息 工信部发布,近日,有舆论报道反映,不法分子偷盗个人手机后,在某政务 APP 窃取用户个人信息,进而申请网贷消费造成用户财产损失的情况.该文章通过互联网大量转发,引发网民对手机 ...

  8. sql server的密码采用自带什么密码技术存储_【技术分享】浅谈MYSQL 8.0新特性

    于树文 云技术管理处 01 MySQL 8.0中添加的功能 1. 新的系统字典表 整合了存储有关数据库对象信息的事务数据字典,所有的元数据都用InnoDB引擎进行存储. 2. 支持DDL 原子操作 I ...

  9. bcrypt强哈希_为什么应该使用Bcrypt哈希存储的密码

    bcrypt强哈希 79% of participants in a recent ZoneAlarm survey were found to be using risky passwords. T ...

  10. linux wifi密码保存在哪个文件夹,Ubuntu明文存储WiFi密码方法介绍

    玩蛇网推荐图文教程:python 列表 Ubuntu明文存储WiFi密码方法介绍.Linux系统的驱动发行版在主目录外存储Wi-Fi配置文件,这使得它们更易于被访问. 这包括Wi-Fi配置文件的密码: ...

最新文章

  1. java 同步块 抛出异常_不把 wait 放在同步块中,为啥这种情况不会抛出 IllegalMonitorStateException?...
  2. 小结两种在Python中导入C语言扩展库的方法
  3. python绘制饼图explode_python通过matplotlib生成复合饼图
  4. SqlServerDBCC SHRINKFILE不起作用
  5. 1730: 数区间(线段覆盖,贪心)
  6. 如何在线将pdf转换成ppt格式
  7. Centos5.5安装使用Xen
  8. spring mvc学习(33):原生apiSpring MVC过滤器-HiddenHttpMethodFilter
  9. spark的外排:AppendOnlyMap与ExternalAppendOnlyMap
  10. Python3 爬虫(一)-- 简单网页抓取
  11. easymock_EasyMock验证
  12. 802.x无线认证服务器,无线802.1X认证
  13. 虚幻引擎图文笔记:导入FBX骨骼动画(附官方FBX模型下载)
  14. 基于snowflake的序列号生成器
  15. python脚本实现QQ自动发送消息
  16. android room表关联,Android Room的用法
  17. CSDN蓝桥杯算法题——题解Java版本——切面条
  18. 小学生python趣味编程-【少儿编程】python趣味编程第二课:写文字
  19. Oracle 备份失败报错ORA-04063: view SYS.KU_RADM_FPTM_VIEW has errors
  20. mysql计算订单总金额_【写SQL语句】按照用户统计对应订单数和订单总金额?

热门文章

  1. 论坛介绍 | COSCon'22 开源操作系统(O)
  2. Docker数据卷映射
  3. 就在那犹豫的一刹那,跌入那深渊
  4. 区别: @Secured(), @PreAuthorize() 及 @RolesAllowed()
  5. Lua-面试考题附答案解析(一)
  6. 恢复html默认打开方式,打开方式怎么还原?文件打开方式修复的方法
  7. linux运维都不知道是什么,这8种命令都不会,还算什么Linux运维!
  8. Canal监听阿里云RDS
  9. php 判断中文和英文,PHP如何判断中文还是英文?
  10. openstack虚拟机无法获取IP地址