PHP与密码安全

在这里插入图片描述

加密密码

一般在存储用户密码之前应该先对密码进行加密(如使用MD5、SHA等算法),然后将其存储在数据库中。

用MD5加密密码的代码如下:

<?php
	$password = $_POST['password'];
	echo md5($password);
?>

用SHA1加密密码的代码如下:

<?php
	$password = $_POST['password'];
	echo sha1($password);
?>
有一些攻击者将用户常用的密码总结 出来,再使用这些加密算法得出其加密后的值,
将加密后的值和原始密码保存起来,形成一张可通过密码对原文进行反查的数据表,称其为彩虹表。
攻击者只需要用彩虹表与加密后的密码比对,就能得到用户的原始密码。

不建议使用dex和MD5等弱加密算法对密码等敏感信息进行加密,散列算法推荐使用SHA256或SHA512。

<?php
	$password = $_POST['password'];
	echo hash("sha256",$password);
?>

PHP内置了hash()函数,只需要将加密方式传给hash()函数,直接指明使用SHA256、SHA512等加密方式即可。

密码加盐

使用盐(salt)来混淆加密后的值。可以加大攻击者直接从字典密码库中碰撞除用户密码的难度。如果所有
用户的salt一样,且混淆方式已知,那么攻击者依然可以针对常见密码与salt混合生成一张具有针对性的彩虹表

为了加大安全系数,应该采用随机salt,每次写入用户的密码时(注册或修改密码),随机生成一个salt(一个随机字符),并将salt与密码混合(可以是各种混合方式,而不仅仅限于将两个连接在一起),再进行散列计算。这样即使攻击者拥有了彩虹表,也不能立即猜测出哪些散列值对应哪些常规的密码,因为即使用户输入常规密码,但其混合了salt的散列值与原密码已经不一样了。

使用加盐方式对加密用户密码的代码如下:

<?php
	$password = $_POST['password'];
	$salt = rand(1,10000);
	$password = sha1($password.$salt);
?>

然而在salt对于不同用户各异的情况下,也难以对所有用户生成一张彩虹表。但攻击者依然可以针对某一个用户,使用暴力穷举的方式来破译密码。如果用户的密码长度较短且全是数字,再加上若使用的salt过于简单,而MD5、SHA等算法由于本身特性使得加密过程比较快,就很容易被破解。

可以增加普通MD5等快速算法的迭代次生成复杂的salt,或者使用mcrypt这样更为复杂的加密算法,迫使攻击者再暴力破解的时候需要更长的时间。由于将加密算法控制在微妙即可给攻击者的破译带来打击,而同时单个用户登入验证的耗时又不算太长,这种方法可以有效地解决攻击者破译密码的危险。

多次加密的代码如下:

<?php

$password = MD5($_POST['password']);
$salt = MD5(rand(1,10000));
$password = sha1($password.$salt);

?>

生成较长、较复杂的随机salt的代码如下:

<?php

