Önemli : Çok özel bir kullanım durumunuz yoksa , şifreleri şifrelemeyin , bunun yerine bir şifre karma algoritması kullanın. Birisi şifrelerini sunucu tarafındaki bir uygulamada şifrelediğini söylediğinde , ya bilgisizdir ya da tehlikeli bir sistem tasarımını tanımlar. Şifreleri güvenli bir şekilde saklamak , şifrelemeden tamamen ayrı bir sorundur.
Haberdar olmak. Güvenli sistemler tasarlayın.
PHP'de Taşınabilir Veri Şifreleme
PHP 5.4 veya daha yenisini kullanıyorsanız ve kendiniz bir şifreleme modülü yazmak istemiyorsanız , kimliği doğrulanmış şifreleme sağlayan mevcut bir kitaplığı kullanmanızı öneririm . Bağladığım kütüphane sadece PHP'nin sağladığı bilgilere dayanıyor ve bir avuç güvenlik araştırmacısı tarafından periyodik olarak inceleniyor. (Ben de dahil.)
Taşınabilirlik hedefleriniz PECL uzantıları gerektirmezse, libsodium sizin veya PHP'de yazabileceğim herhangi bir şey için şiddetle tavsiye edilir.
Güncelleme (2016-06-12): Artık sodyum_compat kullanabilir ve PECL uzantılarını yüklemeden aynı kripto libsodium tekliflerini kullanabilirsiniz.
Kriptografi mühendisliğinde elinizi denemek istiyorsanız, okumaya devam edin.
İlk olarak, kimliği doğrulanmamış şifrelemenin ve Kriptografik Kıyamet İlkesi'nin tehlikelerini öğrenmek için zaman ayırmalısınız .
- Şifrelenmiş veriler yine de kötü niyetli bir kullanıcı tarafından oynanabilir.
- Şifrelenmiş verilerin kimliğinin doğrulanması kurcalamayı önler.
- Şifrelenmemiş verilerin kimliğinin doğrulanması kurcalamayı önlemez.
Şifreleme ve Şifre Çözme
PHP'de Şifreleme biz kullanacağız (aslında basittir openssl_encrypt()
ve openssl_decrypt()
size bilgileri şifrelemek için nasıl ilgili bazı kararlar yaptıktan sonra başvurun. openssl_get_cipher_methods()
Sisteminizde desteklenen yöntemlerinin listesi için en iyi seçimdir. TO modunda AES :
aes-128-ctr
aes-192-ctr
aes-256-ctr
Şu anda AES anahtar boyutunun endişelenmesi gereken önemli bir konu olduğuna inanmak için bir neden yoktur ( 256 bit modundaki kötü anahtar zamanlaması nedeniyle büyük olasılıkla daha iyi değildir ).
Not: Kullanılmadığı için terkedilebilir ve güvenliği etkileyebilecek , hata ayıklanmış hatalar kullanmıyoruzmcrypt
. Bu nedenlerden dolayı, diğer PHP geliştiricilerini de bundan kaçınmaları için teşvik ediyorum.
OpenSSL kullanarak Basit Şifreleme / Şifre Çözme Sarıcı
class UnsafeCrypto
{
const METHOD = 'aes-256-ctr';
/**
* Encrypts (but does not authenticate) a message
*
* @param string $message - plaintext message
* @param string $key - encryption key (raw binary expected)
* @param boolean $encode - set to TRUE to return a base64-encoded
* @return string (raw binary)
*/
public static function encrypt($message, $key, $encode = false)
{
$nonceSize = openssl_cipher_iv_length(self::METHOD);
$nonce = openssl_random_pseudo_bytes($nonceSize);
$ciphertext = openssl_encrypt(
$message,
self::METHOD,
$key,
OPENSSL_RAW_DATA,
$nonce
);
// Now let's pack the IV and the ciphertext together
// Naively, we can just concatenate
if ($encode) {
return base64_encode($nonce.$ciphertext);
}
return $nonce.$ciphertext;
}
/**
* Decrypts (but does not verify) a message
*
* @param string $message - ciphertext message
* @param string $key - encryption key (raw binary expected)
* @param boolean $encoded - are we expecting an encoded string?
* @return string
*/
public static function decrypt($message, $key, $encoded = false)
{
if ($encoded) {
$message = base64_decode($message, true);
if ($message === false) {
throw new Exception('Encryption failure');
}
}
$nonceSize = openssl_cipher_iv_length(self::METHOD);
$nonce = mb_substr($message, 0, $nonceSize, '8bit');
$ciphertext = mb_substr($message, $nonceSize, null, '8bit');
$plaintext = openssl_decrypt(
$ciphertext,
self::METHOD,
$key,
OPENSSL_RAW_DATA,
$nonce
);
return $plaintext;
}
}
Kullanım Örneği
$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');
$encrypted = UnsafeCrypto::encrypt($message, $key);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key);
var_dump($encrypted, $decrypted);
Demo : https://3v4l.org/jl7qR
Yukarıdaki basit kripto kütüphanesinin kullanımı hala güvenli değildir. Biz gereken metni elde doğrulamak ve biz şifresini önce onları doğrulamak .
Not : Varsayılan olarak UnsafeCrypto::encrypt()
ham bir ikili dize döndürür. İkili güvenlikli bir biçimde (base64 kodlu) saklamanız gerekiyorsa bu şekilde adlandırın:
$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');
$encrypted = UnsafeCrypto::encrypt($message, $key, true);
$decrypted = UnsafeCrypto::decrypt($encrypted, $key, true);
var_dump($encrypted, $decrypted);
Demo : http://3v4l.org/f5K93
Basit Kimlik Doğrulama Sarıcı
class SaferCrypto extends UnsafeCrypto
{
const HASH_ALGO = 'sha256';
/**
* Encrypts then MACs a message
*
* @param string $message - plaintext message
* @param string $key - encryption key (raw binary expected)
* @param boolean $encode - set to TRUE to return a base64-encoded string
* @return string (raw binary)
*/
public static function encrypt($message, $key, $encode = false)
{
list($encKey, $authKey) = self::splitKeys($key);
// Pass to UnsafeCrypto::encrypt
$ciphertext = parent::encrypt($message, $encKey);
// Calculate a MAC of the IV and ciphertext
$mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);
if ($encode) {
return base64_encode($mac.$ciphertext);
}
// Prepend MAC to the ciphertext and return to caller
return $mac.$ciphertext;
}
/**
* Decrypts a message (after verifying integrity)
*
* @param string $message - ciphertext message
* @param string $key - encryption key (raw binary expected)
* @param boolean $encoded - are we expecting an encoded string?
* @return string (raw binary)
*/
public static function decrypt($message, $key, $encoded = false)
{
list($encKey, $authKey) = self::splitKeys($key);
if ($encoded) {
$message = base64_decode($message, true);
if ($message === false) {
throw new Exception('Encryption failure');
}
}
// Hash Size -- in case HASH_ALGO is changed
$hs = mb_strlen(hash(self::HASH_ALGO, '', true), '8bit');
$mac = mb_substr($message, 0, $hs, '8bit');
$ciphertext = mb_substr($message, $hs, null, '8bit');
$calculated = hash_hmac(
self::HASH_ALGO,
$ciphertext,
$authKey,
true
);
if (!self::hashEquals($mac, $calculated)) {
throw new Exception('Encryption failure');
}
// Pass to UnsafeCrypto::decrypt
$plaintext = parent::decrypt($ciphertext, $encKey);
return $plaintext;
}
/**
* Splits a key into two separate keys; one for encryption
* and the other for authenticaiton
*
* @param string $masterKey (raw binary)
* @return array (two raw binary strings)
*/
protected static function splitKeys($masterKey)
{
// You really want to implement HKDF here instead!
return [
hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true),
hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true)
];
}
/**
* Compare two strings without leaking timing information
*
* @param string $a
* @param string $b
* @ref https://paragonie.com/b/WS1DLx6BnpsdaVQW
* @return boolean
*/
protected static function hashEquals($a, $b)
{
if (function_exists('hash_equals')) {
return hash_equals($a, $b);
}
$nonce = openssl_random_pseudo_bytes(32);
return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce);
}
}
Kullanım Örneği
$message = 'Ready your ammunition; we attack at dawn.';
$key = hex2bin('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f');
$encrypted = SaferCrypto::encrypt($message, $key);
$decrypted = SaferCrypto::decrypt($encrypted, $key);
var_dump($encrypted, $decrypted);
Demolar : ham ikili , base64 kodlu
Bu SaferCrypto
kütüphaneyi bir üretim ortamında veya aynı kavramları kendi uygulamanızda kullanmak isteyen varsa , sizden önce ikinci bir görüş için yerleşik kriptograflarınıza ulaşmanızı şiddetle tavsiye ederim . Farkında bile olamayacağım hatalardan bahsedebilirler.
Saygın bir şifreleme kütüphanesi kullanmaktan çok daha iyi olacaksınız .