前言
PHP加密方式分為單項(xiàng)散列加密,對(duì)稱加密,非對(duì)稱加密這幾類。像常用的MD5、hash、crypt、sha1這種就是單項(xiàng)散列加密,單項(xiàng)散列加密是不可逆的。像URL編碼、base64編碼這種就是對(duì)稱加密,是可逆的,就是說加密解密都是用的同一秘鑰。除此外就是非對(duì)稱加密,加密和解密的秘鑰不是同一個(gè),如果從安全性而言,加密的信息如果還想著再解密回來,非對(duì)稱加密無疑是最為安全的方式。
MD5加密
md5加密算法在PHP中是最常見的加密算法,這個(gè)算法是不可逆的,通常用于加密用戶的密碼等信息來保證用戶的信息安全。來自 RFC 1321 的解釋 - MD5 報(bào)文摘要算法:MD5 報(bào)文摘要算法將任意長度的信息作為輸入值,并將其換算成一個(gè) 128 位長度的"指紋信息"或"報(bào)文摘要"值來代表這個(gè)輸入值,并以換算后的值作為結(jié)果。MD5 算法主要是為數(shù)字簽名應(yīng)用程序而設(shè)計(jì)的;在這個(gè)數(shù)字簽名應(yīng)用程序中,較大的文件將在加密(這里的加密過程是通過在一個(gè)密碼系統(tǒng)下[如:RSA]的公開密鑰下設(shè)置私有密鑰而完成的)之前以一種安全的方式進(jìn)行壓縮。好,來舉個(gè)例子
<?php
//這里是一個(gè)字符串
$str="this is zifuchuan";
//通過MD5加密函數(shù)加密
$res=md5($str);//在PHP中,MD5()函數(shù)還有第二個(gè)參數(shù),為bool類型,當(dāng)為TRUE是返回的加密是16字符原始//二進(jìn)制格式字符串,當(dāng)為FALSE是返回32位的16進(jìn)制,默認(rèn)為false,一般都默認(rèn)//返回二進(jìn)制
$res=md5($str,true);
?>
Crypt()加密算法
crypt()加密算法是一種不可逆的加密算法,他有兩個(gè)參數(shù),一個(gè)是需要加密的字符串,另外一個(gè)是鹽值(或者成為干擾字符串),如果沒有指定第二個(gè)參數(shù)那么將自己隨機(jī)生成一個(gè)干擾字符串并且是以MD5加密的方式。另外這個(gè)函數(shù)在不同的操作系統(tǒng)上的表現(xiàn)形式也是不一樣的,會(huì)自動(dòng)檢測。舉個(gè)例子。
<?php
//需要加密的字符串
$str="this is string";
//使用crypt加密,不指定鹽值
$res=crypt($str);//指定鹽值,但是鹽值只能寫兩位,如果超過了則只會(huì)取前兩位,在某些系統(tǒng)中會(huì)直接返回FALSE
$res=crypt($str,'jm');
?>
sha1加密算法
sha1加密算法和MD5加密算法一樣時(shí)不可逆的,有兩個(gè)參數(shù),一個(gè)是要加密的字符串,第二個(gè)是bool值,如果指定第二個(gè)參數(shù)為TRUE,則返回二進(jìn)制格式的字符串,如果不指定則默認(rèn)為FALSE,返回的是40位的16進(jìn)制格式的字符串,舉個(gè)例子
<?php
//需要加密的字符串
$str="this is string";
//通過sha1進(jìn)行加密
$res=sha1($str);
//通過指定第二個(gè)參數(shù)加密
$res=sha1($str,true);
?>
URL編碼加密
對(duì)于我們的網(wǎng)站,直接暴露給用戶的就是地址欄的傳參,對(duì)于這一部分都是明文的,所以我們可以使用基本的加密算法來簡單加密一下,注意,此種方式加密是可逆的,也就是說加密后的密文我們可以解密之后看到,所以如果你想實(shí)現(xiàn)真正的加密,并不推薦這個(gè)加密算法。
在PHP中對(duì)于URL加密解密用到兩個(gè)函數(shù)urlencode和urldecode.
我們就可以對(duì)這段地址進(jìn)行加密
<?php
//需要加密的網(wǎng)址
$str = "http://www.guojiadong.com?name=guojiadong&phone=112";
//使用urlencode加密
$res = urlencode($str);
//使用urldecode解密
$result = urldecode($res);
?>
既然通過這種方式加密解密并且加密之后也并沒有什么太大的區(qū)別,我們需要他的目的是什么呢?我們想對(duì)于想破解這串加密的字符串可以輕松的破解,其實(shí)這兩個(gè)函數(shù)有他特殊的作用,也就是說除了加密的作用,當(dāng)然了這是題外話,因?yàn)楸局黝}主要是加密,但是作為擴(kuò)展還是要說一下。
<?php
//在HTML傳參到后臺(tái)中的時(shí)候如果我們想把&作為參數(shù)傳到后臺(tái),在沒有加密之前,瀏覽器會(huì)把他作為
//參數(shù)分隔符
//例如:http://guojiadong.com?name=guojiadong&123,
我們想把guojiadong&123作為參數(shù)傳給
//后臺(tái),這個(gè)時(shí)候直接這樣寫后臺(tái)得到的數(shù)據(jù)卻只得到name的值為guojiadong,而123確作為變量
//當(dāng)然了用一個(gè)數(shù)字做變量是不合法的,但是瀏覽器確并不這么智能的區(qū)分他
//為了解決這個(gè)問題我們就可以對(duì)這部分字符編碼
$str="http://guojiadong.com?name=".urlencode('guojiadong&123');
//這樣我們傳過來的值就變成了name = guojiadong&123
?>
Base64編碼加密
大家注意,雖然base64寫到本節(jié)加密算法中,但是他并不是主要用來加密的,而且從大多數(shù)的程序來說,幾乎沒有人會(huì)用他作為加密手段來加密數(shù)據(jù),那么他的作用主要是用于做什么呢?這要說的base64加密的機(jī)制了。
base64加密本質(zhì)上說就是把數(shù)據(jù)轉(zhuǎn)換為ASCLL碼,比如一個(gè)圖片進(jìn)行base64編碼就會(huì)變成一堆以Ascll碼連接的字符串,這會(huì)更有利于文件的傳輸,當(dāng)然base64的作用在與文件的傳輸。例如手機(jī)客戶端上傳文件到服務(wù)器,使用base64編碼可以輕松實(shí)現(xiàn)文件的傳輸。
base64加密函數(shù)
base64_encode($data);
base64解密函數(shù)
base64_decode($data);
hash加密
hash加密也是不可逆的,因?yàn)槭墙o定一個(gè)不確定的字符串返回特定長度的字符串,這個(gè)本質(zhì)意義上來說實(shí)現(xiàn)了單項(xiàng)散列加密。使用方法
hash($ago,$data);
$ago是可以指定加密使用的哈希算法,例如:"md5","sha256","haval160,4" 等。
$data是要加密的數(shù)據(jù)
Password Hashing API 加密
Password Hashing API是PHP 5.5之后才有的新特性,它主要是提供下面幾個(gè)函數(shù)供我們使用:
password_hash() – 對(duì)密碼加密.
password_verify() – 驗(yàn)證已經(jīng)加密的密碼,檢驗(yàn)其hash字串是否一致.
password_needs_rehash() – 給密碼重新加密.
password_get_info() – 返回加密算法的名稱和一些相關(guān)信息.
雖然說crypt()函數(shù)在使用上已足夠,但是password_hash()不僅可以使我們的代碼更加簡短,而且還在安全方面給了我們更好的保障,所以,現(xiàn)在PHP的官方都是推薦這種方式來加密用戶的密碼,很多流行的框架比如Laravel就是用的這種加密方式。
$hash = password_hash($passwod, PASSWORD_DEFAULT);
對(duì),就是這么簡單,一行代碼,All done。
PASSWORD_DEFAULT目前使用的就是Bcrypt,所以在上面我會(huì)說推薦這個(gè),不過因?yàn)镻assword Hashing API做得更好了,我必須鄭重地想你推薦Password Hashing API。這里需要注意的是,如果你代碼使用的都是PASSWORD_DEFAULT加密方式,那么在數(shù)據(jù)庫的表中,password字段就得設(shè)置超過60個(gè)字符長度,你也可以使用PASSWORD_BCRYPT,這個(gè)時(shí)候,加密后字串總是60個(gè)字符長度。
這里使用password_hash()你完全可以不提供鹽值(salt)和 消耗值 (cost),你可以將后者理解為一種性能的消耗值,cost越大,加密算法越復(fù)雜,消耗的內(nèi)存也就越大。當(dāng)然,如果你需要指定對(duì)應(yīng)的鹽值和消耗值,你可以這樣寫:
$options = [
'salt' => custom_function_for_salt(), //write your own code to generate a suitable salt
'cost' => 12 // the default cost is 10 ];
$hash = password_hash($password, PASSWORD_DEFAULT, $options);
密碼加密過后,我們需要對(duì)密碼進(jìn)行驗(yàn)證,以此來判斷用戶輸入的密碼是否正確:
if (password_verify($password, $hash)) {
// Pass }
else {
// Invalid
}
很簡單的吧,直接使用password_verify就可以對(duì)我們之前加密過的字符串(存在數(shù)據(jù)庫中)進(jìn)行驗(yàn)證了。
然而,如果有時(shí)候我們需要更改我們的加密方式,如某一天我們突然想更換一下鹽值或者提高一下消耗值,我們這時(shí)候就要使用到password_needs_rehash()函數(shù)了:
if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12])) {
// cost change to 12 $hash = password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]);
// don't forget to store the new hash!
}
只有這樣,PHP的Password Hashing API才會(huì)知道我們重現(xiàn)更換了加密方式,這樣的主要目的就是為了后面的密碼驗(yàn)證。
簡單地說一下password_get_info(),這個(gè)函數(shù)一般可以看到下面三個(gè)信息:
algo – 算法實(shí)例
algoName – 算法名字
options – 加密時(shí)候的可選參數(shù)