L 關鍵數據加密,包含用戶登陸註冊

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: 1 rasmuslerISCgZzpwk3UhDidwXvin0Blowfish: 2a07 usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi
SHA-256: 5 rounds=5000usesomesillystri KqJWpanXZHKq2BOB43TSaYhEWsQ1Lr5QNyPCDH/Tp.6
SHA-512: 6 rounds=5000usesomesillystri D4IrlXatmP7rx3P3InaxBeoomnAihCKRVQP22JZ6EY47Wc6BkroIuUUBOov1i.S5KPgErtP/EN5mcO.ChWQW21

在 crypt() 函數支持多重散列的系統上,下面的常量根據相應的類型是否可用被設置爲 0 或 1:
CRYPT_STD_DES – 基於標準 DES 算法的散列使用 “./0-9A-Za-z” 字符中的兩個字符作爲鹽值。在鹽值中使用非法的字符將導致 crypt() 失敗。

CRYPT_MD5 – MD5 散列使用一個以 1 開始的 12 字符的字符串鹽值。

CRYPT_BLOWFISH – Blowfish 算法使用如下鹽值:“2a ”,一個兩位 cost 參數,“$” 以及 64 位由 “./0-9A-Za-z” 中的字符組合而成的字符串。在鹽值中使用此範圍之外的字符將導致 crypt() 返回一個空字符串。兩位 cost 參數是循環次數以 2 爲底的對數,它的範圍是 04-31,超出這個範圍將導致 crypt() 失敗。

CRYPT_SHA256 – SHA-256 算法使用一個以 5 開頭的 16 字符字符串鹽值進行散列。如果鹽值字符串以 “rounds=$” 開頭,N 的數字值將被用來指定散列循環的執行次數,這點很像 Blowfish 算法的 cost 參數。默認的循環次數是 5000,最小是 1000,最大是 999,999,999。超出這個範圍的 N 將會被轉換爲最接近的值。

CRYPT_SHA512 – SHA-512 算法使用一個以 6 開頭的 16 字符字符串鹽值進行散列。如果鹽值字符串以 “rounds=$” 開頭,N 的數字值將被用來指定散列循環的執行次數,這點很像 Blowfish 算法的 cost 參數。默認的循環次數是 5000,最小是 1000,最大是 999,999,999。超出這個範圍的 N 將會被轉換爲最接近的值


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

http://www.zmit.cn


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() 函數中已經對你的密碼“加鹽”了,這意味着你不需要自己“加鹽”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章