http://pan.baidu.com/s/1jHGXpGE 主流的高加密方案phpass
1. MD5加密
不需要引入任何文件,但是容易被破解,對於安全要求高的程序不能只用md5加密。
/**
* MD5加密操作
* @param string $str 原始字符串
* @param bool $raw_output 可選 被設置爲 TRUE,以16字節長度的原始二進制格式返回,不進行加密。
* @return string 返回加密後的字符串
*/
string md5 ( string $str [, bool $raw_output = false ] )
這是一種不可逆加密,執行如下的代碼
$password = '123456';
echo md5($password);
得到結果是e10adc3949ba59abbe56e057f20f883e
2. Crype加密
/**
* Crype加密操作
* @param string $str 原始字符串
* @param string $salt 可選的鹽值字符串。如果沒有提供,算法行爲將由不同的算法實現決定,並可能導致不可預料的結束。
* @return string 返回一個基於標準 UNIX DES 算法或系統上其他可用的替代算法的散列字符串。
*/
string crypt ( string $str [, string $salt ] )
這是也一種不可逆加密,執行如下的代碼
$password = '123456';
$salt = "test";// 只取前兩個
echo crypt($password, $salt);
得到的結果是teMGKvBPcptKo
使用自動鹽值的例子如下:
$password = crypt('mypassword'); // 自動生成鹽值
/* 你應當使用 crypt() 得到的完整結果作爲鹽值進行密碼校驗,以此來避免使用不同散列算法導致的問題。(如上所述,基於標準 DES 算法的密碼散列使用 2 字符鹽值,但是基於 MD5 算法的散列使用 12 個字符鹽值。)*/
if (crypt('mypassword', $password) == $password) {
echo "Password verified!";
}
執行結果是輸出 Password verified!
以不同散列類型使用 crypt()的例子如下:
if (CRYPT_STD_DES == 1) {
echo 'Standard DES: ' . crypt('rasmuslerdorf', 'rl') . "\n";
}
if (CRYPT_EXT_DES == 1) {
echo 'Extended DES: ' . crypt('rasmuslerdorf', '_J9..rasm') . "\n";
}
if (CRYPT_MD5 == 1) {
echo 'MD5: ' . crypt('rasmuslerdorf', '$1$rasmusle$') . "\n";
}
if (CRYPT_BLOWFISH == 1) {
echo 'Blowfish: ' . crypt('rasmuslerdorf', '$2a$07$usesomesillystringforsalt$') . "\n";
}
if (CRYPT_SHA256 == 1) {
echo 'SHA-256: ' . crypt('rasmuslerdorf', '$5$rounds=5000$usesomesillystringforsalt$') . "\n";
}
if (CRYPT_SHA512 == 1) {
echo 'SHA-512: ' . crypt('rasmuslerdorf', '$6$rounds=5000$usesomesillystringforsalt$') . "\n";
}
其結果如下
Standard DES: rl.3StKT.4T8M
Extended DES: _J9..rasmBYk8r9AiWNc
MD5:
SHA-256:
SHA-512:
在 crypt() 函數支持多重散列的系統上,下面的常量根據相應的類型是否可用被設置爲 0 或 1:
CRYPT_STD_DES – 基於標準 DES 算法的散列使用 “./0-9A-Za-z” 字符中的兩個字符作爲鹽值。在鹽值中使用非法的字符將導致 crypt() 失敗。
CRYPT_MD5 – MD5 散列使用一個以
CRYPT_BLOWFISH – Blowfish 算法使用如下鹽值:“
CRYPT_SHA256 – SHA-256 算法使用一個以
CRYPT_SHA512 – SHA-512 算法使用一個以
3. SHA1加密
/**
* Crype加密操作
* @param string $str 原始字符串
* @param string $raw_output 如果可選的 raw_output 參數被設置爲 TRUE,那麼 sha1 摘要將以 20 字符長度的原始格式返回,否則返回值是一個 40 字符長度的十六進制數字。
* @return string 加密後的字符串。
*/
string sha1 ( string $str [, bool $raw_output = false ] )
這是也一種不可逆加密,執行如下代碼:
$password = '123456';
echo sha1($password);
得到的結果是7c4a8d09ca3762af61e59520943dc26494f8941b
以上幾種雖然是不可逆加密,但是也可以根據查字典的方式去解密。如下的地址中就提供了可以將上面的加密結果解密出來的功能。
所以不能簡單的僅僅使用一種加密算法,加密越複雜,被破解出的可能性就越小。
4. URL加密
string urlencode (string $str)
此函數便於將字符串編碼並將其用於 URL 的請求部分,同時它還便於將變量傳遞給下一頁。
返回字符串,此字符串中除了 -_. 之外的所有非字母數字字符都將被替換成百分號(%)後跟兩位十六進制數,空格則編碼爲加號(+)。此編碼與 WWW 表單 POST 數據的編碼方式是一樣的,同時與 application/x-www-form-urlencoded 的媒體類型編碼方式一樣。由於歷史原因,此編碼在將空格編碼爲加號(+)方面與 RFC1738 編碼不同。
string urldecode (string $str)
解碼給出的已編碼字符串中的任何 %##。 加號(’+’)被解碼成一個空格字符。
這是一種可逆加密,urlencode方法用於加密,urldecode方法用於解密,執行如下代碼:
$url = 'http://www.zmit.cn';
$encodeUrl = urlencode($url);
echo $encodeUrl . "\n";// 如果是在網頁上展示的,就將\n修改爲
echo urldecode($encodeUrl);
得到的結果如下
http%3A%2F%2Fwww.zmit.cn%2F
5. Base64信息編碼加密
/**
* Base64加密操作
* @param string $data 原始字符串
* @return string 加密後的字符串。
*/
string base64_encode (string $data)
使用 base64 對 data 進行編碼。
設計此種編碼是爲了使二進制數據可以通過非純 8-bit 的傳輸層傳輸,例如電子郵件的主體。
Base64-encoded 數據要比原始數據多佔用 33% 左右的空間。
/**
* Base64解密操作
* @param string $data 編碼過的數據
* @param string $strict 如果輸入的數據超出了 base64 字母表,則返回 FALSE。
* @return string 加密後的字符串。
*/
string base64_decode ( string $data [, bool $strict = false ] )
對 base64 編碼的 data 進行解碼。
執行如下代碼:
$name = 'CraryPrimitiveMan';
$encodeName = base64_encode($name);
echo $encodeName . "\n";
echo base64_decode($encodeName);
其結果如下
Q3JhcnlQcmltaXRpdmVNYW4=
CraryPrimitiveMan
6.推薦phpass
經 phpass 0.3 測試,在存入數據庫之前進行哈希保護用戶密碼的標準方式。 許多常用的哈希算法如 md5,甚至是 sha1 對於密碼存儲都是不安全的, 因爲駭客能夠使用那些算法輕而易舉地破解密碼。
對密碼進行哈希最安全的方法是使用 bcrypt 算法。開源的 phpass 庫以一個易於使用的類來提供該功能。
<?php
//包含防止sql注入以及用戶名密碼判斷的註冊、登錄、修改密碼
require '../PasswordHash.php';
// In a real application, these should be in a config file instead
$db_host = '127.0.0.1';
$db_port = 3306;
$db_user = 'mydbuser';
$db_pass = 'voulDyu0gue$s?';
$db_name = 'myapp';
// Base-2 logarithm of the iteration count used for password stretching
$hash_cost_log2 = 8;
// Do we require the hashes to be portable to older systems (less secure)?
$hash_portable = FALSE;
// Are we debugging this code? If enabled, OK to leak server setup details.
$debug = TRUE;
function fail($pub, $pvt = '')
{
global $debug;
$msg = $pub;
if ($debug && $pvt !== '')
$msg .= ": $pvt";
/* The $pvt debugging messages may contain characters that would need to be
* quoted if we were producing HTML output, like we would be in a real app,
* but we're using text/plain here. Also, $debug is meant to be disabled on
* a "production install" to avoid leaking server setup details. */
exit("An error occurred ($msg).\n");
}
function get_post_var($var)
{
$val = $_POST[$var];
if (get_magic_quotes_gpc())
$val = stripslashes($val); //去除提交的字段的斜槓,防止sql注入
return $val;
}
header('Content-Type: text/plain');
$op = $_POST['op'];
if ($op !== 'new' && $op !== 'login' && $op !== 'change') //限制請求類型爲註冊、登錄、改密碼,如果不是新建與登陸請求則拒絕
fail('Unknown request');
$user = get_post_var('user');
/* 用戶完整性檢查,不能只依靠預處理sql,防止sql注入 */
if (!preg_match('/^[a-zA-Z0-9_]{1,60}$/', $user))
fail('Invalid username');
$pass = get_post_var('pass');
/* 爲了節省cpu使用,我們這裏設置長度上限爲72 */
if (strlen($pass) > 72)
fail('The supplied password is too long');
$db = new mysqli($db_host, $db_user, $db_pass, $db_name, $db_port);
if (mysqli_connect_errno())
fail('MySQL connect', mysqli_connect_error());
$hasher = new PasswordHash($hash_cost_log2, $hash_portable);
if ($op === 'new') { //如果是新建用戶則insert
$hash = $hasher->HashPassword($pass);
if (strlen($hash) < 20) //長度過小則判斷爲加密失敗
fail('Failed to hash new password');
unset($hasher); //加密完成後釋放$hasher
($stmt = $db->prepare('insert into users (user, pass) values (?, ?)'))
|| fail('MySQL prepare', $db->error);
$stmt->bind_param('ss', $user, $hash)
|| fail('MySQL bind_param', $db->error);
if (!$stmt->execute()) {
/* 查詢插入失敗的原因,可能是用戶名已經被佔用。
* 從查詢語句能夠更準確方便地得到提示。 如果我們支持多種數據庫就要從代碼中找到出錯原因。
* 然而我們大部分使用的是mysql */
if ($db->errno === 1062 /* ER_DUP_ENTRY */) //1062字段值重複錯誤
fail('This username is already taken');
else
fail('MySQL execute', $db->error);
}
$what = 'User created';
} else { //登錄與修改都需要查詢數據庫,所以以下代碼共用
$hash = '*'; // In case the user is not found
($stmt = $db->prepare('select pass from users where user=?'))
|| fail('MySQL prepare', $db->error);
$stmt->bind_param('s', $user)
|| fail('MySQL bind_param', $db->error);
$stmt->execute()
|| fail('MySQL execute', $db->error);
$stmt->bind_result($hash)
|| fail('MySQL bind_result', $db->error);
if (!$stmt->fetch() && $db->errno)
fail('MySQL fetch', $db->error);
if ($hasher->CheckPassword($pass, $hash)) {
$what = 'Authentication succeeded';
} else {
$what = 'Authentication failed';
$op = 'fail'; // Definitely not 'change'
}
if ($op === 'change') { //===是包括變量值與類型完全相等,而==只是比較兩個數的值是否相等。
$stmt->close();
$newpass = get_post_var('newpass');
if (strlen($newpass) > 72)
fail('The new password is too long');
$hash = $hasher->HashPassword($newpass);
if (strlen($hash) < 20)
fail('Failed to hash new password');
unset($hasher);
($stmt = $db->prepare('update users set pass=? where user=?'))
|| fail('MySQL prepare', $db->error);
$stmt->bind_param('ss', $hash, $user)
|| fail('MySQL bind_param', $db->error);
$stmt->execute()
|| fail('MySQL execute', $db->error);
$what = 'Password changed';
}
unset($hasher);
}
$stmt->close();
$db->close();
echo "$what\n";
?>
phpass 在 HashPassword() 函數中已經對你的密碼“加鹽”了,這意味着你不需要自己“加鹽”。