Kullanıcılarımın şifrelerini nasıl güvenli bir şekilde saklayabilirim?


169

Bu düz MD5'ten ne kadar güvenli ? Şifre güvenliğini araştırmaya yeni başladım. PHP için oldukça yeniyim.

$salt = 'csdnfgksdgojnmfnb';

$password = md5($salt.$_POST['password']);
$result = mysql_query("SELECT id FROM users
                       WHERE username = '".mysql_real_escape_string($_POST['username'])."'
                       AND password = '$password'");

if (mysql_num_rows($result) < 1) {
    /* Access denied */
    echo "The username or password you entered is incorrect.";
} 
else {
    $_SESSION['id'] = mysql_result($result, 0, 'id');
    #header("Location: ./");
    echo "Hello $_SESSION[id]!";
}

Not php 5.4+ bu yerleşik
Benjamin

Ayrıca Openwall'un PHP şifre karma çerçevesine (PHPass) bakın. Taşınabilir ve kullanıcı şifreleri üzerinde yaygın saldırılara karşı sertleştirilmiş.
jww

1
Bugün bu soruya rastlayan insanlar için zorunlu " string interpolation yerine PDO'ları kullanın".
Monica'nın Davası

Yanıtlar:


270

Parola saklama düzeninizi güvenli hale getirmenin en kolay yolu standart bir kitaplık kullanmaktır .

Güvenlik, çoğu programcının tek başına ele alabileceğinden çok daha karmaşık ve daha görünmez vidalama olasılıkları olduğundan, standart bir kitaplık kullanmak neredeyse her zaman en kolay ve en güvenli (tek olmasa da) mevcut seçenektir.


Yeni PHP şifre API'sı (5.5.0+)

PHP sürüm 5.5.0 veya daha yenisini kullanıyorsanız, yeni basitleştirilmiş parola karma API'sını kullanabilirsiniz

PHP'nin şifre API'sini kullanan kod örneği:

<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);

// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

(Hala eski 5.3.7 veya daha yeni bir sürümü kullanıyorsanız, yerleşik işlevlere erişmek için ircmaxell / password_compat yükleyebilirsiniz )


Tuzlanmış karmaların iyileştirilmesi: biber ekleyin

Ekstra güvenlik istiyorsanız, şimdi güvenlik görevlileri (2017) (otomatik olarak) tuzlanmış şifre karmasına bir ' biber ' eklemenizi tavsiye ediyor.

Bu modeli güvenli bir şekilde uygulayan basit, sınıfta bir düşüş var, ben tavsiye ederim: Netsilik / PepperedPasswords ( github ).
Bir MIT Lisansı ile birlikte gelir, böylece özel projelerde bile istediğiniz gibi kullanabilirsiniz.

Kod örneği Netsilik/PepperedPasswords:

<?php
use Netsilik/Lib/PepperedPasswords;

// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');

$hasher = new PepperedPasswords($config['pepper']);

// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);

// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}


OLD standart kütüphanesi

Lütfen dikkat: artık buna ihtiyacınız olmamalı! Bu sadece tarihi amaçlar için burada.

Bir göz atın: Taşınabilir PHP şifre karma çerçeve : phpass ve CRYPT_BLOWFISHmümkünse algoritmayı kullandığınızdan emin olun .

Phpass (v0.2) kullanan kod örneği:

<?php
require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

PHPass oldukça iyi bilinen bazı projelerde uygulanmıştır:

  • phpBB3
  • WordPress 2.5+ ve BBPress
  • Drupal 7 sürümü, (modül Drupal 5 ve 6 için kullanılabilir)
  • diğerleri

İyi olan şey, ayrıntılar hakkında endişelenmenize gerek olmamasıdır, bu ayrıntılar deneyimli kişiler tarafından programlanmış ve internetteki birçok kişi tarafından incelenmiştir.

