首頁 >後端開發 >php教程 >php安全加密技術

php安全加密技術

伊谢尔伦
伊谢尔伦原創
2016-11-21 16:11:571057瀏覽

 一個PHP開發者應主要熟悉以下的加密方式:

 

l        對稱加密金鑰

l             資訊驗證碼

 

  本附錄主要關注使用mcrypt擴展的對稱加密演算法。需要參考的資料如下:

 

  實用加密技術(Applied Cryptography), by Bruce Schneier (Wiley)

http://www.schneier.com/blog/

http://wiki

http://www.schneier.com/blog/

http://wiki /Cryptography

http://phpsec.org/articles/2005/password-hashing.html

http://pear.php.net/package/Crypt_HMAC

http://pear.php.net/package/ Crypt_RSA

 

C.1. 密碼的儲存

  當你在資料庫內儲存的密碼時,永遠不要以明碼方式存入,而是應該儲存密碼的hash值並同時使用附加字串:

 

<?php
 
  /* $password contains the password. */
 
  $salt = &#39;SHIFLETT&#39;;
  $password_hash = md5($salt . md5($password . $salt));
 
  /* Store password hash. */
 
  ?>

 

當你需要確認一個密碼是否正確時,以同樣的方式計算出hash值並比較異同:

<?php
 
  $salt = &#39;SHIFLETT&#39;;
  $password_hash = md5($salt . md5($_POST[&#39;password&#39;] . $salt));
 
  /* Compare password hashes. */
 
  ?>

 

  如果hash值完全相同,你就有理由認為密碼也是相同的。

  如果使用了這個技巧,是不可能告訴使用者他們的密碼是什麼的。當使用者忘記密碼時,你只能讓他輸入一個新密碼並重新計算hash值存入資料庫。當然,你需要非常小心地對使用者進行身分確認──密碼提醒機制是容易受到頻繁攻擊的目標,​​同時也是經常出現安全漏洞的來源。

 

C.2. 使用mcrypt

  PHP的標準加密擴充是mcrypt,它支援許多不同的加密演算法。你可以透過mcrypt_list_algorithms( )函數來查看你的平台上支援的演算法列表:

 

<?php
 
  echo &#39;<pre class="brush:php;toolbar:false">&#39; . print_r(mcrypt_list_algorithms(), TRUE) . &#39;
'; ?>

 

  加密和解密分別由mcrypt_encrypt( ) 和 mcrypt_decrypt( )函數來實現。這兩個函數都有5個參數,第一個參數是用來指定使用的演算法:

 <?php
 
  mcrypt_encrypt($algorithm,
                 $key,
                 $cleartext,
                 $mode,
                 $iv);
 
  mcrypt_decrypt($algorithm,
                 $key,
                 $ciphertext,
                 $mode,
                 $iv);
 
  ?>

 

 其中的加密鍵(第二個參數)是非常敏感的數據,因此你要確保把它存放在安全的地方。可以用第八章保護資料庫權限的方法來保護加密鍵。如果經濟條件允許的話,硬體加密鍵是最好的選擇,它提供了超級強大的安全性。

  函數有多種模式可供選擇,你可以使用mcrypt_list_modes( )來列出所有支援的模式:

<?php
 
  echo &#39;<pre class="brush:php;toolbar:false">&#39; . print_r(mcrypt_list_modes(), TRUE) . &#39;
'; ?>

 

第五個參數($iv)為初始化向量,可以使用mcrypt_create_iv( )函數建立。

  下列的範例類別提供了基本的加密解密方法:

class crypt
  {
    private $algorithm;
    private $mode;
    private $random_source;
 
    public $cleartext;
    public $ciphertext;
    public $iv;
 
    public function __construct($algorithm = MCRYPT_BLOWFISH,
                                $mode = MCRYPT_MODE_CBC,
                                $random_source = MCRYPT_DEV_URANDOM)
    {
      $this->algorithm = $algorithm;
      $this->mode = $mode;
      $this->random_source = $random_source;
    }
 
    public function generate_iv()
    {
      $this->iv = mcrypt_create_iv(mcrypt_get_iv_size($this->algorithm,
        $this->mode), $this->random_source);
    }
 
    public function encrypt()
    {
      $this->ciphertext = mcrypt_encrypt($this->algorithm,
        $_SERVER[&#39;CRYPT_KEY&#39;], $this->cleartext, $this->mode, $this->iv);
    }
 
    public function decrypt()
    {
      $this->cleartext = mcrypt_decrypt($this->algorithm,
        $_SERVER[&#39;CRYPT_KEY&#39;], $this->ciphertext, $this->mode, $this->iv);
    }
  }
 
  ?>

 

  上面的類別會在其它範例中使用,以下是它的使用方法範例:

<?php
 
  $crypt = new crypt();
 
  $crypt->cleartext = &#39;This is a string&#39;;
  $crypt->generate_iv();
  $crypt->encrypt();
 
  $ciphertext = base64_encode($crypt->ciphertext);
  $iv = base64_encode($crypt->iv);
 
  unset($crypt);
 
  /* Store $ciphertext and $iv (initialization vector). */
 
  $ciphertext = base64_decode($ciphertext);
  $iv = base64_decode($iv);
 
  $crypt = new crypt();
 
  $crypt->iv = $iv;
  $crypt->ciphertext = $ciphertext;
  $crypt->decrypt();
 
  $cleartext = $crypt->cleartext;
?>
擴充提示你在編譯PHP時使用-mcrypt標識。安裝指南及要求詳見http://php.net/mcrypt。

 C.3. 信用卡號的保存

  我常被問到如何安全地保存信用卡號。我的總是會先詢問他們是否確實有必要保存信用卡號。畢竟不管具體是如何操作的,引入不必要的風險是不明智的。同時國家法律還有關於信用卡資訊處理的規定,我也時時小心提醒我並不是一個法律專家。

  本書中我並不會專門討論信用卡處理的方法,而是會說明如何保存加密資訊到資料庫及在讀取時解密。此流程會導致系統效能的下降,但是確實提供了一層保護措施。其主要優點是如果資料庫內容洩密暴露出的只是加密訊息,但是前提是加密鍵是安全的。因此,加密鍵與加密的實作方法本身同樣重要。   將加密資料保存到資料的過程是,先加密數據,然後透過初始向量與明文建立密文來儲存到資料庫。由於密文是二進位字串,還需要透過base64_encode( )轉換成普通文字字串以確保二進位編碼的安全儲存。

  <?php
 
  $crypt = new crypt();
 
  $crypt->cleartext = &#39;1234567890123456&#39;;
  $crypt->generate_iv();
  $crypt->encrypt();
 
  $ciphertext = $crypt->ciphertext;
  $iv = $crypt->iv;
 
  $string = base64_encode($iv . $ciphertext);
 
  ?>

 

將該字串保存到資料庫中。在讀取時,則是上面流程的逆處理:

 <?php
 
  $string = base64_decode($string);
 
  $iv_size = mcrypt_get_iv_size($algorithm, $mode);
 
  $ciphertext = substr($string, $iv_size);
  $iv = substr($string, 0, $iv_size);
 
  $crypt = new crypt();
 
  $crypt->iv = $iv;
  $crypt->ciphertext = $ciphertext;
  $crypt->decrypt();
 
  $cleartext =  $crypt->cleartext;
 
  ?>

 

 本實作方法假定加密演算法與模式不變。如果它們是不定的話,你還要保存它們以用於解密資料。加密鍵是唯一需要保密的資料。

 

C.4. 加密會話資料

  如果你的数据库存在安全问题,或者部分保存在会话中的数据是敏感的,你可能希望加密会话数据。除非很有必要,一般我不推荐这样做,但是如果你觉得在你的情形下需要这样做的话,本节提供了一个实现方法的示例。

  这个方案十分简单。实际上,在第八章中,已经说明了如何通过调用session_set_save_handler( )来执行你自己的会话机制。通过对保存和读取数据的函数的少量调整,你就能加密存入数据库的数据及在读取时解密数据:

  <?php
 
  function _read($id)
  {
    global $_sess_db;
 
    $algorithm = MCRYPT_BLOWFISH;
    $mode = MCRYPT_MODE_CBC;
 
    $id = mysql_real_escape_string($id);
 
    $sql = "SELECT data
            FROM   sessions
            WHERE  id = &#39;$id&#39;";
 
    if ($result = mysql_query($sql, $_sess_db))
    {
        $record = mysql_fetch_assoc($result);
 
        $data = base64_decode($record[&#39;data&#39;]);
 
        $iv_size = mcrypt_get_iv_size($algorithm, $mode);
 
        $ciphertext = substr($data, $iv_size);
        $iv = substr($data, 0, $iv_size);
 
        $crypt = new crypt();
 
        $crypt->iv = $iv;
        $crypt->ciphertext = $ciphertext;
        $crypt->decrypt();
 
        return $crypt->cleartext;
    }
 
    return &#39;&#39;;
  }
 
  function _write($id, $data)
  {
    global $_sess_db;
 
    $access = time();
 
    $crypt = new crypt();
 
    $crypt->cleartext = $data;
    $crypt->generate_iv();
    $crypt->encrypt();
 
    $ciphertext = $crypt->ciphertext;
    $iv = $crypt->iv;
 
    $data = base64_encode($iv . $ciphertext);
 
    $id = mysql_real_escape_string($id);
    $access = mysql_real_escape_string($access);
    $data = mysql_real_escape_string($data);
 
    $sql = "REPLACE
            INTO    sessions
            VALUES  (&#39;$id&#39;, &#39;$access&#39;, &#39;$data&#39;)";
 
    return mysql_query($sql, $_sess_db);
  }
  ?>


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn