SORU
23 ŞUBAT 2011, ÇARŞAMBA


İki yönlü şifreleme: alınabilir şifreleri depolamak lazım

Kullanıcı almak ve görmek hangi şifreleri depolayan bir uygulama yaratıyorum. Parolaları bir donanım aygıtı için karma karşı kontrol söz konusu değildir.

Bilmeniz Gerekenler:

  1. Nasıl PHP bir şifre şifrelemek şifresini?

  2. İle parolaları şifrelemek için en güvenli algoritma nedir?

  3. Özel anahtar depolama?

  4. Özel anahtarı depolamak yerine, iyi bir fikir kullanıcıların özel anahtarı her zaman girmeniz gerekir için bir parola şifresi gerekiyor mu? (Bu uygulama, kullanıcıların güvenilir olabilir)

  5. Ne şekilde şifre çalınmış ve şifresi çözülmüş olabilir mi? Ben farkında olmak için ne yapmak gerekiyor?

CEVAP
23 ŞUBAT 2011, ÇARŞAMBA


Şahsen, Diğerleri viagra gibi mcrypt kullanırdım. Ama bir not daha var...

  1. Nasıl PHP bir şifre şifrelemek şifresini?

    Aşağıda güçlü bir sınıf için o sizin için her şeyi ilgilenir:

  2. İle parolaları şifrelemek için en güvenli algoritma nedir?

    en güvenli? hiçbirini. Eğer şifrelemek için gidiyoruz en güvenli yöntem bilgilendirme açıkları (XSS, uzaktan eklenmesi, vb.) karşı korumaktır. Eğer dışarı çıkarsa, saldırgan sonunda (şifreleme un-geri dönüşümlü anahtar olmadan - @Olarak NullUserException bu tamamen doğru olduğuna işaret ediyor. 100% şifreleme çatlasa Kırılması imkansız olan bazı şifreleme programları OneTimePad) gibi.

  3. Özel anahtar depolama?

    Ne yapardım 3 tuşlarını kullanın. Kullanıcı tarafından sağlanan bir, bir uygulamaya özeldir ve başka bir kullanıcı belirli (tuz gibi). Uygulama belirli bir yere anahtar (config dosyası web-kök, bir çevre değişkeni, vb dışında) saklanabilir. Kullanıcı belirli bir db şifreli parola yanında bir sütun içinde saklanır. Kullanıcı bir saklı olmaz sağladı. O zaman, böyle bir şey yaparsın:

    $key = $userKey . $serverKey . $userSuppliedKey;
    

    Yararı yok, tuşlarından birine 2 Veri tehlikeye olmadan tehlikeye girebilir. Eğer SQL Enjeksiyon saldırısı varsa, $userKey ama diğer 2 alabilirsiniz. Eğer yerel bir sunucu kullanmak varsa, $userKey $serverKey ama üçüncü $userSuppliedKey alabilirsiniz. Eğer onlar yendi kullanıcı ile bir anahtarı vardır, onlar almak $userSuppliedKey ama diğer 2 (ama sonra tekrar, eğer kullanıcı dayak ile bir İngiliz anahtarı, çok geç kaldın zaten).

  4. Özel anahtarı depolamak yerine, iyi bir fikir kullanıcıların özel anahtarı her zaman girmeniz gerekir için bir parola şifresi gerekiyor mu? (Bu uygulama, kullanıcıların güvenilir olabilir)

    Kesinlikle. Aslında bunu yapmam için tek yol bu. Aksi takdirde dayanıklı bir depolama biçimi (APC gibi paylaşımlı bellek ya da, ya da bir oturum dosyası memcached) şifresiz sürümünü saklamak için ihtiyacınız olacak. Ek tavizler kendinizi açığa. Asla yerel bir değişken dışında hiçbir şeye şifre şifresiz sürüm deposu.

  5. Ne şekilde şifre çalınmış ve şifresi çözülmüş olabilir mi? Ben farkında olmak için ne yapmak gerekiyor?

    Sistem uzlaşma herhangi bir şekilde onları şifreli veri görüntülemenize olanak sağlayacak. Eğer kod enjekte veya dosya alabiliyorsa, şifresi çözülen veri şifresini çözmek bu dosyaları düzenleyebilirsiniz beri () görüntüleyebilirsiniz. Replay veya MITM saldırı da onlara anahtarları dahil tam erişim sağlar. Çiğ HTTP trafiği koklama da anahtarları teslim edecek.

    Tüm bağlantılar için SSL kullanın. Ve emin olun server üzerinde hiçbir güvenlik açıkları her türlü (, XSS, SQL Enjeksiyon, Ayrıcalık Yükseltme, Uzaktan Kod Çalıştırma, vb CSRF).