$password = $_POST['password''];
$salt = base64_encode(mcrypt_create_iv(32,MCRYPT_DEV_RANDOM);
$password = sha1($password.$salt);

?>

使用password_hash()函数,指定第二个参数为PASSWORD_BCRYPT进行加密密码的代码如下:

$password = password_hash($password,PASSWORD_BCRYPT);

除了以上方式外,还可以用自己的方式对字符串进行混淆,创造更为复杂的密码加密方式

<?php

if (defined("CRYPT_BLOWFISH") && (CRYPT_BLOWFISH){
	$salt = '$2y$11$' . substr(md5(uniqid(rand(), true)), 0, 22);
	echo crypt($password, $salt);
}

?>

bcrypt其实就是blowfish和crypt()函数的结合。通过CRYPT_BLOWFISH判断blowfish是否可用,然后生成一个salt。不过这里需要注意的是,crypt()的salt必须$2a$或者$2y$开头

blowfish是区块加密算法中的对称加密的一种
crypt()函数返回使用DES、blowfish或MD5等算法加密的字符串。在不同的操作系统上,该函数的行为不同,某些操作系统支持一种以上的算法类型。

防止暴力破解

暴力破解(Brute-force Attract)又称为穷举破解,是一种密码的破译方式,即将密码进行逐个尝试知道找出真正的密码为止。

常见的防御方法有以下几种

(1)使用验证码进行验证登入
(2)使用Token生成form_hash,然后验证
(3)使用随机数时,要确保用户无法获取随机数生成算法。
(4)身份验证需要用户凭短信、邮件接受验证码时,需要对验证次数进行限制
(5)限制某时间段内验证此数
(6)用户在设置密码时要求用户使用特殊字符和字母数字组合,并限制最小长度

随机数安全

随机数与密码一样,防止被预测,在各类业务场景中必不可少。随机数有真随机数和伪随机数之分。

真随机数使用真随机数发生器(TRNG)生成,是利用不可预知的物理方式来产生的随机数,例如掷钱币、骰子、转轮,使用电子元件的噪声、核裂变等。

伪随机数使用伪随机发生器(PRNG)生成,是计算机利用一定的算法或种子来产生的。计算机中生成的都是伪随机数,其中伪随机又分为强伪随机数(难以预测的随机数)和若伪随机数(易于预测的随机数)。

项目中通常用随机数的场景有密码salt生成、验证码生成、Token生成、UUID生成、密钥生成、数字签名生成、加密向量生成、Nonce生成等 。

加密向量(IV或SV)是一个固定长度地输入值,使用随机数产生地初始向量才能达到语义安全,并让攻击者难以对同一把密钥地的密文进行破解。在区块加密中,使用了初始向量的加密模式称为区块加密模式
Nonce是Number once的缩写,在密码学中Nonce是一个只被使用一次的任意或非重复的随机数值。

不正确地使用随机数会导致一系列地安全问题。

(1)在研发过程中使用时间戳作为随机数[MD5(时间戳),MD5(用户ID+时间戳)],但是由于时间戳是可以
	预测的,因此很容易被破解。
(2)生成密码用的slat以及找回密码时的Token,需要一个随机数,如果直接根据用户ID生成Token,很容易
	被攻击者猜解。
(3)OAuth2.0中需要第三方传递一个state参数作为CSRF Token来防止CSRF攻击,很多研发人员根本不适用
	这个参数,或者时传入一个固定的值。由于认证方无法对这个值进行业务层面的有效性校验,导致了OAuth的CSRF攻击。
(4)在抽奖程序中如果使用的随机数不均匀或者可猜解,可直接造成奖品损失。
(5)PHP5在Windows操作系统下调用rand()函数的时候会发生随机数不均匀的情况,其他操作系统不会有这
	样的情况。PHP提供了另一个高质量、非常好的随机数发生器mt_rand(),在涉及项目安全的时候可选用
	这个函数。

数字摘要

数字摘要也称作数字签名,是将任意长度的消息变成固定长度的短消息。它是一个单向的、不可逆转的加密方法、一般采用单项Hash函数将需要加密大的明文“摘要”成一串固定长度的密文,这一串密文又称为数字指纹,它有固定的长度,而且不同的明文摘要成密文结果总是不同的,而同样的明文摘要必定一致。数字摘要常用于互联网上传输的信息加密认证,进行防篡改识别

常用的数字摘要算法又MD5和SHA等。

消息摘要算法第五版(Message Digest Algorithm MD5,MD5)是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。MD5被广泛用于数字摘要,是因为对原数据进行任何改动,哪怕只修改一个字节,所得到的MD5值都有很大区别。并且,已知原数据和其MD5值,要找到一个具有相同MD5值得数据(即伪造数据)是非常困难的。

MAC和HMAC简介

消息认证码(Message Authentication Code ,MAC)在发送消息的基础上通过KEY生成加密摘要,通常被用于检测消息在传输过程中是否被篡改。MAC消息认证过程如图:
在这里插入图片描述

消息认证中,消息的发送方通过密钥和MAC算发生成MAC数据标记,然后将消息和MAC标签发送到接收方。消息接收方依次使用相同的密钥通过相同的MAC算法生成的MAC标签进行比较。如果它们相同,则接受方可以认为消息在传输期间未发生改变或篡改。

同时。为了防止重放攻击,消息本身必须包含确保相同仅能被发送一次的数据,例如使用时间戳
、序列号或使用一次MAC。

散列消息身份验证码(Hashed Message Authentication Code,HMAC)是在MAC算法基础上加密散列算法实现的。

使用hash_hmac()函数来使用MD5方式给原始消息生成散列值

<?php
	echo hash_hmac('ma5','LEO学PHP','php_secret_key');
?>

如果需要给文件生成散列值,可使用hash_hmac_file()函数,在下面的例子中使用SHA256算法生成散列值。

<?php
	echo hash_hmac('sha256','/tmp/LEO学PHP.pdf','php_secret_key');
?>

对称加密

对称加密算法是指 ,数据发信方将明文(原始数据)和密钥一起经过加密处理后,是其变成复杂的加密密文发送出去。收信方收到密文后,若要解读原文,则需要使用加密密钥及相同算法的逆算法对密文进行解读,使其恢复成可读明文。对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高,适用于加密大量数据的场合。常用的算法有DES,3DES,TDEA,Blowfish,RC2,RC4,RC5,IDEA,SKIPJACK,AES等。

PHP中如果需要使用对称加密算法,则需要mcrypt扩展的支持。PHP的mcrypt扩展提供了强大的加密解密方法。具体可以通过函数mcrypt_list_algorithms()和mcrypt_list+modes()来显示。

<pre>
<?php
	$type_list = mcrypt_list_algorithms();	//mcrypt支持的加密算法列表
	$mode_list = mcrypt_list_modes();	//mcrypt支持的加密模式列表
	print_r($type_list);
	print_r($mode_list);
?>
</pre>

在这里插入图片描述

使用DES方式加密的代码如下:

<?php 

$auth_key = 'safe_key';
$salt = '!@#$%';
$content = 'Hello World';
$td = mcrypt_module_open(mcrypt_des,'','ecb','');	//使用mcrypt_des算法ecb模式

$iv_size = mcrypt_enc_get_iv_size($td);	//设置初始向量大小
$iv = mcrypt_create_iv($iv_size,mcrypt_rand);	//创建初始向量
$key_size = mcrypt_enc_get_key_size($td);	//返回所支持的最大密钥长度(以字节计算)

$key = substr(md5($auth_key.salt),0,$key_size);
mcrypt_generic_init($td, $key, $iv);	//初始化
$secret = mcrypt_generic($td, $content);	//加密并返回加密后的内容
echo base64_encode($secret);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);	//结束

 ?>

在这里插入图片描述

使用DES方式解密的代码如下:

<?php 

$auth_key = 'safe_key';
$salt = '!@#$%';
$secret = 'Rr6TE6b1+XXiPkJnFUOuMw==';
$td = mcrypt_module_open(mcrypt_des,'','ecb','');	//使用mcrypt_des算法ecb模式

$iv_size = mcrypt_enc_get_iv_size($td);	//设置初始向量大小
$iv = mcrypt_create_iv($iv_size,mcrypt_rand);	//创建初始向量
$key_size = mcrypt_enc_get_key_size($td);	//返回所支持的最大密钥长度(以字节计算)

$key = substr(md5($auth_key.salt),0,$key_size);
mcrypt_generic_init($td, $key, $iv);	//初始化
$content = mdecrypt_generic($td, base64_decode($secret));	//解密并返回内容
echo $content;
mcrypt_generic_deinit($td);
mcrypt_module_close($td);	//结束

 ?>

在这里插入图片描述

AES是Advanced Enctyption Standard(高级加密标准)的缩写,在密码学中又称Rijindael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
AES目前有五种加密模式:

(1)电码本模式
(2)密码分组链接模式
(3)计数模式
(4)密码反馈模式
(5)输出反馈模式

在PHP中mcrypt扩展中,rijndael-128、rijndael-192、rijndael-256就是AES加密,三种分别使用不同的数据块和密钥长度进行加密。

在AES的ECB模式中,一般是16字节为一块,然后对这一整块进行加密,如果输入的字符串不够16字节,就需要补位。

在AES的CBC加密模式中,需要添加初始化向量(IV),zhi6默认是16个0.由于是分组加密,因此下一组的IV就用前一组的加密的密文来充当。CFB、OFB模式类似,只不过更复杂,破解难度更大。

非对称加密

对称加密算法在加密和解密时使用的是同一个密钥。与对称加密算法不同,非对称加密算法需要两个密钥——公开密钥(public key,公钥)和私有密钥(private key,私钥)进行加密和解密。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密;如果用私钥对数据进行加密,那么只有对应的公钥才能解密。

在非对称加密中使用的主要算法有RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等,RSA是目前最有影响力的公钥加密算法之一,它能抵抗到目前为zhi已知的绝大多数密码攻击。

生成私钥
openssl genrsa -out rsa_private_key.pem 1024
生成公钥
openssl rsa -in rsa_private_key.pem -pubout-out rsa_public_key.pem
<?php 

$private_key_file = "rsa_private_key.pem";
$public_key_file = "rsa_public_key.pem";
$data = "Hello World";
if (file_exists($private_key_file)){
	$private_key_file = file_get_contents($private_key_file);
}
else{
	die('private key not exists');
}

if (file_exists($public_key_file)){
	$public_key = file_get_contents($public_key_file);
}
else{
	die('public key not exists');
}

$encrypted = $decrypted = "";
openssl_private_encrypt($data, $encrypted, $private_key);	//使用私钥加密数据
openssl_public_decrypt($encrypted, $decrypted, $public_key);
//使用公钥界面
echo $decrypted;
$encrypted = $decrypted = "";
openssl_public_encrypt($data, $encrypted, $public_key);//使用公钥进行加密
openssl_private_decrypt($data, $decrypted, $public_key);	//使用私钥进行加密
echo $decrypted;

 ?>

小结

重点概述了各种加密方式的项目应用场景,在使用密码的过程中的安全问题。根据业务场景不同,选择正确的加密方式,保证用户信息安全。

发布了71 篇原创文章 · 获赞 3 · 访问量 4044

猜你喜欢

转载自blog.csdn.net/zouchengzhi1021/article/details/105341373