Şifre saklama şemaları hakkında daha fazla bilgi için Jeff`in blog gönderisini okuyun : Muhtemelen Şifreleri Yanlış Saklıyorsunuz

' Ben kendim yapacağım, teşekkür ederim ' yaklaşımına giderseniz , kullanmazsanız MD5ya da SHA1artık kullanmazsanız ne yaparsanız yapın . Bunlar güzel karma algoritmasıdır, ancak güvenlik nedeniyle kırılmış olarak kabul edilir .

Şu anda, CRYPT_BLOWFISH ile crypt kullanmak en iyi uygulamadır.
PHP'deki CRYPT_BLOWFISH, Bcrypt karmasının bir uygulamasıdır. Bcrypt, algoritmayı yavaşlatmak için pahalı anahtar kurulumundan yararlanarak Blowfish blok şifresini temel alır.


29

SQL ifadelerini birleştirmek yerine parametreli sorgular kullanırsanız kullanıcılarınız çok daha güvenli olacaktır. Ve tuz her kullanıcı için benzersiz olmalı ve şifre karması ile birlikte saklanmalıdır.


1
Nettuts + 'da PHP'de güvenlik hakkında iyi bir makale var, şifre tuzlamadan da bahsediliyor. Belki bir göz atmalısınız
Fábio Antunes

3
Nettuts + model olarak kullanmak için çok kötü bir makaledir - tuzla bile çok kolay zorlanabilen MD5 kullanımını içerir. Bunun yerine, bir eğitim sitesinde bulabileceğiniz herhangi bir koddan çok daha iyi olan PHPass kütüphanesini kullanın, yani bu cevap: stackoverflow.com/questions/1581610/…
RichVel

11

Her kullanıcının benzersiz bir tuza sahip olması daha iyi bir yol olacaktır.

Bir tuz elde etmenin yararı, bir saldırganın her sözlük kelimesinin MD5 imzasını önceden oluşturmasını zorlaştırmasıdır. Ancak, bir saldırgan sabit bir tuzunuz olduğunu öğrenirse, sabit tuzunuzun ön ekine sahip her sözlük sözcüğünün MD5 imzasını önceden oluşturabilir.

Daha iyi bir yol, bir kullanıcı parolasını her değiştirdiğinde, sisteminiz rastgele bir tuz üretir ve bu tuzu kullanıcı kaydıyla birlikte depolar. Şifreyi kontrol etmek biraz daha pahalı hale getirir (MD5 imzasını oluşturmadan önce tuza bakmanız gerekir), ancak bir saldırganın MD5'leri önceden oluşturmasını çok daha zorlaştırır.


3
Tuzlar genellikle parola karmasıyla birlikte depolanır (örneğin crypt()işlevin çıktısı ). Ve yine de parola karmasını geri almak zorunda olduğunuz için, kullanıcıya özel bir tuz kullanmak prosedürü daha pahalı hale getirmeyecektir. (Yoksa yeni bir rastgele tuz üretmek pahalı mı demek istediniz? Gerçekten sanmıyorum.) Aksi takdirde +1.
İnşallah

Güvenlik amacıyla, tabloya yalnızca saklı yordamlar aracılığıyla erişim sağlamak ve karmanın geri dönmesini önlemek isteyebilirsiniz. Bunun yerine, müşteri hash olduğunu düşündüğü şeyi iletir ve bir başarı veya başarısızlık bayrağı alır. Bu, depolanan
işlemin

@Inshallah - tüm kullanıcılar aynı tuza sahipse, user1 üzerinde kullandığınız sözlük saldırısını user2'ye karşı yeniden kullanabilirsiniz. Ancak her kullanıcının benzersiz bir tuzu varsa, saldırmak istediğiniz her kullanıcı için yeni bir sözlük oluşturmanız gerekir.
R Samuel Klatchko

@R Samuel - bu yüzden cevabınızı oyladım, çünkü bu tür saldırıları önlemek için en iyi uygulama stratejisini önerir. Yorumum, hiç anlamadığım bir kullanıcı başına tuzun ek maliyeti ile ilgili söylediklerinizle ilgili şaşkınlığımı ifade etmekti. ("tuzlar genellikle parola karmasıyla birlikte depolandığından" kullanıcı başına tuz için ek depolama ve CPU gereksinimleri o kadar mikroskobiktir ki, bunların belirtilmesi bile gerekmez ...)
Inshallah

@Inshallah - Eğer karma şifre tamam olup olmadığını kontrol veritabanı var durumda düşünüyordum (sonra tuz almak için bir db alma ve karma şifre kontrol etmek için ikinci bir db erişim var). Tuz / karma parolasını tek bir geri almada indirip istemcide karşılaştırmayı yaptığınız durumda haklısınız. Karışıklık için özür dilerim.
R Samuel Klatchko

11

Köşedeki PHP 5.5 (daha önceki sürümlerde bile mevcut, aşağıya bakın) yeni, yerleşik çözümünü kullanmanızı öneririm: password_hash()ve password_verify(). İhtiyacınız olan şifre güvenliği seviyesine ulaşmak için çeşitli seçenekler sunar (örneğin, $optionsdizi aracılığıyla bir "maliyet" parametresi belirleyerek )

<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));

$options = array(
    'cost' => 7, // this is the number of rounds for bcrypt
    // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>

dönecek

string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."

Gördüğünüz gibi, dize, tuzlarda ve seçeneklerde belirtilen maliyeti içerir. Ayrıca kullanılan algoritmayı da içerir.

Bu nedenle, parolayı kontrol ederken (örneğin kullanıcı oturum açtığında), tamamlayıcı password_verify()işlevini kullanırken parola karmasının kendisinden gerekli kripto parametrelerini çıkarır.

Bir tuz belirtilmediğinde, oluşturulan şifre karması her çağrıda farklı olacaktır password_hash()çünkü tuz rastgele üretilir. Bu nedenle, önceki bir karmayı yeni oluşturulan bir karıyla karşılaştırmak, doğru bir şifre için bile başarısız olacaktır.

Doğrulama şu şekilde çalışır:

var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));

var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));

Bu yerleşik işlevleri sağlamanın, veri hırsızlığı durumunda yakında daha iyi şifre güvenliği sağlayacağını umuyorum, çünkü programcının uygun bir uygulamaya koyması gereken düşünce miktarını azaltır.

password_hashPHP 5.3.7+ sürümünde PHP 5.5'ler verecek küçük bir kütüphane (bir PHP dosyası) vardır : https://github.com/ircmaxell/password_compat


2
Çoğu durumda tuz parametresini atlamak daha iyidir. İşlev, işletim sisteminin rastgele kaynağından bir tuz oluşturur, kendi başınıza daha iyi bir tuz sağlayabilme şansınız çok azdır.
martinstoeckli

1
Ben de öyle yazdım, değil mi? "hiçbir tuz belirtilmezse, rastgele oluşturulur, bu nedenle bir tuz belirtmemesi tercih edilir"
akirk

Çoğu örnek, tuz eklemeniz tavsiye edilmese bile her iki parametrenin nasıl ekleneceğini gösterir, bu yüzden nedenini merak ediyorum? Ve dürüst olmak gerekirse, bir sonraki satırda değil, sadece kodun arkasındaki yorumu okudum. Her neyse, örnek fonksiyonun en iyi şekilde nasıl kullanılacağını gösterdiğinde daha iyi olmaz mıydı?
martinstoeckli

Haklısın, katılıyorum. Cevabımı buna göre değiştirdim ve çizgiyi yorumladım. Teşekkürler
akirk

? nasıl kaydedilen şifre ve girilen şifre aynı ise ben kontrol etmelisiniz i kullanıyorum password_hash()ve password_verifyne olursa olsun şifre (doğru ya da değil) i Doğru şifre ile sona kullanılır
Brownman canlanma

0

Bu benimle iyi. Bay Atwood , MD5'in gökkuşağı masalarına karşı gücünü ve temelde güzel oturduğunuz gibi uzun bir tuzla yazdı (bazı rastgele noktalama işaretleri / sayılar olsa da, onu geliştirebilir).

Bu günlerde daha popüler hale gelen SHA-1'e de bakabilirsiniz.


6
Bay Atwood'un gönderisinin (kırmızı renkte) altındaki not, güvenlik görevlisinin MD5, SHA1 ve şifreleri saklamak için diğer hızlı karma işlemlerini kullandığını belirten başka bir gönderiyle bağlantı kuruyor.
sipwiz

2
@Matthew Scharley: Pahalı parola karma algoritmalarının getirdiği ek çabanın yanlış güvenlik olduğunu kabul etmiyorum. Kolayca tahmin edilebilen şifrelerin kaba-zorlanmasına karşı koruma sağlamaktır. Giriş denemelerini sınırlandırıyorsanız, aynı şeye karşı koruyorsunuz (biraz daha etkili olmasına rağmen). Ancak bir düşman DB depolanmış karmalarına erişebiliyorsa, bu (kolayca tahmin edilebilir) şifreleri oldukça hızlı bir şekilde zorlayabilir (ne kadar kolay tahmin edilebileceğine bağlı olarak). SHA-256 crypt algoritması için varsayılan 10000 turdur, bu yüzden 10000 kat daha zor hale getirir.
İnşallah

3
Yavaş karmalar aslında hızlı bir çok sayıda yineleme yapılarak ve her yineleme arasında veri karıştırılarak yapılır. Amaç, kötü adam parola karmalarınızın bir kopyasını alsa bile, sözlüğünü karmalarınıza karşı test etmek için önemli miktarda CPU süresi yakması gerektiğidir.
caf

4
@caf: bcrypt algoritmasının Eksblowfish anahtar zamanlamasının parametrelendirilebilir pahalılığını kullandığına inanıyorum; bunun nasıl çalıştığından tam olarak emin değilim, ancak anahtar zamanlaması, herhangi bir şifreleme yapılmadan önce, bir şifre bağlamı nesnesi başlatma sırasında yapılan çok pahalı bir işlemdir.
İnşallah

3
İnşallah: Bu doğrudur - bcrypt algoritması, altta yatan kripto ilkelinin bir karma işlevinden ziyade bir blok şifresi olduğu farklı bir tasarımdır. PHK MD5 crypt () gibi karma fonksiyonlara dayanan şemalardan bahsediyordum.
caf

0

Eklemek istiyorum:

  • Kullanıcıların şifrelerini uzunluğuyla sınırlamayın

Eski sistemlerle uyumluluk için genellikle parolanın maksimum uzunluğu için bir sınır belirleyin. Bu kötü bir güvenlik politikasıdır: kısıtlama ayarlarsanız, yalnızca minimum şifre uzunluğu için ayarlayın.

  • Kullanıcı şifrelerini e-posta ile göndermeyin

Unutulan bir şifreyi kurtarmak için kullanıcının şifreyi değiştirebileceği adresi göndermelisiniz.

  • Kullanıcı şifrelerinin karmasını güncelleme

Parola karması güncel olmayabilir (algoritmanın parametreleri güncellenebilir). Fonksiyonu kullanarak password_needs_rehash()kontrol edebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.