A. hash破解 有什么用
你应该也网络过,hash是微软存储密码的一种计算方式,也就是所谓的加密方式。当然这种计算方式并非唯一的,有很多种加密方式,一般的系统的加密采用的是lm跟nthash,两者一个是7+7的大写转化,另外一个是128字节的加密方式,,,,我说的不好,你可以另外网络确认,简单点说,你破解了hash也就得到了密码。跟使用者一样的密码,这样你就可以使用它的身份做操作了。
B. 哈希表、哈希算法、一致性哈希表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。它通过把关键码映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数(哈希函数),存放记录的数组叫做散列表。
优点:
哈希表可以提供快速的操作。
缺点:
哈希表通常是基于数组的,数组创建后难于扩展。
也没有一种简便的方法可以以任何一种顺序〔例如从小到大)遍历表中的数据项 。
综上, 如果不需要有序遍历数据,井且可以提前预测数据量的大小。那么哈希表在速度和易用性方面是无与伦比的。
1. 使用哈希函数将被查找的键转换为数组的索引。
2. 处理哈希碰撞冲突。
若关键字为 k ,则其值存放在 f(k) 的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系 f 为散列函数,按这个思想建立的表为散列表。
若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为 均匀散列函数 (Uniform Hash function),这就是使关键字经过散列函数得到一个"随机的地址",从而减少碰撞。
散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位。
一个好的散列函数一般应该考虑下列因素 :
1.计算简单,以便提高转换速度。
2.关键词对应的地址空间分布均匀,以尽量减少冲突。
1. 直接寻址法
取关键字或者关键字的某个线性函数值作为哈希地址,即H(Key)=Key或者H(Key)=a*Key+b(a,b为整数),这种散列函数也叫做自身函数.如果H(Key)的哈希地址上已经有值了,那么就往下一个位置找,直到找到H(Key)的位置没有值了就把元素放进去。
2. 数字分析法
数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。
3. 平方取中法
取关键字平方后的中间几位作为散列地址。这种方法的原理是通过取平方扩大差别,平方值的中间几位和这个数的每一位都相关,则对不同的关键字得到的哈希函数值不易产生冲突,由此产生的哈希地址也较为均匀。该方法适用于关键字中的每一位都有某些数字重复出现频度很高的现象。
4. 折叠法
折叠法是将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(注意:叠加和时去除进位)作为散列地址。
数位叠加可以有移位叠加和间界叠加两种方法。移位叠加是将分割后的每一部分的最低位对齐,然后相加;间界叠加是从一端向另一端沿分割界来回折叠,然后对齐相加。
该方法适用于关键字特别多的情况。
5. 随机数法
选择一个随机数,作为散列地址,通常用于关键字长度不同的场合。
6. 除留余数法
取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址.即H(Key)=Key MOD p,p<=m.不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选得不好,则很容易产生冲突。
对不同的关键字可能得到同一散列地址,即 k1≠k2 ,而 f(k1)=f(k2) ,这种现象称为碰撞(英语:Collision)。具有相同函数值的关键字对该散列函数来说称做同义词。
通过构造性能良好的散列函数,可以减少冲突,但一般不可能完全避免冲突,因此解决冲突是哈希法的另一个关键问题。 创建哈希表和查找哈希表都会遇到冲突,两种情况下解决冲突的方法应该一致。
下面以创建哈希表为例,说明解决冲突的方法。
1.开放寻址法
这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式:Hi=(H(key)+di)%m i=1,2,…,m-1,其中H(key)为哈希函数,m 为表长,di称为增量序列,i为碰撞次数。增量序列的取值方式不同,相应的再散列方式也不同。增量序列主要有以下几种:
(1) 线性探测再散列
di=1,2,3,…,m-1
这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。
(2)二次探测再散列
di=12,-12,22,-22,…,k2,-k2( k<=m/2 )
这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。
(3)伪随机探测再散列
di=伪随机数序列。
线性探测再散列的 优点 是:只要哈希表不满,就一定能找到一个不冲突的哈希地址,而二次探测再散列和伪随机探测再散列则不一定。线性探测再散列容易产生“二次聚集”,即在处理同义词的冲突时又导致非同义词的冲突。
其实除了上面的几种方法,开放寻址法还有很多变种,不过都是对di有不同的表示方法。(如双散列探测法:di=i*h2(k))
2.再哈希法
这种方法是同时构造多个不同的哈希函数:Hi=RHi(key),i=1,2,3,…,n。
当哈希地址H1=RH1(key)发生冲突时,再计算H2=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。
3.链地址法(拉链法)
这种方法的基本思想是将所有哈希地址相同的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表(数组)中,因而查找、插入和删除主要在同义词链中进行。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。链地址法适用于经常进行插入和删除的情况。
拉链法的优点
与开放寻址法相比,拉链法有如下几个优点:
(1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
(2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
(3)开放寻址法为减少冲突,要求装填因子α较小,故当结点规模较大时会浪费很多空间。而拉链法中理论上可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;(散列表的装填因子定义为:α= 填入表中的元素个数 / 散列表的长度)
注:HashMap默认装填因子是0.75。
(4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。而对开放寻址法构造的散列表,删除结点不能简单地将被删结点的空间置为空,否则将截断在它之后填入散列表的同义词结点的查找路径。这是因为各种开放寻址法中,空地址单元都被理解没有查找到元素。 因此在用开放寻址法处理冲突的散列表上执行删除操作,只能在被删结点上做删除标记,而不能真正删除结点。
拉链法的缺点
拉链法的缺点是:指针需要额外的空间,故当结点规模较小时,开放寻址法较为节省空间,此时将节省的指针空间用来扩大散列表的规模,可使装填因子变小,这又减少了开放寻址法中的冲突,从而提高平均查找速度。
4、建立公共溢出区
这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表(在这个方法里面是把元素分开两个表来存储)。
散列表的查找过程基本上和造表过程相同。一些关键码可通过散列函数转换的地址直接找到,另一些关键码在散列函数得到的地址上产生了冲突,需要按处理冲突的方法进行查找。在介绍的三种处理冲突的方法中,产生冲突后的查找仍然是给定值与关键码进行比较的过程。所以,对散列表查找效率的量度,依然用平均查找长度来衡量。
查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。
影响产生冲突多少有以下三个因素:
1. 散列函数是否均匀;
2. 处理冲突的方法;
3. 散列表的装填因子。
散列表的装填因子
定义为:α= 填入表中的元素个数 / 散列表的长度
α是散列表装满程度的标志因子。由于表长是定值,α与"填入表中的元素个数"成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。
实际上,散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数。
这个HASH算法不是大学里数据结构课里那个HASH表的算法。这里的HASH算法是密码学的基础,了解了hash基本定义,就不能不提到一些着名的hash算法,MD5 和 SHA-1 可以说是目前应用最广泛的Hash算法,而它们都是以 MD4 为基础设计的。
Hash算法在信息安全方面的应用主要体现在以下的3个方面:
⑴ 文件校验
我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗 数据篡改 的能力,它们一定程度上能检测出数据传输中的信道误码,但却不能防止对数据的恶意破坏。
MD5 Hash算法的"数字指纹"特性,使它成为目前应用最广泛的一种文件完整性 校验和 (Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。
⑵ 数字签名
Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在 数字签名 协议中,单向散列函数扮演了一个重要的角色。对 Hash 值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点。
⑶ 鉴权协议
如下的鉴权协议又被称作挑战--认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。
一致性哈希表简称DHT,主要应用于分布式缓存中,可以用来解决分布式存储结构下动态增加和删除节点所带来的问题。比如,一个分布式的存储系统,要将数据存储到具体的节点上,如果采用普通的hash方法,将数据映射到具体的节点上,如key%N(key是数据的key,N是机器节点数),如果有一个机器加入或退出这个集群,则所有的数据映射都无效了,如果是持久化存储则要做数据迁移,如果是分布式缓存,则其他缓存就失效了。
判定哈希算法好坏的四个定义 :
1、平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。
2、单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
3、分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。 分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
4、负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同的内容。与分散性一样,这种情况也是应当避免的, 因此好的哈希算法应能够尽量降低缓冲的负荷。
在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash取模算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。接下来主要说明一下一致性哈希算法是如何设计的。
以SpyMemcached的ketama算法来说,思路是这样的:
把数据用hash函数,映射到一个很大的空间里,如图所示。数据的存储时,先得到一个hash值,对应到这个环中的每个位置,如k1对应到了图中所示的位置,然后沿顺时针找到一个机器节点B,将k1存储到B这个节点中。
如果B节点宕机了,则B上的数据就会落到C节点上,如下图所示:
这样,只会影响C节点,对其他的节点A,D的数据不会造成影响。然而,这又会造成一个“雪崩”的情况,即C节点由于承担了B节点的数据,所以C节点的负载会变高,C节点很容易也宕机,这样依次下去,这样造成整个集群都挂了。
为此,引入了“虚拟节点”的概念:即把想象在这个环上有很多“虚拟节点”,数据的存储是沿着环的顺时针方向找一个虚拟节点,每个虚拟节点都会关联到一个真实节点,如下图所使用:
图中的A1、A2、B1、B2、C1、C2、D1、D2都是虚拟节点,机器A负载存储A1、A2的数据,机器B负载存储B1、B2的数据,机器C负载存储C1、C2的数据。由于这些虚拟节点数量很多,均匀分布,因此不会造成“雪崩”现象。
C. 哈希算法的原理
什么是哈希算法?哈希是一种加密算法,也称为散列函数或杂凑函数。哈希函数是一个公开函数,可以将任意长度的消息M映射成为一个长度较短且长度固定的值H(M),称H(M)为哈希值、散列值(Hash Value)、杂凑值或者消息摘要。它是一种单向密码体制,即一个从明文到密文的不可逆映射,只有加密过程,没有解密过程。
Hash的特点
易压缩:对于任意大小的输入x,Hash值的长度很小,在实际应用中,函数H产生的Hash值其长度是固定的。
易计算:对于任意给定的消息,计算其Hash值比较容易。
单向性:对于给定的Hash值,要找到使得在计算上是不可行的,即求Hash的逆很困难。在给定某个哈希函数H和哈希值H(M)的情况下,得出M在计算上是不可行的。即从哈希输出无法倒推输入的原始数值。这是哈希函数安全性的基础。
抗碰撞性:理想的Hash函数是无碰撞的,但在实际算法的设计中很难做到这一点。
有两种抗碰撞性:一种是弱抗碰撞性,即对于给定的消息,要发现另一个消息,满足在计算上是不可行的;另一种是强抗碰撞性,即对于任意一对不同的消息,使得在计算上也是不可行的。
高灵敏性:这是从比特位角度出发的,指的是1比特位的输入变化会造成1/2的比特位发生变化。消息M的任何改变都会导致哈希值H(M)发生改变。即如果输入有微小不同,哈希运算后的输出一定不同。
D. 十大常见密码加密方式
一、密钥散列
采用MD5或者SHA1等散列算法,对明文进行加密。严格来说,MD5不算一种加密算法,而是一种摘要算法。无论多长的输入,MD5都会输出一个128位(16字节)的散列值。而SHA1也是流行的消息摘要算法,它可以生成一个被称为消息摘要的160位(20字节)散列值。MD5相对SHA1来说,安全性较低,但是速度快;SHA1和MD5相比安全性高,但是速度慢。
二、对称加密
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密。对称加密算法中常用的算法有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK等。
三、非对称加密
非对称加密算法是一种密钥的保密方法,它需要两个密钥来进行加密和解密,这两个密钥是公开密钥和私有密钥。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。非对称加密算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。
四、数字签名
数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是在使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。
五、直接明文保存
早期很多这样的做法,比如用户设置的密码是“123”,直接就将“123”保存到数据库中,这种是最简单的保存方式,也是最不安全的方式。但实际上不少互联网公司,都可能采取的是这种方式。
六、使用MD5、SHA1等单向HASH算法保护密码
使用这些算法后,无法通过计算还原出原始密码,而且实现比较简单,因此很多互联网公司都采用这种方式保存用户密码,曾经这种方式也是比较安全的方式,但随着彩虹表技术的兴起,可以建立彩虹表进行查表破解,目前这种方式已经很不安全了。
七、特殊的单向HASH算法
由于单向HASH算法在保护密码方面不再安全,于是有些公司在单向HASH算法基础上进行了加盐、多次HASH等扩展,这些方式可以在一定程度上增加破解难度,对于加了“固定盐”的HASH算法,需要保护“盐”不能泄露,这就会遇到“保护对称密钥”一样的问题,一旦“盐”泄露,根据“盐”重新建立彩虹表可以进行破解,对于多次HASH,也只是增加了破解的时间,并没有本质上的提升。
八、PBKDF2
该算法原理大致相当于在HASH算法基础上增加随机盐,并进行多次HASH运算,随机盐使得彩虹表的建表难度大幅增加,而多次HASH也使得建表和破解的难度都大幅增加。
九、BCrypt
BCrypt 在1999年就产生了,并且在对抗 GPU/ASIC 方面要优于 PBKDF2,但是我还是不建议你在新系统中使用它,因为它在离线破解的威胁模型分析中表现并不突出。
十、SCrypt
SCrypt 在如今是一个更好的选择:比 BCrypt设计得更好(尤其是关于内存方面)并且已经在该领域工作了 10 年。另一方面,它也被用于许多加密货币,并且我们有一些硬件(包括 FPGA 和 ASIC)能实现它。 尽管它们专门用于采矿,也可以将其重新用于破解。
E. 如何安全的存储密码
大多数的web开发者都会遇到设计用户账号系统的需求。账号系统最重要的一个方面就是如何保护用户的密码。一些大公司的用户数据库泄露事件也时有发生,所以我们必须采取一些措施来保护用户的密码,即使网站被攻破的情况下也不会造成较大的危害。如果你还在存储用户密码的MD5,那可真的有点弱了。赶紧来看看这篇文章吧。
保护密码最好的的方式就是使用带盐的密码hash(salted password hashing).对密码进行hash操作是一件很简单的事情,但是很多人都犯了错。接下来我希望可以详细的阐述如何恰当的对密码进行hash,以及为什么要这样做。
重要提醒
如果你打算自己写一段代码来进行密码hash,那么赶紧停下吧。这样太容易犯错了。这个提醒适用于每一个人,不要自己写密码的hash算法 !关于保存密码的问题已经有了成熟的方案,那就是使用phpass或者本文提供的源码。
什么是hash
hash("hello") =
hash("hbllo") =
hash("waltz") = 算法是一种单向的函数。它可以把任意数量的数据转换成固定长度的“指纹”,这个过程是不可逆的。而且只要输入发生改变,哪怕只有一个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还是远远达不到我们的安全需求。
F. hash是什么意思
是用来加密的一种方式文件校验
我们比较熟悉的校验算法有奇偶校验和CRC校验,这2种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正数据传输中的信道误码,但却不能防止对数据的恶意破坏。
MD5 Hash算法的"数字指纹"特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。
数字签名
Hash 算法也是现代密码体系中的一个重要组成部分。由于非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色。 对 Hash 值,又称"数字摘要"进行数字签名,在统计上可以认为与对文件本身进行数字签名是等效的。而且这样的协议还有其他的优点。
鉴权协议
如下的鉴权协议又被称作"挑战--认证模式:在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。
以上就是一些关于hash以及其相关的一些基本预备知识。那么在emule里面他具体起到什么作用呢?
参考资料:www.hash.com.cn
G. 密码学HASH与对称加密
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
MD5信息摘要算法 (英语:MD5 Message-Digest Algorithm),一种被广泛使用的 密码散列函数 ,可以产生出一个128位(16 字节 )的散列值(hash value),用于确保信息传输完整一致。2004年,证实MD5算法无法防止碰撞(collision)(如网站: CMD5 ),因此不适用于安全性认证,如 SSL 公开密钥认证或是 数字签名 等用途。
MD5 是哈希算法的一种。
密码加密常见的有以下几种方式:
HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写,并在 IPSec 和其他网络协议(如 SSL )中得以广泛应用,现在已经成为事实上的Internet安全标准。它可以与任何迭代散列函数捆绑使用。
如上图中,共有两个流程:
授权设备登录流程:
1、输入账号过后,就把账号作为参数向服务器发送请求
2、服务器根据账号生成对应的key,并传递给客户端
3、客户端拿到key,进行HMAC运算,并将运算结果的哈希值传给服务器
其他设备登录流程:
1、输入账号过后,在本地缓存中找服务器传过来的key,有就登录,没有就把账号作为参数向服务器发送请求
2、服务器要先看这个账号是否开启了设备锁,没有开启就不允许登录,开启了,就向授权设备发送请求,是否授权,如果授权,就将这个账号的key传给其他客户端
3、客户端拿到key,进行HMAC运算,并将运算结果的哈希值传给服务器
但是在这之中有一个潜在的安全隐患问题: 当别人拿到账号和传递的哈希值过后,也就能拿到登录权限,从而不安全。
为了防止上面的问题,注册流程不变,服务器还是保存的有加了key的HMAC哈希值。
1、只是登录的时候,客户端将哈希值与时间戳拼接过后,进行MD5加密,再传给服务器。
2、服务器将注册保存的账号对应的HMAC哈希值,分别与当前时间,和前一分钟拼接再MD5加密,再和客户端传过来的进行匹配,匹配成功则登录成功,否则不成功。
3、注意这里的时间戳是服务器给的时间戳。
常见的加密算法:
应用模式:
AES加密解密都是用到的CCCrypt函数,并且需要导入 CommonCrypto 框架。
H. Windows系统中用户的密码采用什么Hash算法有什么区别
NTLMhash和Net-NTLMhash
区别:1、NTLMhash通常是指Windows系统下SecurityAccountManager中保存的用户密码hash,该hash的生成方法:将明文口令转换成十六进制的格式,转换成Unicode格式,即在每个字节之后添加0x00,对Unicode字符串作MD4加密,生成32位的十六进制数字串。2、Net-NTLMhash,通过是指网络环境下NTLM认证中的hash。
I. 如何安全的存储用户的密码
保护密码最好的的方式就是使用带盐的密码hash(salted password hashing).对密码进行hash操作是一件很简单的事情,但是很多人都犯了错。接下来我希望可以详细的阐述如何恰当的对密码进行hash,以及为什么要这样做。
重要提醒
如果你打算自己写一段代码来进行密码hash,那么赶紧停下吧。这样太容易犯错了。这个提醒适用于每一个人,不要自己写密码的hash算法 !关于保存密码的问题已经有了成熟的方案,那就是使用phpass或者本文提供的源码。
什么是hash
hash("hello") =
hash("hbllo") =
hash("waltz") =
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,获取明文常见的手段。
如何破解hash
字典和暴力破解攻击(Dictionary and Brute Force Attacks)
最常见的破解hash手段就是猜测密码。然后对每一个可能的密码进行hash,对比需要破解的hash和猜测的密码hash值,如果两个值一样,那么之前猜测的密码就是正确的密码明文。猜测密码攻击常用的方式就是字典攻击和暴力攻击。
Dictionary Attack
Trying apple : failed
Trying blueberry : failed
Trying justinbeiber : failed
...
Trying letmein : failed
Trying s3cr3t : success!
字典攻击是将常用的密码,单词,短语和其他可能用来做密码的字符串放到一个文件中,然后对文件中的每一个词进行hash,将这些hash与需要破解的密码hash比较。这种方式的成功率取决于密码字典的大小以及字典的是否合适。
Brute Force Attack
Trying aaaa : failed
Trying aaab : failed
Trying aaac : failed
...
Trying acdb : failed
Trying acdc : success!
暴力攻击就是对于给定的密码长度,尝试每一种可能的字符组合。这种方式需要花费大量的计算机时间。但是理论上只要时间足够,最后密码一定能够破解出来。只是如果密码太长,破解花费的时间就会大到无法承受。
目前没有方式可以阻止字典攻击和暴力攻击。只能想办法让它们变的低效。如果你的密码hash系统设计的是安全的,那么破解hash唯一的方式就是进行字典或者暴力攻击了。
查表破解(Lookup Tables)
对于特定的hash类型,如果需要破解大量hash的话,查表是一种非常有效而且快速的方式。它的理念就是预先计算(pre-compute)出密码字典中每一个密码的hash。然后把hash和对应的密码保存在一个表里。一个设计良好的查询表结构,即使存储了数十亿个hash,每秒钟仍然可以查询成百上千个hash。
如果你想感受下查表破解hash的话可以尝试一下在CraskStation上破解下下面的sha256 hash。
反向查表破解(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。
加盐(Adding Salt)
hash("hello") =
hash("hello" + "QxLUF1bgIAdeQX") =
hash("hello" + "bv5PehSMfV11Cd") =
hash("hello" + "YYLmfY6IehjZMQ") =
查表和彩虹表的方式之所以有效是因为每一个密码的都是通过同样的方式来进行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个字节的随机数据。
错误的方式:双重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等是更好的选择。
正确的方式:如何恰当的进行hash
这部分会详细讨论如何恰当的进行密码hash。第一个章节是最基础的,这章节的内容是必须的。后面一个章节是阐述如何继续增强安全性,让hash破解变得异常困难。
基础:使用加盐hash
我们已经知道恶意黑客可以通过查表和彩虹表的方式快速的获得hash对应的明文密码,我们也知道了通过使用随机的盐可以解决这个问题。但是我们怎么生成盐,怎么在hash的过程中使用盐呢?
盐要使用密码学上可靠安全的伪随机数生成器(Cryptographically Secure Pseudo-Random Number Generator (CSPRNG))来产生。CSPRNG跟普通的伪随机数生成器比如C语言中的rand(),有很大不同。正如它的名字说明的那样,CSPRNG提供一个高标准的随机数,是完全无法预测的。我们不希望我们的盐能够被预测到,所以一定要使用CSPRNG。