61阅读

如何清除用户名和密码-我是大智慧新一代的收费用户,我如何知道我的用户名和密码?由于现在?

发布时间:2017-11-05 所属栏目:安全存储

一 : 我是大智慧新一代的收费用户,我如何知道我的用户名和密码?由于现在?

我是大智慧新一代的收费用户,我如何知道我的用户名和密码?

我是大智慧新一代的收费用户,我如何知道我的用户名和密码?
由于现在是一点就自动登陆,所以我也不清楚我现在的用户名和密码是多少?还有如何选择大智慧新一代收费版的自动登陆选项呢?
如果我把用户名和密码告诉我的朋友,他可以使用吗?

请高手给予帮忙,十分感谢!有分送上


womenyizhidoushishiyongmianfeide

二 : 如何清除保存的FTP用户名和密码

很多人习惯登陆FTP时选择保存密码,这样下次只需打开地址即可进入FTP的页面了。这样确实方便,但如果遇到更换别的FTP用户名登陆,该怎么办?相信不少人还真答不出。重装浏览器,或者重装系统?呵呵,那就太小题大做了。这里我找到了[www.61k.com]1个快捷有效的解决方法:进入注册表(运行——regedit)——找到HKEY_CURRENT_USER\Software\Microsoft\FTP\Accounts项,将其下面的子项(一般以FTP的IP命名)删除就可以。如果你登录FTP是记住密码,用这个方法也可以完全将用户信息清除。

三 : 如何安全的存储用户的密码(1)

大多数的web开发者都会遇到设计用户账号系统的需求。账号系统最重要的一个方面就是如何保护用户的密码。一些大公司的用户数据库泄露事件也时有发生,所以我们必须采取一些措施来保护用户的密码,即使网站被攻破的情况下也不会造成较大的危害。如果你还在存储用户密码的MD5,那可真的有点弱了。赶紧来看看这篇文章吧。

保护密码最好的的方式就是使用带盐的密码hash(salted password hashing).对密码进行hash操作是一件很简单的事情,但是很多人都犯了错。接下来我希望可以详细的阐述如何恰当的对密码进行hash,以及为什么要这样做。

重要提醒

如果你打算自己写一段代码来进行密码hash,那么赶紧停下吧。这样太容易犯错了。这个提醒适用于每一个人,不要自己写密码的hash算法 !关于保存密码的问题已经有了成熟的方案,那就是使用phpass或者本文提供的源码。

什么是hash

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366hash("waltz") = c0e81794384491161f1777c232bc6bd9ec38f616560b120fda8e90f383853542

Hash算法是一种单向的函数。它可以把任意数量的数据转换成固定长度的“指纹”,这个过程是不可逆的。而且只要输入发生改变,哪怕只有一个bit,输出的hash值也会有很大不同。这种特性恰好合适用来用来保存密码。因为我们希望使用一种不可逆的算法来加密保存的密码,同时又需要在用户登陆的时候验证密码是否正确。

在一个使用hash的账号系统中,用户注册和认证的大致流程如下:

1, 用户创建自己的账号2, 用户密码经过hash操作之后存储在数据库中。没有任何明文的密码存储在服务器的硬盘上。3, 用户登陆的时候,将用户输入的密码进行hash操作后与数据库里保存的密码hash值进行对比。4, 如果hash值完全一样,则认为用户输入的密码是正确的。否则就认为用户输入了无效的密码。5, 每次用户尝试登陆的时候就重复步骤3和步骤4。

在步骤4的时候不要告诉用户是账号还是密码错了。只需要显示一个通用的提示,比如账号或密码不正确就可以了。这样可以防止攻击者枚举有效的用户名。

还需要注意的是用来保护密码的hash函数跟数据结构课上见过的hash函数不完全一样。比如实现hash表的hash函数设计的目的是快速,但是不够安全。只有加密hash函数(cryptographic hash functions)可以用来进行密码的hash。这样的函数有SHA256, SHA512, RipeMD, WHIRLPOOL等。

一个常见的观念就是密码经过hash之后存储就安全了。这显然是不正确的。有很多方式可以快速的从hash恢复明文的密码。还记得那些md5破解网站吧,只需要提交一个hash,不到一秒钟就能知道结果。显然,单纯的对密码进行hash还是远远达不到我们的安全需求。下一部分先讨论一下破解密码hash,获取明文常见的手段。

如何安全的存储用户的密码(1)_安全存储

如何破解hash

字典和暴力破解攻击(Dictionary and Brute Force Attacks)

最常见的破解hash手段就是猜测密码。然后对每一个可能的密码进行hash,对比需要破解的hash和猜测的密码hash值,如果两个值一样,那么之前猜测的密码就是正确的密码明文。猜测密码攻击常用的方式就是字典攻击和暴力攻击。

Dictionary AttackTrying apple : failedTrying blueberry : failedTrying justinbeiber : failed...Trying letmein : failedTrying s3cr3t : success!

字典攻击是将常用的密码,单词,短语和其他可能用来做密码的字符串放到一个文件中,然后对文件中的每一个词进行hash,将这些hash与需要破解的密码hash比较。这种方式的成功率取决于密码字典的大小以及字典的是否合适。

Brute Force AttackTrying aaaa : failedTrying aaab : failedTrying aaac : failed...Trying acdb : failedTrying acdc : success!

暴力攻击就是对于给定的密码长度,尝试每一种可能的字符组合。这种方式需要花费大量的计算机时间。但是理论上只要时间足够,最后密码一定能够破解出来。只是如果密码太长,破解花费的时间就会大到无法承受。

目前没有方式可以阻止字典攻击和暴力攻击。只能想办法让它们变的低效。如果你的密码hash系统设计的是安全的,那么破解hash唯一的方式就是进行字典或者暴力攻击了。

查表破解(Lookup Tables)

对于特定的hash类型,如果需要破解大量hash的话,查表是一种非常有效而且快速的方式。它的理念就是预先计算(pre-compute)出密码字典中每一个密码的hash。然后把hash和对应的密码保存在一个表里。一个设计良好的查询表结构,即使存储了数十亿个hash,每秒钟仍然可以查询成百上千个hash。

如果你想感受下查表破解hash的话可以尝试一下在CraskStation上破解下下面的sha256 hash。

c11083b4b0a7743af748c85d343dfee9fbb8b2576c05f3a7f0d632b0926aadfc08eac03b80adc33dc7d8fbe44b7c7b05d3a2c511166bdb43fcb710b03ba919e7e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f9045206b8b8a996cf5320cb12ca91c7b790fba9f030408efe83ebb83548dc3007bd

反向查表破解(Reverse Lookup Tables)

Searching for hash(apple) in users' hash list... : Matches [alice3, 0bob0, charles8]Searching for hash(blueberry) in users' hash list... : Matches [usr10101, timmy, john91]Searching for hash(letmein) in users' hash list... : Matches [wilson10, dragonslayerX, joe1984]Searching for hash(s3cr3t) in users' hash list... : Matches [bruce19, knuth1337, john87]Searching for hash(z@29hjja) in users' hash list... : No users used this password

这种方式可以让攻击者不预先计算一个查询表的情况下同时对大量hash进行字典和暴力破解攻击。

首先,攻击者会根据获取到的数据库数据制作一个用户名和对应的hash表。然后将常见的字典密码进行hash之后,跟这个表的hash进行对比,就可以知道用哪些用户使用了这个密码。这种攻击方式很有效果,因为通常情况下很多用户都会有使用相同的密码。

彩虹表 (Rainbow Tables)

彩虹表是一种使用空间换取时间的技术。跟查表破解很相似。只是它牺牲了一些破解时间来达到更小的存储空间的目的。因为彩虹表使用的存储空间更小,所以单位空间就可以存储更多的hash。彩虹表已经能够破解8位长度的任意md5hash。彩虹表具体的原理可以参考http://www.project-rainbowcrack.com/

下一章节我们会讨论一种叫做“盐”(salting)的技术。通过这种技术可以让查表和彩虹表的方式无法破解hash。

如何安全的存储用户的密码(1)_安全存储

加盐(Adding Salt)

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824hash("hello" + "QxLUF1bgIAdeQX") = 9e209040c863f84a31e719795b2577523954739fe5ed3b58a75cff2127075ed1hash("hello" + "bv5PehSMfV11Cd") = d1d3ec2e6f20fd420d50e2642992841d8338a314b8ea157c9e18477aaef226abhash("hello" + "YYLmfY6IehjZMQ") = a49670c3c18b9e079b9cfaf51634f563dc8ae3070db2c4a8544305df1b60f007