Düzenleme:Burada güçlü bir şifreleme yöntemi PHP sınıf bir uygulama:

/**
 * A class to handle secure encryption and decryption of arbitrary data
 *
 * Note that this is not just straight encryption.  It also has a few other
 *  features in it to make the encrypted data far more secure.  Note that any
 *  other implementations used to decrypt data will have to do the same exact
 *  operations.  
 *
 * Security Benefits:
 *
 * - Uses Key stretching
 * - Hides the Initialization Vector
 * - Does HMAC verification of source data
 *
 */
class Encryption {

    /**
     * @var string $cipher The mcrypt cipher to use for this instance
     */
    protected $cipher = '';

    /**
     * @var int $mode The mcrypt cipher mode to use
     */
    protected $mode = '';

    /**
     * @var int $rounds The number of rounds to feed into PBKDF2 for key generation
     */
    protected $rounds = 100;

    /**
     * Constructor!
     *
     * @param string $cipher The MCRYPT_* cypher to use for this instance
     * @param int    $mode   The MCRYPT_MODE_* mode to use for this instance
     * @param int    $rounds The number of PBKDF2 rounds to do on the key
     */
    public function __construct($cipher, $mode, $rounds = 100) {
        $this->cipher = $cipher;
        $this->mode = $mode;
        $this->rounds = (int) $rounds;
    }

    /**
     * Decrypt the data with the provided key
     *
     * @param string $data The encrypted datat to decrypt
     * @param string $key  The key to use for decryption
     * 
     * @returns string|false The returned string if decryption is successful
     *                           false if it is not
     */
    public function decrypt($data, $key) {
        $salt = substr($data, 0, 128);
        $enc = substr($data, 128, -64);
        $mac = substr($data, -64);

        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        if (!hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {
             return false;
        }

        $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);

        $data = $this->unpad($dec);

        return $data;
    }

    /**
     * Encrypt the supplied data using the supplied key
     * 
     * @param string $data The data to encrypt
     * @param string $key  The key to encrypt with
     *
     * @returns string The encrypted data
     */
    public function encrypt($data, $key) {
        $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        $data = $this->pad($data);

        $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);

        $mac = hash_hmac('sha512', $enc, $macKey, true);
        return $salt . $enc . $mac;
    }

    /**
     * Generates a set of keys given a random salt and a master key
     *
     * @param string $salt A random string to change the keys each encryption
     * @param string $key  The supplied key to encrypt with
     *
     * @returns array An array of keys (a cipher key, a mac key, and a IV)
     */
    protected function getKeys($salt, $key) {
        $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
        $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
        $length = 2 * $keySize   $ivSize;

        $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);

        $cipherKey = substr($key, 0, $keySize);
        $macKey = substr($key, $keySize, $keySize);
        $iv = substr($key, 2 * $keySize);
        return array($cipherKey, $macKey, $iv);
    }

    /**
     * Stretch the key using the PBKDF2 algorithm
     *
     * @see http://en.wikipedia.org/wiki/PBKDF2
     *
     * @param string $algo   The algorithm to use
     * @param string $key    The key to stretch
     * @param string $salt   A random salt
     * @param int    $rounds The number of rounds to derive
     * @param int    $length The length of the output key
     *
     * @returns string The derived key.
     */
    protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
        $size   = strlen(hash($algo, '', true));
        $len    = ceil($length / $size);
        $result = '';
        for ($i = 1; $i <= $len; $i  ) {
            $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
            $res = $tmp;
            for ($j = 1; $j < $rounds; $j  ) {
                 $tmp  = hash_hmac($algo, $tmp, $key, true);
                 $res ^= $tmp;
            }
            $result .= $res;
        }
        return substr($result, 0, $length);
    }

    protected function pad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $padAmount = $length - strlen($data) % $length;
        if ($padAmount == 0) {
            $padAmount = $length;
        }
        return $data . str_repeat(chr($padAmount), $padAmount);
    }

    protected function unpad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $last = ord($data[strlen($data) - 1]);
        if ($last > $length) return false;
        if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
            return false;
        }
        return substr($data, 0, -1 * $last);
    }
}

Bir fonksiyon PHP 5.6 eklendi kullanıyorum not: hash_equals. timing-safe comparison fonksiyon double HMAC verification kullanarak uygulayan: bu işlevi yerine kullanabilirsiniz 5.6 daha düşük

function hash_equals($a, $b) {
    $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
    return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);
}

Kullanımı:

$e = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$encryptedData = $e->encrypt($data, $key);

Daha sonra şifresini çözmek için:

$e2 = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$data = $e2->decrypt($encryptedData, $key);

$e2 ikinci kez farklı örneklerini hala doğru verileri deşifre olacaktır göstermek için kullanılır unutmayın.

Şimdi, nasıl/neden başka bir çözüm üzerinde çalışır:

  1. Anahtarları

    • Anahtarlar doğrudan kullanılmaz. Bunun yerine, standart bir PBKDF2 anahtar türetme tarafından gerilir.

    • Anahtar şifreleme için kullanılan metin her şifreli blok için benzersizdir. Verilen anahtar bu nedenle bir "olur". ana anahtar Bu sınıf, bu nedenle rotasyon, şifreleme ve Kimlik Doğrulama anahtarları anahtar sağlar.

    • ÖNEMLİ NOT, $rounds parametre (Şifreli 128 bit en azından rastgele Güvenli) yeterli gücü gerçek rasgele sayı için yapılandırıldı. Eğer şifre veya rastgele olmayan bir anahtar (CS rastgele ya da daha az rastgele o zaman 128 bit) kullanmak için gidiyoruz eğergerekirBu parametre artırın. Şifreleri daha iyi gelemez, ancak çalışma zamanı katacak () için 10000 en az öneririm...

  2. Veri Bütünlüğü

    • Güncelleştirilmiş sürümünü şifreli veri doğruluğunu sağlamak için çok iyi bir yöntem olan ŞİFRELEME-O-MAC kullanır.
  3. Şifreleme:

    • Aslında mcrypt şifreleme gerçekleştirmek için kullanır. Ya da MCRYPT_BLOWFISH MCRYPT_RIJNDAEL_128 cyphers kullanarak ve modu için MCRYPT_MODE_CBC öneririm. Güçlü ve oldukça hızlı (şifreleme ve şifre çözme döngüsü makinem, yaklaşık 1/2 saniye sürer).

Sana verecek ne şimdi, ilk listeden noktası 3 olarak, bu gibi bir işlevi vardır:

function makeKey($userKey, $serverKey, $userSuppliedKey) {
    $key = hash_hmac('sha512', $userKey, $serverKey);
    $key = hash_hmac('sha512', $key, $userSuppliedKey);
    return $key;
}

makeKey() fonksiyonu streç olabilir, ama daha sonra gergin olacak beri, gerçekten bunu yapmak için çok büyük bir anlamı yok.

Bildiğim kadarıyla depolama boyutu olarak, düz metin bağlı. Blowfish 8 bayt blok boyutu kullanır, olacak:

  • Tuz için 16 bayt
  • Hmac için 64 bayt
  • veri uzunluğu
  • Veri uzunluğu kadar doldurma % 8 == 0

16 karakter veri kaynağı için, şifrelenmiş veri 16 karakter olacak. Gerçek şifrelenmiş veri boyutu 16 bayt doldurma nedeniyle olduğu anlamına gelir. Sonra tuz için 16 byte ve hmac için 64 bayt ekleyin ve toplam saklı boyutu 96 bayt. En fazla 80 karakter yükü, ve en kötü ihtimalle 87 karakter bir yükü var...

Bu yardımcı olur umarım

Not:12/11/12: ben sadece ÇOK daha iyi bir şifreleme yöntemi ile bu sınıf güncellendi, iyi türetilmiş tuşlarını kullanarak, ve MAC nesil... elden geçiriyorum

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • fast2hell

    fast2hell

    16 AĞUSTOS 2006
  • FUzzyBUnnyBOoties

    FUzzyBUnnyBO

    3 EKİM 2007
  • soyacincautv

    soyacincautv

    14 NİSAN 2010