出于信息保密的目的,在信息传输或存储中,采用密码技术对需要保密的信息进行处理,使得处理后的信息不能被非受权者(含非法者)读懂或解读,这一过程称为加密。在加密处理过程中,需要保密的信息称为“明文”,经加密处理后的信息称为“密文”。
加密即是将“明文”变为“密文”的过程;与此类似,将“密文”变为“明文”的过程被称为解密。
常规的 http 请求,所有信息都是明文传输的,只要中间人在链路中的任意阶段进行劫持,就会带来三大风险:
窃听风险(eavesdropping):第三方可以获知通信内容。
篡改风险(tampering):第三方可以修改通信内容。
冒充风险(pretending):第三方可以冒充他人身份参与通信。
解决以上问题,可以使用 https。https 信息的安全,完全建立在证书可信的基础上,那如果中间人伪造证书怎么办?
黑客自己伪造的证书需要客户端验证通过,才可以继续访问,只要客户端验证通过,那么公钥A,私钥B和私钥C对黑客来说都是透明的,也有没有数据安全可言了,所以黑客只要诱导用户安装自己伪造的证书即可,例如使用各种钓鱼的不可描述网站。
所以即使使用 https 传输明文密码,也不是绝对安全的。那怎么样才能保证密码安全呢?
我们看一下乐述云享的登录方式:
这应该能明显看得出来密码是加密过的。
可以看一下这个请求:
?
这意味着,该登陆密码是使用 RSA 进行加密和解密处理的,而这个请求就是公钥。
从登录页面的网络请求中,我们可以看到使用的是 jsencrypt.js 这个库对数据进行RSA公钥加密。这确保了数据在到达服务器之前就保持了机密性。
RSA 是目前最有影响力的公钥加密算法之一,它能够抵抗到目前为止已知的绝大多数密码攻击,已被 ISO 组织推荐为公钥数据加密标准。
那接下来,我们来看一下如何使用 jsencrypt.js 对用户密码进行加密。
首先需要加载 jsencrypt.js 脚本文件。
CDN加载推荐:https://www.bootcdn.cn/jsencrypt/
前端JS加密方法:
var encrypt = new JSEncrypt();
var pubKey = '此处为公钥';
encrypt.setPublicKey(pubKey);
var rsaContent = encrypt.encrypt('需要加密的内容');
在服务器端需要使用 PHP 将获取的密钥进行解密:
$privateKey = '
此处为私钥
';
$privateID = openssl_pkey_get_private($privateKey);
$cryptText = base64_decode('前端发来的加密内容');
if(openssl_private_decrypt($cryptText, $sourceStr, $privateID, OPENSSL_PKCS1_PADDING)) {
$unCryptedContent = $sourceStr; // 此为解密成功后的内容
}else{
die('解密失败');
}
账号密码的存储也是有说法的,为了确保密码的安全,绝对不能选择明文存储,以下是一些可供参考的加密方案:
使用 MD5、SHA 等加密算法:
此种加密方法我们称之为单向Hash算法,攻击者可以通过彩虹表与加密后的密码对比,来获取用户的原始密码,彩虹表就是肝出来的一张表(通过收集用户常用密码,形成一张表,再使用 MD5、SHA 等加密算法,计算出常用密码加密后的内容,与常用密码一一对应存储,这张表就是彩虹表)
密码加盐:
密码加盐指的是取一个随机值(每一个用户拥有一个 salt)与用户密码组合后再进行加密。这种方式可以在一定程度上增加破解难度,对于加了“固定盐”的HASH算法,需要保护“盐”不能泄露,这就会遇到“保护对称密钥”一样的问题,一旦“盐”泄露,根据“盐”重新建立彩虹表可以进行破解,对于多次HASH,也只是增加了破解的时间,并没有本质上的提升。
对称加密:
比如3DES、AES等算法,使用这种方式加密是可以通过解密来还原出原始密码的,当然前提条件是需要获取到密钥。不过既然大量的用户信息已经泄露了,密钥很可能也会泄露,当然可以将一般数据和密钥分开存储、分开管理,但要完全保护好密钥也是一件非常复杂的事情,所以这种方式并不是很好的方式。
非对称加密:
对称加密算法在加密和解密时使用的是同一个密钥。与对称加密算法不同的是,非对称加密算法需要两个密钥——公开密钥和私有密钥进行加密和解密。RSA 是目前最有影响力的公钥加密算法之一,它能够抵抗到目前为止已知的绝大多数密码攻击,已被 ISO 组织推荐为公钥数据加密标准。
注意:虽然加密方式较多,但是在密码加密上,还是使用一些成熟的方案吧,以免搞砸。
乐述云享存储密码的方案是采用 phpass 来生成用于存储的密码,这个类库是用 bcrypt 算法对密码进行哈系的算法。这种方式生成的密码是随机且不可逆的,同一个明文的密码在不同时间,产生的密文也不一样,相对来说较为安全。
phpass 是一个可在PHP应用程序中使用的可移植公共域密码哈希框架 。
官方:https://www.openwall.com/phpass/
示例代码:
<?php
// 引入 phpass 库
require_once('PasswordHash.php')
// 初始化散列器为不可移植(这样更安全)
$hasher = new PasswordHash(8, false);
// 计算密码的哈希值。$hashedPassword 是一个长度为 60 个字符的字符串.
$hashedPassword = $hasher->HashPassword('123456');
// 你现在可以安全地将 $hashedPassword 保存到数据库中!
// 通过echo $hashedPassword;你会发现每次输出的加密后的值不一样,
// 所以当用户登录时不能直接用用户输入的密码加密后的值和数据库中存储的值进行比较判断。
// 需要调用CheckPassword方法比较用户输入内容(产生的哈希值)和我们之前计算出的哈希值,
// 来判断用户是否输入了正确的密码
$hasher->CheckPassword('001234', $hashedPassword); // false
$hasher->CheckPassword('123456', $hashedPassword); // true
... ...