查表和彩虹表的方式之所以有效是因为每一个密码的都是通过同样的方式来进行hash的。如果两个用户使用了同样的密码,那么一定他们的密码hash也一定相同。我们可以通过让每一个hash随机化,同一个密码hash两次,得到的不同的hash来避免这种攻击。

具体的操作就是给密码加一个随即的前缀或者后缀,然后再进行hash。这个随即的后缀或者前缀成为“盐”。正如上面给出的例子一样,通过加盐,相同的密码每次hash都是完全不一样的字符串了。检查用户输入的密码是否正确的时候,我们也还需要这个盐,所以盐一般都是跟hash一起保存在数据库里,或者作为hash字符串的一部分。

盐不需要保密,只要盐是随机的话,查表,彩虹表都会失效。因为攻击者无法事先知道盐是什么,也就没有办法预先计算出查询表和彩虹表。如果每个用户都是使用了不同的盐,那么反向查表攻击也没法成功。

下一节,我们会介绍一些盐的常见的错误实现。

错误的方式:短的盐和盐的复用

最常见的错误实现就是一个盐在多个hash中使用或者使用的盐很短。

盐的复用(Salt Reuse)

不管是将盐硬编码在程序里还是随机一次生成的,在每一个密码hash里使用相同的盐会使这种防御方法失效。因为相同的密码hash两次得到的结果还是相同的。攻击者就可以使用反向查表的方式进行字典和暴力攻击。只要在对字典中每一个密码进行hash之前加上这个固定的盐就可以了。如果是流行的程序的使用了硬编码的盐,那么也可能出现针对这种程序的这个盐的查询表和彩虹表,从而实现快速破解hash。

用户每次创建或者修改密码一定要使用一个新的随机的盐

短的盐

如果盐的位数太短的话,攻击者也可以预先制作针对所有可能的盐的查询表。比如,3位ASCII字符的盐,一共有95x95x95 = 857,375种可能性。看起来好像很多。假如每一个盐制作一个1MB的包含常见密码的查询表,857,375个盐才是837GB。现在买个1TB的硬盘都只要几百块而已。

基于同样的理由,千万不要用用户名做为盐。虽然对于每一个用户来说用户名可能是不同的,但是用户名是可预测的,并不是完全随机的。攻击者完全可以用常见的用户名作为盐来制作查询表和彩虹表破解hash。

根据一些经验得出来的规则就是盐的大小要跟hash函数的输出一致。比如,SHA256的输出是256bits(32bytes),盐的长度也应该是32个字节的随机数据。

如何安全的存储用户的密码(1)_安全存储

错误的方式:双重hash和古怪的hash函数

这一节讨论另外一个常见的hash密码的误解:古怪的hash算法组合。人们可能解决的将不同的hash函数组合在一起用可以让数据更安全。但实际上,这种方式带来的效果很微小。反而可能带来一些互通性的问题,甚至有时候会让hash更加的不安全。本文一开始就提到过,永远不要尝试自己写hash算法,要使用专家们设计的标准算法。有些人会觉得通过使用多个hash函数可以降低计算hash的速度,从而增加破解的难度。通过减慢hash计算速度来防御攻击有更好的方法,这个下文会详细介绍。

下面是一些网上找到的古怪的hash函数组合的样例。

md5(sha1(password))md5(md5(salt) + md5(password))sha1(sha1(password))sha1(str_rot13(password + salt))md5(sha1(md5(md5(password) + sha1(password)) + md5(password)))

不要使用他们!

注意:这部分的内容其实是存在争议的!我收到过大量邮件说组合hash函数是有意义的。因为如果攻击者不知道我们用了哪个函数,就不可能事先计算出彩虹表,并且组合hash函数需要更多的计算时间。

攻击者如果不知道hash算法的话自然是无法破解hash的。但是考虑到Kerckhoffs’s principle,攻击者通常都是能够接触到源码的(尤其是免费软件和开源软件)。通过一些目标系统的密码–hash对应关系来逆向出算法也不是非常困难。

如果你想使用一个标准的”古怪”的hash函数,比如HMAC,是可以的。但是如果你的目的是想减慢hash的计算速度,那么可以读一下后面讨论的慢速hash函数部分。基于上面讨论的因素,最好的做法是使用标准的经过严格测试的hash算法。

hash碰撞(Hash Collisions)

因为hash函数是将任意数量的数据映射成一个固定长度的字符串,所以一定存在不同的输入经过hash之后变成相同的字符串的情况。加密hash函数(Cryptographic hash function)在设计的时候希望使这种碰撞攻击实现起来成本难以置信的高。但时不时的就有密码学家发现快速实现hash碰撞的方法。最近的一个例子就是MD5,它的碰撞攻击已经实现了。

碰撞攻击是找到另外一个跟原密码不一样,但是具有相同hash的字符串。但是,即使在相对弱的hash算法,比如MD5,要实现碰撞攻击也需要大量的算力(computing power),所以在实际使用中偶然出现hash碰撞的情况几乎不太可能。一个使用加盐MD5的密码hash在实际使用中跟使用其他算法比如SHA256一样安全。不过如果可以的话,使用更安全的hash函数,比如SHA256, SHA512, RipeMD, WHIRLPOOL等是更好的选择。

如何安全的存储用户的密码(1)_安全存储

正确的方式:如何恰当的进行hash

这部分会详细讨论如何恰当的进行密码hash。第一个章节是最基础的,这章节的内容是必须的。后面一个章节是阐述如何继续增强安全性,让hash破解变得异常困难。

基础:使用加盐hash

我们已经知道恶意黑客可以通过查表和彩虹表的方式快速的获得hash对应的明文密码,我们也知道了通过使用随机的盐可以解决这个问题。但是我们怎么生成盐,怎么在hash的过程中使用盐呢?

盐要使用密码学上可靠安全的伪随机数生成器(Cryptographically Secure Pseudo-Random Number Generator (CSPRNG))来产生。CSPRNG跟普通的伪随机数生成器比如C语言中的rand(),有很大不同。正如它的名字说明的那样,CSPRNG提供一个高标准的随机数,是完全无法预测的。我们不希望我们的盐能够被预测到,所以一定要使用CSPRNG。下表提供了一些常用语言中的CSPRNG。

如何安全的存储用户的密码(1)_安全存储

每一个用户,每一个密码都要使用不同的盐。用户每次创建账户或者修改密码都要使用一个新的随机盐。永远不要重复使用盐。盐的长度要足够,一个经验规则就是盐的至少要跟hash函数输出的长度一致。盐应该跟hash一起存储在用户信息表里。

存储一个密码:

1, 使用CSPRNG生成一个长的随机盐。

2, 将密码和盐拼接在一起,使用标准的加密hash函数比如SHA256进行hash

3, 将盐和hash记录在用户数据库中

验证一个密码:

1, 从数据库中取出用户的盐和hash

2, 将用户输入的密码和盐按相同方式拼接在一起,使用相同的hash函数进行hash

3, 比较计算出的hash跟存储的hash是否相同。如果相同则密码正确。反之则密码错误。

在本文的最后,给出了php,C#,Java,Ruby的加盐密码hash的实现代码。

在web应用中,要在服务端进行hash:

如果你在写一个web应用,可能会有在客户端还是服务端进行hash的疑惑。是将密码在浏览器里使用javascript进行hash,还是将明文传给服务端,在服务端进行hash呢?

即使在客户端用javascript进行了hash,在服务端依然需要将得到的密码hash再进行hash。如果不这么做的话,认证用户的时候,服务端是获取了浏览器传过来的hash跟数据库里的hash比较。这样子看起来是更安全了,因为没有明文密码传送到服务端。但是事实上却不是这样。

问题在于这样的话,如果恶意的黑客获取了用户的hash,就可以直接用来登陆用户的账号了。甚至都不需要知道用户的明文密码!也就不需要破解hash了。

这并不是说你完全不能在浏览器端进行hash。只是如果你要这样做的话,一定要在服务端再hash一次。在浏览器端进行hash是一个不错的想法,但是在实现的时候一定要考虑到以下几点:

1, 客户端密码hash并不是HTTPS(SSL/TLS)的替代品。如果浏览器和服务器之间的连接是不安全的,中间人(man-in-the-middle)可能通过修改网页的加载的javascript移除掉hash函数来得到用户的明文密码。

2, 有些浏览器可能不支持javascript,有些用户也会禁用javascript。为了更好的兼容性,需要检测用户的浏览器是否支持javascript,如果不支持的话就需要在服务端模拟客户端hash的逻辑。

3, 客户端的hash也需要加盐。一个很容想到的方式就是使用客户端脚本请求服务器或得用户的盐。记住,不要使用这种方式。因为这样恶意攻击者就可以通过这个逻辑来判断一个用户名是否有效。因为我们已经在服务端进行了恰当的加盐的hash。所以这里使用用户名跟特定的字符串(比如域名)拼接作为客户端的盐是可以的。

使用慢速hash函数让破解更加困难:

加盐可以让攻击者无法使用查表和彩虹表的方式对大量hash进行破解。但是依然无法避免对单个hash的字典和暴力攻击。高端的显卡(GPUs)和一些定制的硬件每秒可以计算数十亿的hash,所以针对单个hash的攻击依然有效。为了避免字典和暴力攻击,我们可以采用一种称为key扩展(key stretching)的技术。

思路就是让hash的过程便得非常缓慢,即使使用高速GPU和特定的硬件,字典和暴力破解的速度也慢到没有实用价值。通过减慢hash的过程来防御攻击,但是hash速度依然可以保证用户使用的时候没有明显的延迟。

key扩展的实现是使用一种大量消耗cpu资源的hash函数。不要去使用自己创造的迭代hash函数,那是不够的。要使用标准算法的hash函数,比如PBKDF2或者bcrypt。PHP实现可以在这里找到。

这些算法采用了一个安全变量或者迭代次数作为参数。这个值决定了hash的过程具体有多慢。对于桌面软件和手机APP,确定这个参数的最好方式是在设备上运行一个标准测试程序得到hash时间大概在半秒左右的值。这样就可以避免暴力攻击,也不会影响用户体验。

如果是在web应用中使用key扩展hash函数,需要考虑可能有大量的计算资源用来处理用户认证请求。攻击者可能通过这种方式来进行拒绝服务攻击。不过我依然推荐使用key扩展hash函数,只是迭代次数设置的小一点。这个次数需要根据自己服务器的计算能力和预计每秒需要处理的认证请求次数来设置。对于拒绝服务攻击可以通过让用户登陆的时候输入验证码的方式来防御。系统设计的时候一定要考虑到这个迭代次数将来可以方便的增加或降低。

如果你担心计算机的能力不够强,而又希望在自己的web应用中使用key扩展hash函数,可以考虑在用户的浏览器运行hash函数。Stanford JavaScript Crypto Library包含了PBKDF2算法。在浏览器中进行hash需要考虑上面提到的几个方面。

如何安全的存储用户的密码(1)_安全存储

理论上不可能破解的hash:使用加密的key和密码hash硬件

只要攻击者能够验证一个猜测的密码是正确还是错误,他们都可以使用字典或者暴力攻击破解hash。更深度的防御方法是加入一个保密的key(secret key)进行hash,这样只有知道这个key的人才能验证密码是否正确。这个可以通过两种方式来实现。一种是hash通过加密算法加密比如AES,或者使用基于key的hash函数(HMAC)。

这个实现起来并不容易。key一定要做到保密,即使系统被攻破也不能泄露才行。但是如果攻击者获取了系统权限,无论key保存在哪里,都可能被获取到。所以这个key一定要保存在一个外部系统中,比如专门用来进行密码验证的物理隔离的服务器。或是使用安装在服务器上特殊硬件,比如YubiHSM。

强烈建议所有大型的服务(超过10万用户)的公司使用这种方式。对于超过100万用户的服务商一定得采用这种方式保护用户信息。

如果条件不允许使用专用验证的服务器和特殊的硬件,依然从这种方式中受益。大部分数据库泄露都是利用了SQL注入技术。sql注入大部分情况下,攻击者都没法读取服务器上的任意文件(关闭数据库服务器的文件权限)。如果你生成了一个随机的key,把它保存在了一个文件里。并且密码使用了加密key的加盐hash,单单sql注入攻击导致的hash泄露并不会影响用户的密码。虽然这种方式不如使用独立的系统来保存key安全,因为如果系统存在文件包含漏洞的话,攻击者就可能读取这个秘密文件了。不过,使用了加密key总归好过没有使用吧。

需要注意使用key的hash并不是不需要加盐,聪明的攻击者总是会找到办法获取到key的。所以让hash在盐和key扩展的保护下非常重要。

其他的安全措施

密码hash仅仅是在发生安全事故的时候保护密码。它并不能让应用程序更加安全。对于保护用户密码hash更多的是需要保护密码hash不被偷走。

即使经验丰富的程序也需要经过安全培训才能写出安全的应用。一个不错的学习web应用漏洞的资源是OWASP。除非你理解了OWASP Top Ten Vulnerability List,否则不要去写关系到敏感数据的程序。公司有责任确保所有的开发者都经过了足够的安全开发的培训。

通过第三方的渗透测试也是不错的方式。即使最好的程序员也会犯错,所以让安全专家来审计代码总是有意义的。寻找一个可信赖的第三方或者自己招聘一个安全人员来机型定期的代码审计。安全评审要在应用生命周期的早期就开始并且贯穿整个开发过程。

对网站进行入侵监控也十分重要。我建议至少招聘一名全职的安全人员进行入侵检测和安全事件响应。如果入侵没有检测到,攻击者可能让在你的网站上挂马影响你的用户。所以迅速的入侵检测和响应也很重要。

如何安全的存储用户的密码(1)_安全存储

经常提问的问题

我应该使用什么hash算法

可以使用

1, 本文最后介绍的代码

2, OpenWall的Portable PHP password hashing framework

3, 经过充分测试的加密hash函数,比如SHA256, SHA512, RipeMD, WHIRLPOOL, SHA3等

4, 设计良好的key扩展hash算法,比如PBKDF2,bcrypt,scrypt

5, crypt#Library_Function_crypt.283.29)的安全版本。($2y$, $5$, $6$)

不要使用

1, 过时的hash函数,比如MD5,SHA1

2, crypt的不安全版本。($1$, $2$, $2x$, $3$)

3, 任何自己设计的算法。

尽管MD5和SHA1并没有密码学方面的攻击导致它们生成的hash很容易被破解,但是它们年代很古老了,通常都认为(可能有一些不恰当)它们不合适用来进行密码的存储。所以我不推荐使用它们。对于这个规则有个例外就是PBKDF2,它使用SHA1作为它的基础算法。

当用户忘记密码的时候我应该怎样让他们重置

在我个人看来现在外面广泛使用的密码重置机制都是不安全的,如果你有很高的安全需求,比如重要的加密服务,那么不要让用户重置他们的密码。

大多数网站使用绑定的email来进行密码找回。通过生成一个随机的只使用一次的token,这个token必须跟账户绑定,然后把密码重置的链接发送到用户邮箱中。当用户点击密码重置链接的时候,提示他们输入新的密码。需要注意token一定要绑定到用户以免攻击者使用发送给自己的token来修改别人的密码。

token一定要设置成15分钟后或者使用一次后作废。当用户登陆或者请求了一个新的token的时候,之前发送的token都作废也是不错的主意。如果token不失效的话,那么就可以用来永久控制这个账户了。Email(SMTP)是明文传输的协议,而互联网上可能有很多恶意的路由器记录email流量。并且用户的email账号也可能被盗。使token尽可能快的失效可以降低上面提到的这些风险。

用户可能尝试去修改token,所以不要在token里存储任何账户信息。token应该是一个不能被预测的随机的二进制块(binary blob),仅仅用来进行识别的一条记录。

永远不要通过email发送用户的新密码。记得用户重置密码的时候要重新生成盐,不要使用之前旧密码使用的盐。

如果我的用户数据库泄露了,我应该怎么办

第一要做的就是弄明白信息是怎么泄露的,然后把漏洞修补好。

人们可能会想办法掩盖这次安全事件,希望没有人知道。但是,尝试掩盖安全事件会让你的处境变得更糟。因为你不告知你的用户他的信息和密码可能泄露了会给用户带来更大的风险。一定要第一时间通知用户发生了安全事件,即使你还没有完全搞明白黑客到底渗透到了什么程度。在首页上放一个提醒,然后链接到详细说明的页面。如果可能的话给每一个用户发送email提醒。

向你的用户详细的说明他的密码是如何被保护的,希望是加盐的hash,即使密码进行了加盐hash保护,攻击者依然会进行字典和暴力攻击尝试破解hash。攻击者会使用发现的密码尝试登陆其他网站,因为用户可能在不同的网站都使用了相同的密码(所谓的撞库攻击)。告知你的用户存在的这些风险,建议他们修改使用了相同密码的地方。在自己的网站上,下次用户登陆的时候强制他们修改密码。大部分用户可能会尝试使用相同的密码,为了方便。要设计足够的逻辑避免这样的情况发生。

即使有了加盐的hash,攻击者也可能快速破解一些很弱的弱密码。为了降低这种风险,可以在使用正确密码的前提下,加一个邮件认证,直到用户修改密码。

还要告知你的用户有哪些个人信息存储在网站上。如果数据库包含信用卡信息,你需要通知你的用户注意自己近期的账单,并且最好注销掉这个信用卡。

应该使用怎样的密码策略,需要强制使用强密码么

如果你的服务不是有很严格的安全需求,那么不要限制你的用户。我建议在用户输入密码的时候显示它的强度等级。让用户自己决定使用什么强度的密码。如果你的系统有很强的安全需求,那么强制用户使用12位以上的密码,至少包含2个数字,2个字母,2个字符。

每6个月最多强制用户修改一次密码。超过这个次数,用户就会感到疲劳。他们更倾向于选择一个弱密码。更应该做的是教育你的用户,当他们感到自己的密码可能泄露的时候主动修改密码。

如果攻击者获取了数据库权限,他不能直接替换hash登陆任意账户么

当然,不过如果他已经或得了数据库权限,很可能已经可以获得服务器上的所有信息了。所以没有什么必要去修改hash登陆别人账户。进行密码hash的目的不是保护网站不被入侵,而是如果入侵发生了,可以更好的保护用户的密码。

在SQL注入攻击中,保护hash不被替换的方式使用两个用户不同权限的用户连接数据库。一个具有写权限,另外一个只具有只读的权限。

为什么需要一些特别的算法比如HMAC,而不是直接把密码和加密key拼接在一起

(这部分讲一些密码学的原理,翻译的不好请见谅)

hash函数,比如MD5,SHA1,SHA2使用了Merkle–Damgård construction,这导致算法可能长度扩展攻击(length extension attacks)。意思就是说给定一个hash H(X),攻击者可以在不知道X的情况下,可以找到一个H(pad(X)+Y)的值,Y是个其他的字符串。pad(X)是hash函数使用的填充函数(padding function)。

这就意味者,对于hash H(key + message),攻击者可以计算 H(pad(key + message) + extension),并不需要知道加密key。如果这个hash是用在消息认证过程中,使用key为了避免消息被修改。这样的话这个系统就可能失效了,因为攻击者掌握了一个有效的基于 message+extension的hash。

这种攻击对于如何快速破解hash还不是很清楚。但是,基于一些风险的考虑,不建议使用单纯的hash函数进行加密key的hash。也许一个聪明的密码学家一天就可以找到使用这种攻击快速破解hash的方法。所以记得使用HMAC。

盐应该拼在密码的前面还是后面

这个不重要。选择一个并且保持风格一致就行了。实际中,把盐放在前面更常见一点。

为什么本文最后提供的hash代码使用了固定执行时间的函数来比较hash(length-constant)

使用固定的时间来比较hash是为了防止攻击者在线上的系统中使用基于时间差的攻击。这样攻击者就只能线下破解了。

比较两个字符串是否相同,标准的方式是先比较第一个字节,然后比较第二个字节,一次类推。只要发现有一个字节不同,那么这两个字符串就是不同了。可以返回false的消息了。如果所有字节比较下来都一样,那么这两个字符串就是相同的,可以返回true。这就意味了比较两个字符串,如果他们相同的长度不一样,花费的时间不一样。开始部分相同的长度越长,花费的时间也就越长。

基于这个原理,攻击者可以先找256个字符串,他们的hash都是以不同的字节开头。然后发送到目标服务器,计算服务器返回的时间。时间最长的那一个就是第一个字节hash是正确的。依次类推。攻击者就可能得到hash更多的字节。

这种攻击听起来好像在网络上实现起来比较困难。但是已经有人实现过了。所以我们在比较hash的时候采用了花费时间固定的函数。

如何安全的存储用户的密码(1)_安全存储

本文提供的代码中 slowequals 函数是怎么工作的

上一回答讲到了我们需要比较时间固定的函数,这部分详细讲一下代码的实现。

1. private static boolean slowEquals(byte[] a, byte[] b)2. {3. int diff = a.length ^ b.length;4. for(int i = 0; i < a.length && i < b.length; i++)5. diff |= a[i] ^ b[i];6. return diff == 0;7. }

这段代码使用了异或(XOR)操作符”^”来比较整数是否相等,而没有使用”==”操作符。原因在于如果两个数完全一致,异或之后的值为零。因为 0 XOR 0 = 0, 1 XOR 1 = 0, 0 XOR 1 = 1, 1 XOR 0 = 1。

所以,第一行代码如果a.length等于b.length,变量diff等于0,否则的话diff就是一个非零的值。然后,让a,b的每一个字节XOR之后再跟diff OR。这样,只有diff一开始是0,并且,a,b的每一个字节XOR的结果也是零,最后循环完成后diff的值才是0,这种情况是a,b完全一样。否则最后diff是一个非零的值。

我们使用XOR而不适用”==”的原因是”==”通常编译成分支的形式。比如C代码”diff &= a == b” 可能编译成下面的X86汇编。

MOV EAX, [A]CMP [B], EAXJZ equalJMP doneequal:AND [VALID], 1done:AND [VALID], 0

分支会导致代码执行的时间出现差异。

C代码的”diff |= a ^ b”编译之后类似于,

MOV EAX, [A]XOR EAX, [B]OR [DIFF], EAX

执行时间跟两个变量是否相等没有关系。

为什么要讨论这么多关于hash的东西

用户在你的网站上输入密码,是相信你的安全性。如果你的数据库被黑了。而用户密码又没有恰当的保护,那么恶意的攻击者就可以利用这些密码尝试登陆其他的网站和服务。进行撞库攻击。(很多用户在所有的地方都是使用相同的密码)这不仅仅是你的网站安全,是你的所有用户的安全。你要对你用户的安全负责。

如何安全的存储用户的密码(1)_安全存储

PHP PBKDF2 密码hash代码

代码下载

  1. <?php
  2. /*
  3. *PasswordHashingWithPBKDF2().
  4. *Copyright(c)2013,TaylorHornby
  5. *Allrightsreserved.
  6. *
  7. *Redistributionanduseinsourceandbinaryforms,withorwithout
  8. *modification,arepermittedprovidedthatthefollowingconditionsaremet:
  9. *
  10. *1.Redistributionsofsourcecodemustretaintheabovecopyrightnotice,
  11. *thislistofconditionsandthefollowingdisclaimer.
  12. *
  13. *2.Redistributionsinbinaryformmustreproducetheabovecopyrightnotice,
  14. *thislistofconditionsandthefollowingdisclaimerinthedocumentation
  15. *and/orothermaterialsprovidedwiththedistribution.
  16. *
  17. *THISSOFTWAREISPROVIDEDBYTHECOPYRIGHTHOLDERSANDCONTRIBUTORS"ASIS"
  18. *ANDANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE
  19. *IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE
  20. *AREDISCLAIMED.INNOEVENTSHALLTHECOPYRIGHTHOLDERORCONTRIBUTORSBE
  21. *LIABLEFORANYDIRECT,INDIRECT,INCIDENTAL,SPECIAL,EXEMPLARY,OR
  22. *CONSEQUENTIALDAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOF
  23. *SUBSTITUTEGOODSORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESS
  24. *INTERRUPTION)HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERIN
  25. *CONTRACT,STRICTLIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)
  26. *ARISINGINANYWAYOUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISEDOFTHE
  27. *POSSIBILITYOFSUCHDAMAGE.
  28. */
  29. //Theseconstantsmaybechangedwithoutbreakingexistinghashes.
  30. define("PBKDF2_HASH_ALGORITHM","sha256");
  31. define("PBKDF2_ITERATIONS",1000);
  32. define("PBKDF2_SALT_BYTE_SIZE",24);
  33. define("PBKDF2_HASH_BYTE_SIZE",24);
  34. define("HASH_SECTIONS",4);
  35. define("HASH_ALGORITHM_INDEX",0);
  36. define("HASH_ITERATION_INDEX",1);
  37. define("HASH_SALT_INDEX",2);
  38. define("HASH_PBKDF2_INDEX",3);
  39. functioncreate_hash($password)
  40. {
  41. //format:algorithm:iterations:salt:hash
  42. $salt=base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SIZE,MCRYPT_DEV_URANDOM));
  43. returnPBKDF2_HASH_ALGORITHM.":".PBKDF2_ITERATIONS.":".$salt.":".
  44. base64_encode(pbkdf2(
  45. PBKDF2_HASH_ALGORITHM,
  46. $password,
  47. $salt,
  48. PBKDF2_ITERATIONS,
  49. PBKDF2_HASH_BYTE_SIZE,
  50. true
  51. ));
  52. }
  53. functionvalidate_password($password,$correct_hash)
  54. {
  55. $params=explode(":",$correct_hash);
  56. if(count($params)<HASH_SECTIONS)
  57. returnfalse;
  58. $pbkdf2=base64_decode($params[HASH_PBKDF2_INDEX]);
  59. returnslow_equals(
  60. $pbkdf2,
  61. pbkdf2(
  62. $params[HASH_ALGORITHM_INDEX],
  63. $password,
  64. $params[HASH_SALT_INDEX],
  65. (int)$params[HASH_ITERATION_INDEX],
  66. strlen($pbkdf2),
  67. true
  68. )
  69. );
  70. }
  71. //Comparestwostrings$aand$binlength-constanttime.
  72. functionslow_equals($a,$b)
  73. {
  74. $diff=strlen($a)^strlen($b);
  75. for($i=0;$i<strlen($a)&&$i<strlen($b);$i++)
  76. {
  77. $diff|=ord($a[$i])^ord($b[$i]);
  78. }
  79. return$diff===0;
  80. }
  81. /*
  82. *PBKDF2keyderivationfunctionasdefinedbyRSA'sPKCS#5:https://www.ietf.org/rfc/rfc2898.txt
  83. *$algorithm-Thehashalgorithmtouse.Recommended:SHA256
  84. *$password-Thepassword.
  85. *$salt-Asaltthatisuniquetothepassword.
  86. *$count-Iterationcount.Higherisbetter,butslower.Recommended:Atleast1000.
  87. *$key_length-Thelengthofthederivedkeyinbytes.
  88. *$raw_output-Iftrue,thekeyisreturnedinrawbinaryformat.Hexencodedotherwise.
  89. *Returns:A$key_length-bytekeyderivedfromthepasswordandsalt.
  90. *
  91. *Testvectorscanbefoundhere:https://www.ietf.org/rfc/rfc6070.txt
  92. *
  93. *ThisimplementationofPBKDF2wasoriginallycreatedbyhttps://defuse.ca
  94. *Withimprovementsbyhttp://www.variations-of-shadow.com
  95. */
  96. functionpbkdf2($algorithm,$password,$salt,$count,$key_length,$raw_output=false)
  97. {
  98. $algorithm=strtolower($algorithm);
  99. if(!in_array($algorithm,hash_algos(),true))
  100. trigger_error('PBKDF2ERROR:Invalidhashalgorithm.',E_USER_ERROR);
  101. if($count<=0||$key_length<=0)
  102. trigger_error('PBKDF2ERROR:Invalidparameters.',E_USER_ERROR);
  103. if(function_exists("hash_pbkdf2")){
  104. //TheoutputlengthisinNIBBLES(4-bits)if$raw_outputisfalse!
  105. if(!$raw_output){
  106. $key_length=$key_length*2;
  107. }
  108. returnhash_pbkdf2($algorithm,$password,$salt,$count,$key_length,$raw_output);
  109. }
  110. $hash_length=strlen(hash($algorithm,"",true));
  111. $block_count=ceil($key_length/$hash_length);
  112. $output="";
  113. for($i=1;$i<=$block_count;$i++){
  114. //$iencodedas4bytes,bigendian.
  115. $last=$salt.pack("N",$i);
  116. //firstiteration
  117. $last=$xorsum=hash_hmac($algorithm,$last,$password,true);
  118. //performtheother$count-1iterations
  119. for($j=1;$j<$count;$j++){
  120. $xorsum^=($last=hash_hmac($algorithm,$last,$password,true));
  121. }
  122. $output.=$xorsum;
  123. }
  124. if($raw_output)
  125. returnsubstr($output,0,$key_length);
  126. else
  127. returnbin2hex(substr($output,0,$key_length));
  128. }
  129. ?>

如何安全的存储用户的密码(1)_安全存储

java PBKDF2 密码hash代码

代码下载

  1. /*
  2. *PasswordHashingWithPBKDF2().
  3. *Copyright(c)2013,TaylorHornby
  4. *Allrightsreserved.
  5. *
  6. *Redistributionanduseinsourceandbinaryforms,withorwithout
  7. *modification,arepermittedprovidedthatthefollowingconditionsaremet:
  8. *
  9. *1.Redistributionsofsourcecodemustretaintheabovecopyrightnotice,
  10. *thislistofconditionsandthefollowingdisclaimer.
  11. *
  12. *2.Redistributionsinbinaryformmustreproducetheabovecopyrightnotice,
  13. *thislistofconditionsandthefollowingdisclaimerinthedocumentation
  14. *and/orothermaterialsprovidedwiththedistribution.
  15. *
  16. *THISSOFTWAREISPROVIDEDBYTHECOPYRIGHTHOLDERSANDCONTRIBUTORS"ASIS"
  17. *ANDANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE
  18. *IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE
  19. *AREDISCLAIMED.INNOEVENTSHALLTHECOPYRIGHTHOLDERORCONTRIBUTORSBE
  20. *LIABLEFORANYDIRECT,INDIRECT,INCIDENTAL,SPECIAL,EXEMPLARY,OR
  21. *CONSEQUENTIALDAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOF
  22. *SUBSTITUTEGOODSORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESS
  23. *INTERRUPTION)HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERIN
  24. *CONTRACT,STRICTLIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)
  25. *ARISINGINANYWAYOUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISEDOFTHE
  26. *POSSIBILITYOFSUCHDAMAGE.
  27. */
  28. importjava.security.SecureRandom;
  29. importjavax.crypto.spec.PBEKeySpec;
  30. importjavax.crypto.SecretKeyFactory;
  31. importjava.math.BigInteger;
  32. importjava.security.NoSuchAlgorithmException;
  33. importjava.security.spec.InvalidKeySpecException;
  34. /*
  35. *PBKDF2saltedpasswordhashing.
  36. *Author:havocATdefuse.ca
  37. *www:
  38. */
  39. publicclassPasswordHash
  40. {
  41. publicstaticfinalStringPBKDF2_ALGORITHM="PBKDF2WithHmacSHA1";
  42. //Thefollowingconstantsmaybechangedwithoutbreakingexistinghashes.
  43. publicstaticfinalintSALT_BYTE_SIZE=24;
  44. publicstaticfinalintHASH_BYTE_SIZE=24;
  45. publicstaticfinalintPBKDF2_ITERATIONS=1000;
  46. publicstaticfinalintITERATION_INDEX=0;
  47. publicstaticfinalintSALT_INDEX=1;
  48. publicstaticfinalintPBKDF2_INDEX=2;
  49. /**
  50. *ReturnsasaltedPBKDF2hashofthepassword.
  51. *
  52. *@parampasswordthepasswordtohash
  53. *@returnasaltedPBKDF2hashofthepassword
  54. */
  55. publicstaticStringcreateHash(Stringpassword)
  56. throwsNoSuchAlgorithmException,InvalidKeySpecException
  57. {
  58. returncreateHash(password.toCharArray());
  59. }
  60. /**
  61. *ReturnsasaltedPBKDF2hashofthepassword.
  62. *
  63. *@parampasswordthepasswordtohash
  64. *@returnasaltedPBKDF2hashofthepassword
  65. */
  66. publicstaticStringcreateHash(char[]password)
  67. throwsNoSuchAlgorithmException,InvalidKeySpecException
  68. {
  69. //Generatearandomsalt
  70. SecureRandomrandom=newSecureRandom();
  71. byte[]salt=newbyte[SALT_BYTE_SIZE];
  72. random.nextBytes(salt);
  73. //Hashthepassword
  74. byte[]hash=pbkdf2(password,salt,PBKDF2_ITERATIONS,HASH_BYTE_SIZE);
  75. //formatiterations:salt:hash
  76. returnPBKDF2_ITERATIONS+":"+toHex(salt)+":"+toHex(hash);
  77. }
  78. /**
  79. *Validatesapasswordusingahash.
  80. *
  81. *@parampasswordthepasswordtocheck
  82. *@paramcorrectHashthehashofthevalidpassword
  83. *@returntrueifthepasswordiscorrect,falseifnot
  84. */
  85. publicstaticbooleanvalidatePassword(Stringpassword,StringcorrectHash)
  86. throwsNoSuchAlgorithmException,InvalidKeySpecException
  87. {
  88. returnvalidatePassword(password.toCharArray(),correctHash);
  89. }
  90. /**
  91. *Validatesapasswordusingahash.
  92. *
  93. *@parampasswordthepasswordtocheck
  94. *@paramcorrectHashthehashofthevalidpassword
  95. *@returntrueifthepasswordiscorrect,falseifnot
  96. */
  97. publicstaticbooleanvalidatePassword(char[]password,StringcorrectHash)
  98. throwsNoSuchAlgorithmException,InvalidKeySpecException
  99. {
  100. //Decodethehashintoitsparameters
  101. String[]params=correctHash.split(":");
  102. intiterations=Integer.parseInt(params[ITERATION_INDEX]);
  103. byte[]salt=fromHex(params[SALT_INDEX]);
  104. byte[]hash=fromHex(params[PBKDF2_INDEX]);
  105. //Computethehashoftheprovidedpassword,usingthesamesalt,
  106. //iterationcount,andhashlength
  107. byte[]testHash=pbkdf2(password,salt,iterations,hash.length);
  108. //Comparethehashesinconstanttime.Thepasswordiscorrectif
  109. //bothhashesmatch.
  110. returnslowEquals(hash,testHash);
  111. }
  112. /**
  113. *Comparestwobytearraysinlength-constanttime.Thiscomparisonmethod
  114. *isusedsothatpasswordhashescannotbeextractedfromanon-line
  115. *systemusingatimingattackandthenattackedoff-line.
  116. *
  117. *@paramathefirstbytearray
  118. *@parambthesecondbytearray
  119. *@returntrueifbothbytearraysarethesame,falseifnot
  120. */
  121. privatestaticbooleanslowEquals(byte[]a,byte[]b)
  122. {
  123. intdiff=a.length^b.length;
  124. for(inti=0;i<a.length&&i<b.length;i++)
  125. diff|=a[i]^b[i];
  126. returndiff==0;
  127. }
  128. /**
  129. *ComputesthePBKDF2hashofapassword.
  130. *
  131. *@parampasswordthepasswordtohash.
  132. *@paramsaltthesalt
  133. *@paramiterationstheiterationcount(slownessfactor)
  134. *@parambytesthelengthofthehashtocomputeinbytes
  135. *@returnthePBDKF2hashofthepassword
  136. */
  137. privatestaticbyte[]pbkdf2(char[]password,byte[]salt,intiterations,intbytes)
  138. throwsNoSuchAlgorithmException,InvalidKeySpecException
  139. {
  140. PBEKeySpecspec=newPBEKeySpec(password,salt,iterations,bytes*8);
  141. SecretKeyFactoryskf=SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
  142. returnskf.generateSecret(spec).getEncoded();
  143. }
  144. /**
  145. *Convertsastringofhexadecimalcharactersintoabytearray.
  146. *
  147. *@paramhexthehexstring
  148. *@returnthehexstringdecodedintoabytearray
  149. */
  150. privatestaticbyte[]fromHex(Stringhex)
  151. {
  152. byte[]binary=newbyte[hex.length()/2];
  153. for(inti=0;i<binary.length;i++)
  154. {
  155. binary[i]=(byte)Integer.parseInt(hex.substring(2*i,2*i+2),16);
  156. }
  157. returnbinary;
  158. }
  159. /**
  160. *Convertsabytearrayintoahexadecimalstring.
  161. *
  162. *@paramarraythebytearraytoconvert
  163. *@returnalength*2characterstringencodingthebytearray
  164. */
  165. privatestaticStringtoHex(byte[]array)
  166. {
  167. BigIntegerbi=newBigInteger(1,array);
  168. Stringhex=bi.toString(16);
  169. intpaddingLength=(array.length*2)-hex.length();
  170. if(paddingLength>0)
  171. returnString.format("%0"+paddingLength+"d",0)+hex;
  172. else
  173. returnhex;
  174. }
  175. /**
  176. *TeststhebasicfunctionalityofthePasswordHashclass
  177. *
  178. *@paramargsignored
  179. */
  180. publicstaticvoidmain(String[]args)
  181. {
  182. try
  183. {
  184. //Printout10hashes
  185. for(inti=0;i<10;i++)
  186. System.out.println(PasswordHash.createHash("p\r\nassw0Rd!"));
  187. //Testpasswordvalidation
  188. booleanfailure=false;
  189. System.out.println("Runningtests...");
  190. for(inti=0;i<100;i++)
  191. {
  192. Stringpassword=""+i;
  193. Stringhash=createHash(password);
  194. StringsecondHash=createHash(password);
  195. if(hash.equals(secondHash)){
  196. System.out.println("FAILURE:TWOHASHESAREEQUAL!");
  197. failure=true;
  198. }
  199. StringwrongPassword=""+(i+1);
  200. if(validatePassword(wrongPassword,hash)){
  201. System.out.println("FAILURE:WRONGPASSWORDACCEPTED!");
  202. failure=true;
  203. }
  204. if(!validatePassword(password,hash)){
  205. System.out.println("FAILURE:GOODPASSWORDNOTACCEPTED!");
  206. failure=true;
  207. }
  208. }
  209. if(failure)
  210. System.out.println("TESTSFAILED!");
  211. else
  212. System.out.println("TESTSPASSED!");
  213. }
  214. catch(Exceptionex)
  215. {
  216. System.out.println("ERROR:"+ex);
  217. }
  218. }
  219. }

如何安全的存储用户的密码(1)_安全存储

ASP.NET (C#)密码hash代码

代码下载

  1. /*
  2. *PasswordHashingWithPBKDF2().
  3. *Copyright(c)2013,TaylorHornby
  4. *Allrightsreserved.
  5. *
  6. *Redistributionanduseinsourceandbinaryforms,withorwithout
  7. *modification,arepermittedprovidedthatthefollowingconditionsaremet:
  8. *
  9. *1.Redistributionsofsourcecodemustretaintheabovecopyrightnotice,
  10. *thislistofconditionsandthefollowingdisclaimer.
  11. *
  12. *2.Redistributionsinbinaryformmustreproducetheabovecopyrightnotice,
  13. *thislistofconditionsandthefollowingdisclaimerinthedocumentation
  14. *and/orothermaterialsprovidedwiththedistribution.
  15. *
  16. *THISSOFTWAREISPROVIDEDBYTHECOPYRIGHTHOLDERSANDCONTRIBUTORS"ASIS"
  17. *ANDANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE
  18. *IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE
  19. *AREDISCLAIMED.INNOEVENTSHALLTHECOPYRIGHTHOLDERORCONTRIBUTORSBE
  20. *LIABLEFORANYDIRECT,INDIRECT,INCIDENTAL,SPECIAL,EXEMPLARY,OR
  21. *CONSEQUENTIALDAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOF
  22. *SUBSTITUTEGOODSORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESS
  23. *INTERRUPTION)HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERIN
  24. *CONTRACT,STRICTLIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)
  25. *ARISINGINANYWAYOUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISEDOFTHE
  26. *POSSIBILITYOFSUCHDAMAGE.
  27. */
  28. usingSystem;
  29. usingSystem.Text;
  30. usingSystem.Security.Cryptography;
  31. namespacePasswordHash
  32. {
  33. ///<summary>
  34. ///SaltedpasswordhashingwithPBKDF2-SHA1.
  35. ///Author:havocATdefuse.ca
  36. ///www:
  37. ///Compatibility:.NET3.0andlater.
  38. ///</summary>
  39. publicclassPasswordHash
  40. {
  41. //Thefollowingconstantsmaybechangedwithoutbreakingexistinghashes.
  42. publicconstintSALT_BYTE_SIZE=24;
  43. publicconstintHASH_BYTE_SIZE=24;
  44. publicconstintPBKDF2_ITERATIONS=1000;
  45. publicconstintITERATION_INDEX=0;
  46. publicconstintSALT_INDEX=1;
  47. publicconstintPBKDF2_INDEX=2;
  48. ///<summary>
  49. ///CreatesasaltedPBKDF2hashofthepassword.
  50. ///</summary>
  51. ///<paramname="password">Thepasswordtohash.</param>
  52. ///<returns>Thehashofthepassword.</returns>
  53. publicstaticstringCreateHash(stringpassword)
  54. {
  55. //Generatearandomsalt
  56. RNGCryptoServiceProvidercsprng=newRNGCryptoServiceProvider();
  57. byte[]salt=newbyte[SALT_BYTE_SIZE];
  58. csprng.GetBytes(salt);
  59. //Hashthepasswordandencodetheparameters
  60. byte[]hash=PBKDF2(password,salt,PBKDF2_ITERATIONS,HASH_BYTE_SIZE);
  61. returnPBKDF2_ITERATIONS+":"+
  62. Convert.ToBase64String(salt)+":"+
  63. Convert.ToBase64String(hash);
  64. }
  65. ///<summary>
  66. ///Validatesapasswordgivenahashofthecorrectone.
  67. ///</summary>
  68. ///<paramname="password">Thepasswordtocheck.</param>
  69. ///<paramname="correctHash">Ahashofthecorrectpassword.</param>
  70. ///<returns>Trueifthepasswordiscorrect.Falseotherwise.</returns>
  71. publicstaticboolValidatePassword(stringpassword,stringcorrectHash)
  72. {
  73. //Extracttheparametersfromthehash
  74. char[]delimiter={':'};
  75. string[]split=correctHash.Split(delimiter);
  76. intiterations=Int32.Parse(split[ITERATION_INDEX]);
  77. byte[]salt=Convert.FromBase64String(split[SALT_INDEX]);
  78. byte[]hash=Convert.FromBase64String(split[PBKDF2_INDEX]);
  79. byte[]testHash=PBKDF2(password,salt,iterations,hash.Length);
  80. returnSlowEquals(hash,testHash);
  81. }
  82. ///<summary>
  83. ///Comparestwobytearraysinlength-constanttime.Thiscomparison
  84. ///methodisusedsothatpasswordhashescannotbeextractedfrom
  85. ///on-linesystemsusingatimingattackandthenattackedoff-line.
  86. ///</summary>
  87. ///<paramname="a">Thefirstbytearray.</param>
  88. ///<paramname="b">Thesecondbytearray.</param>
  89. ///<returns>Trueifbothbytearraysareequal.Falseotherwise.</returns>
  90. privatestaticboolSlowEquals(byte[]a,byte[]b)
  91. {
  92. uintdiff=(uint)a.Length^(uint)b.Length;
  93. for(inti=0;i<a.Length&&i<b.Length;i++)
  94. diff|=(uint)(a[i]^b[i]);
  95. returndiff==0;
  96. }
  97. ///<summary>
  98. ///ComputesthePBKDF2-SHA1hashofapassword.
  99. ///</summary>
  100. ///<paramname="password">Thepasswordtohash.</param>
  101. ///<paramname="salt">Thesalt.</param>
  102. ///<paramname="iterations">ThePBKDF2iterationcount.</param>
  103. ///<paramname="outputBytes">Thelengthofthehashtogenerate,inbytes.</param>
  104. ///<returns>Ahashofthepassword.</returns>
  105. privatestaticbyte[]PBKDF2(stringpassword,byte[]salt,intiterations,intoutputBytes)
  106. {
  107. Rfc2898DeriveBytespbkdf2=newRfc2898DeriveBytes(password,salt);
  108. pbkdf2.IterationCount=iterations;
  109. returnpbkdf2.GetBytes(outputBytes);
  110. }
  111. }
  112. }

如何安全的存储用户的密码(1)_安全存储

Ruby (on Rails) 密码hash代码

代码下载

  1. #PasswordHashingWithPBKDF2().
  2. #Copyright(c)2013,TaylorHornby
  3. #Allrightsreserved.
  4. #
  5. #Redistributionanduseinsourceandbinaryforms,withorwithout
  6. #modification,arepermittedprovidedthatthefollowingconditionsaremet:
  7. #
  8. #1.Redistributionsofsourcecodemustretaintheabovecopyrightnotice,
  9. #thislistofconditionsandthefollowingdisclaimer.
  10. #
  11. #2.Redistributionsinbinaryformmustreproducetheabovecopyrightnotice,
  12. #thislistofconditionsandthefollowingdisclaimerinthedocumentation
  13. #and/orothermaterialsprovidedwiththedistribution.
  14. #
  15. #THISSOFTWAREISPROVIDEDBYTHECOPYRIGHTHOLDERSANDCONTRIBUTORS"ASIS"
  16. #ANDANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE
  17. #IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE
  18. #AREDISCLAIMED.INNOEVENTSHALLTHECOPYRIGHTHOLDERORCONTRIBUTORSBE
  19. #LIABLEFORANYDIRECT,INDIRECT,INCIDENTAL,SPECIAL,EXEMPLARY,OR
  20. #CONSEQUENTIALDAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOF
  21. #SUBSTITUTEGOODSORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESS
  22. #INTERRUPTION)HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERIN
  23. #CONTRACT,STRICTLIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)
  24. #ARISINGINANYWAYOUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISEDOFTHE
  25. #POSSIBILITYOFSUCHDAMAGE.
  26. require'securerandom'
  27. require'openssl'
  28. require'base64'
  29. #SaltedpasswordhashingwithPBKDF2-SHA1.
  30. #Authors:@RedragonX(dicesoft.net),havocATdefuse.ca
  31. #www:
  32. modulePasswordHash
  33. #Thefollowingconstantscanbechangedwithoutbreakingexistinghashes.
  34. PBKDF2_ITERATIONS=1000
  35. SALT_BYTE_SIZE=24
  36. HASH_BYTE_SIZE=24
  37. HASH_SECTIONS=4
  38. SECTION_DELIMITER=':'
  39. ITERATIONS_INDEX=1
  40. SALT_INDEX=2
  41. HASH_INDEX=3
  42. #ReturnsasaltedPBKDF2hashofthepassword.
  43. defself.createHash(password)
  44. salt=SecureRandom.base64(SALT_BYTE_SIZE)
  45. pbkdf2=OpenSSL::PKCS5::pbkdf2_hmac_sha1(
  46. password,
  47. salt,
  48. PBKDF2_ITERATIONS,
  49. HASH_BYTE_SIZE
  50. )
  51. return["sha1",PBKDF2_ITERATIONS,salt,Base64.encode64(pbkdf2)].join(SECTION_DELIMITER)
  52. end
  53. #Checksifapasswordiscorrectgivenahashofthecorrectone.
  54. #correctHashmustbeahashstringgeneratedwithcreateHash.
  55. defself.validatePassword(password,correctHash)
  56. params=correctHash.split(SECTION_DELIMITER)
  57. returnfalseifparams.length!=HASH_SECTIONS
  58. pbkdf2=Base64.decode64(params[HASH_INDEX])
  59. testHash=OpenSSL::PKCS5::pbkdf2_hmac_sha1(
  60. password,
  61. params[SALT_INDEX],
  62. params[ITERATIONS_INDEX].to_i,
  63. pbkdf2.length
  64. )
  65. returnpbkdf2==testHash
  66. end
  67. #Runteststoensurethemoduleisfunctioningproperly.
  68. #Returnstrueifalltestssucceed,falseifnot.
  69. defself.runSelfTests
  70. puts"Samplehashes:"
  71. 3.times{putscreateHash("password")}
  72. puts"\nRunningselftests..."
  73. @@allPass=true
  74. correctPassword='aaaaaaaaaa'
  75. wrongPassword='aaaaaaaaab'
  76. hash=createHash(correctPassword)
  77. assert(validatePassword(correctPassword,hash)==true,"correctpassword")
  78. assert(validatePassword(wrongPassword,hash)==false,"wrongpassword")
  79. h1=hash.split(SECTION_DELIMITER)
  80. h2=createHash(correctPassword).split(SECTION_DELIMITER)
  81. assert(h1[HASH_INDEX]!=h2[HASH_INDEX],"differenthashes")
  82. assert(h1[SALT_INDEX]!=h2[SALT_INDEX],"differentsalt")
  83. if@@allPass
  84. puts"***ALLTESTSPASS***"
  85. else
  86. puts"***FAILURES***"
  87. end
  88. return@@allPass
  89. end
  90. defself.assert(truth,msg)
  91. iftruth
  92. puts"PASS[#{msg}]"
  93. else
  94. puts"FAIL[#{msg}]"
  95. @@allPass=false
  96. end
  97. end
  98. end
  99. PasswordHash.runSelfTests

原文地址:#salt

四 : 电脑密码如何清除 快速清除电脑密码的几种方法介绍

 网管员在维护和使用电脑时,经常会遇到各种密码丢失的问题,这里,我们就为广大网管员准备了一些破解密码的方法,但是希望大家不要干坏事哦。开机密码是我们最先要遇到的因此我们就先从CMOS密码破解讲起。虽然CMOS种类各异,但它们的加密方法却基本一致。一般破解的方法主要从"硬"和"软"两个方面来进行。
  一、CMOS破解
  使用电脑,首先需要开机。因此开机密码是我们最先要遇到的。虽然CMOS种类各异,但它们的加密方法却基本一致。一般破解的方法主要从"硬"和"软"两个方面来进行。
  1."硬"解除方法
  硬件方法解除CMOS密码原理是将主板上的CMOSRAM进行放电处理,使存储在CMOSRAM中的参数得不到正常的供电导致内容丢失,从而起到解除CMOS密码的目的。一些报刊对如何破解CMOS密码的通常做法,如跳线短接法和电池短接法已有较多介绍,操作起来也十分方便。但我们这里要介绍的是个另类技巧,这也是一些电脑DIY们很喜欢用的方法。方法也很简单:打开机箱,将硬盘或光驱、软驱的数据线从主板上拔掉,然后再启动计算机,BIOS会在自检时报告错误并自动进入CMOS,此时就可以重新设置BIOS内容了。
  2."软"解除方法
  严格地说,"软"解除CMOS密码没有"硬"解除方法那么彻底,但也十分奏效。CMOS密码根据需要,可设为普通级用户密码和超级用户级密码两种。前者只是限制对BIOS的修改,可以正常启动电脑和运行各类软件,而后者则对进入电脑和BIOS完全禁止。
  1) 破解普通用户密码
  首先用DOS启动盘启动电脑,进入DOS状态,在DOS命令行输入debug回车,然后用所列的其中任何一种方法的数据解除CMOS密码,重新启动电脑,系统会告诉你CMOS参数丢失,要求你重新设定CMOS参数。经过试验,这是一种很有效的方法。"-"后面的字母"O",表示数值输出的地址,70和10都是数值。
  2) 破解超级用户密码
  这里我们需借助外部工具。我们选用最为经典的BiosPwds,是一款免费软件,比较适合对DOS不太熟悉的电脑用户,很久以前就为人们所熟知,只要轻轻一点,就会将用户的CMOS密码显示出来。工具最新版本1.21,127KB,免费下载地址:。下载解压后,双击该软件的执行文件,在出现的界面中点击"Getpasswords"按钮,稍等二、三秒即会将BIOS各项信息显示于BiosPwds的界面上,包括:Bios版本、Bios日期、使用密码等,这时你便可以很轻松地得知BIOS密码。
  二、破解系统密码
  系统密码是你登录到操作系统时所使用到的密码,它为你的计算机提供了一种安全保护,可以使你的计算机免受非法用户的使用,从而保障电脑和机密数据的安全。
  1. Windows98/ME的系统登录密码
  ① 取消法
  最简单的一种方法是在系统登录要求输入密码时,你什么也不用输入,直接点击取消,可以进入操作系统。但用此种方法只能访问本机的资源,如果计算机是局域网的一部分,你将不能访问网络资源。
  ② 新增使用者
  当你由于密码问题被挡在系统之外时,不妨为系统再新增一个使用者,然后重新登录,一样可以登录系统并访问系统或网络资源。单击"开始"/"设置"/"控制面板",然后双击"用户",打开"用户属性"对话框。接着,根据提示依次输入"用户名"、"密码"、"个性化项目设置"中所需的内容,最后单击"完成"。
  ③ 删除"PWL"文件
  删除Windows安装目录下的}.PWL密码文件和Profiles子目录下的所有个人信息文件,然后重新启动Windows,系统就会弹出一个不包含任何用户名的密码设置框,我们无需输入任何内容,直接点击"确定"按钮,Windows密码即被删除。
  ④ 修改注册表
  运行注册表编辑器,打开注册表数据库"HKEY_LOCAL_MACHINENetworkLogon"分支下的"username"修改为"0",然后重新启动系统,也可达到去掉密码的目的。
  2. 破解WindowsNT密码
  如果你有普通用户账号,有一个很简单的方法获取NTAdministrator账号:先把c:winntsystem32下的logon.scr改名为logon.old备份,然后把usrm瞘r.exe改名为logon.scr再重新启动。logon.scr是系统启动时加载的程序,重新启动后,不会出现以往的登录密码输入界面,而是用户管理器,这时你就有权限把自己加到Administrator组。
  3. Windows2000密码
  启动盘启动电脑或引导进入另一操作系统(如Windows98),找到文件夹"X:DocumentsandSettingsAdministrator"(X为Windows2000所在磁盘的盘符),将此文件夹下的"Cookies"文件夹删除,然后重新启动电脑,即可以空密码快速登录Windows2000。
  4. 破解WindowsXP的密码
  在启动WindowsXP时按F8键选择带命令行的安全模式,使用net命令可以对用户身份进行操作。具体步骤如下:使用命令"netuserabcd/add"添加一名为abcd的用户,使用命令"netlocalgroupadministratorsabcd/add"将用户abcd提升为管理员,重新启动电脑,用abcd身份登录,最后对遗忘密码的用户进行密码修改即可。
  三、破解几个常用软件密码
  目前,更多的用户懂得了利用电脑软件对自己的一些储存在电脑中的信息进行加密操作,使无权阅读的人无法轻松打开这些重要资料。下面就让我们一块看一下几个常用软件密码的解除:
  1. 破解WPS系列密码
  如果你是合法用户,在忘却密码时,启动WPS程序,点击"文件"/"密码设置"菜单,在出现的密码设置对话框中可以看到原密码会自动以"}}}"号的方式出现在"密码"文本框中,点击"清除"按钮,再在随后出现的提示框中点击"确认"按钮,该加密文件的密码已经被清除了。以后再次打开该文件就不再需要输入密码了。如果你不是合法用户就只能借助有关工具进行破解。现在破解WPS密码的软件很多,但论其功能强大,破解速度快就要数国产的Edward’sWPS2000PasswordRecovery了。该工具破解WPS密码采用的是破解密码的常见的方法———穷举法。使用步骤如下:首先,在程序界面中的"En瞔ryptedWPS2000file"的文本框中通过右侧的"浏览"按钮加入需破解的WPS加密文件;然后选择密码破解方法,该软件有以下几种密码破解方式:Brute-force(强力攻击)、Dictionary(字典攻击)、mask(掩码搜索)等等,一般选用"Brute-force"(强力破解)法;接着在"Brute—forceRangeOptions"列表框中选择破解密码可能包含的密码范围,例如:大小写字母、数字、是否有空格、特殊字符等;此外还要指定密码长度,如6位或更长;最后,当上述几项设置完毕后,请点击"RUN"选项,密码很快得以破解。
  2. 破解Word文档密码
  可能是微软的Office太引人注目了,针对它的破解软件非常多。下面先让我们来看看如何破解它的文档密码。我们选用一款国产的软件"97/2000/XP密码查看器",这是一款仅有29KB大小的微型简体中文的Word密码解除软件。此软件无需安装,双击可执行文件即可。该工具可以破解Win瞕ows9X/NT/2000/XP全系列的文档密码,可以查找最多13位的密码(未注册版只支持3位),使用"字典式"穷举法破解。使用时在程序中点击"文件"/"打开"命令加入需破解文档;在"任务属性"中设置密码类型,建议将几个选项全部选中;填写密码长度;点击"确定"返回主界面,选择"操作"/"开始破解命令即可进行密码破解。

五 : 如何清除网页上自动保存的登陆用户名密码

本文将图文并茂教您如何清除网页上自动保存登陆的用户名密码。
每次进入一个新网站,要输入用户名和密码时,系统总会提示,是否需要记住密码以方便下一次登陆,有时候一时不慎点了“是”,这要是普通网站就无所谓了,要是邮箱之类的包含隐私内容的地方,就有点麻烦了,谁要是用了你的电脑,但凡把用户名的第一个字母输入对了,这密码可就出来了,怎么办?不急,“Internet选项”能搞定!点击IE右上角的工具按钮,在菜单中选择“Internet选项”


在“Internet选项”中选择“内容”标签,在“自动完成”栏点击“设置”


在“自动完成设置”窗口中不要勾选“表单上的用户名和密码”,以后就再也不会自动保存我们的密码了


对于我们已经点了保存的密码怎么办?“Internet选项”也可以清除!在“Internet选项”中的“常规”标签下“浏览历史记录”栏中选择“删除”


勾选“密码”项,点击“删除”,现在好了,所有记录就都没了!(正如你所见,通过这里还可以删除Internet临时文件、Cookie、历史记录、表单数据等等)

本文标题:如何清除用户名和密码-我是大智慧新一代的收费用户,我如何知道我的用户名和密码?由于现在?
本文地址: http://www.61k.com/1074911.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1