PHP'de parolaları karıştırmak için bcrypt'i nasıl kullanırsınız?


1255

Her zaman ve daha sonra "PHP, bcrypt kuralları saklamak için bcrypt kullanın" tavsiyelerini duyuyorum.

Ama nedir bcrypt? PHP böyle bir işlev sunmuyor, Wikipedia şifreleme yardımcı programı hakkında babbles ve Web aramaları sadece farklı dillerde Blowfish birkaç uygulama ortaya koymaktadır . Şimdi Blowfish PHP ile de kullanılabilir mcrypt, ancak bu şifrelerin depolanmasına nasıl yardımcı olur? Blowfish genel amaçlı bir şifredir, iki şekilde çalışır. Şifrelenebiliyorsa, şifresi çözülebilir. Parolaların tek yönlü karma işlevi gerekir.

Açıklama nedir?


13
Bu soru daha önce ele alınmıştı ve standart bir kütüphane kullanma önerileri mükemmel. Güvenlik karmaşık bir konudur ve ne yaptığını bilen biri tarafından tasarlanmış bir paket kullanarak sadece kendinize yardım edersiniz.
eykanal

59
@eykanal - bu sayfa bcrypt'ten bile bahsetmiyor, ne olduğunu daha az açıklıyor .
Vilx-

8
@eykanal - Nasıl çalıştığına dair bir açıklama sormuyorum. Sadece ne olduđunu bilmek istiyorum . Çünkü "bcrypt" anahtar kelimesi altında net kazmak ne olursa olsun, hiçbir şekilde şifreleri karma için kullanılamaz. Zaten doğrudan değil, PHP'de değil. Tamam, şimdi anlıyorum gerçekten "phpass" paketi şifrenizi şifrenizden türetilen bir anahtar ile şifrelemek için blowfish kullanan (aslında şifre kendisi ile şifrelemek). Ama bunu "bcrypt" olarak adlandırmak ciddi şekilde yanıltıcı ve bu soruda açıklığa kavuşturmak istediğim şey bu.
Vilx-

3
@Vilx: Ben neden olarak daha fazla bilgi ekledik bcryptbir şifreleme şeması karşı tek yönlü karma algoritmasıdır cevabım . Aslında, bcryptBlowfish'in tamamen farklı bir anahtar programına sahip olduğu zaman, tümüyle yanlış bir anlayış vardır, bu da düz metnin, şifrenin başlangıç ​​durumunu (tuz, mermi, anahtar) bilmeden şifre metninden kurtarılamamasını sağlar.
Andrew Moore

1
Ayrıca Openwall'un Taşınabilir PHP şifre karma çerçevesine (PHPass) bakın. Kullanıcı parolalarına yönelik bir dizi yaygın saldırıya karşı sertleştirilmiştir.
jww

Yanıtlar:


1065

bcryptdonanım ile ölçeklendirilebilen bir karma algoritmasıdır (yapılandırılabilir sayıda tur aracılığıyla). Yavaşlığı ve çoklu turları, bir saldırganın parolalarınızı kırmak için büyük fonlar ve donanım dağıtması gerektiğini garanti eder. Bu şifre başına tuzlara ekleyin ( tuzlarıbcrypt GEREKTİRİR) ve bir saldırının gülünç miktarda fon veya donanım olmadan neredeyse mümkün olmadığından emin olabilirsiniz.

bcryptparolaları karma yapmak için Eksblowfish algoritmasını kullanır . Şifreleme aşaması sırasında Eksblowfish ve Blowfish'ten tam olarak aynıdır, anahtar zamanlama faz Eksblowfish sonraki herhangi devlet hem tuz ve anahtar (kullanıcı şifresi) bağlı olmasını sağlar ve hiçbir devlet hem bilmeden önceden hesaplanabilir. Bu önemli fark nedeniyle, bcrypttek yönlü bir karma algoritmasıdır. Tuz, mermi ve anahtarı (parola) bilmeden düz metin parolasını alamazsınız . [ Kaynak ]

Bcrypt nasıl kullanılır:

PHP Kullanımı> = 5.5-DEV

Parola karma işlevleri artık doğrudan PHP> = 5.5 içine yerleştirilmiştir . Artık herhangi bir parolanın karmasını password_hash()oluşturmak için kullanabilirsiniz bcrypt:

<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

// Usage 2:
$options = [
  'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

Kullanıcının sağladığı şifreyi mevcut bir karmaya karşı doğrulamak için aşağıdakini kullanabilirsiniz password_verify():

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

PHP> = 5.3.7, <5.5-DEV (ayrıca RedHat PHP> = 5.3.3) kullanma

Bir yoktur uyumluluk kütüphanesi üzerinde GitHub'dan aynı işlevi sağlayan aslen Yukarıdaki yapıyı C fonksiyonlarının kaynak kodu, göre oluşturulur. Uyumluluk kitaplığı yüklendikten sonra, kullanım yukarıdakiyle aynıdır (hala 5.3.x dalındaysanız steno dizisi gösterimi eksi).

PHP Kullanımı <5.3.7 (DEPRECATED)

crypt()Girdi dizelerinin bcrypt karmaları oluşturmak için işlevi kullanabilirsiniz . Bu sınıf otomatik olarak tuz üretebilir ve mevcut karmaları bir girdi karşısında doğrulayabilir. PHP'nin 5.3.7 veya daha yüksek bir sürümünü kullanıyorsanız, yerleşik işlevi veya uyumlu kitaplığı kullanmanız önemle tavsiye edilir . Bu alternatif yalnızca tarihi amaçlar için sağlanmıştır.

class Bcrypt{
  private $rounds;

  public function __construct($rounds = 12) {
    if (CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->rounds = $rounds;
  }

  public function hash($input){
    $hash = crypt($input, $this->getSalt());

    if (strlen($hash) > 13)
      return $hash;

    return false;
  }

  public function verify($input, $existingHash){
    $hash = crypt($input, $existingHash);

    return $hash === $existingHash;
  }

  private function getSalt(){
    $salt = sprintf('$2a$%02d$', $this->rounds);

    $bytes = $this->getRandomBytes(16);

    $salt .= $this->encodeBytes($bytes);

    return $salt;
  }

  private $randomState;
  private function getRandomBytes($count){
    $bytes = '';

    if (function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
      $bytes = openssl_random_pseudo_bytes($count);
    }

    if ($bytes === '' && is_readable('/dev/urandom') &&
       ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
      $bytes = fread($hRand, $count);
      fclose($hRand);
    }

    if (strlen($bytes) < $count) {
      $bytes = '';

      if ($this->randomState === null) {
        $this->randomState = microtime();
        if (function_exists('getmypid')) {
          $this->randomState .= getmypid();
        }
      }

      for ($i = 0; $i < $count; $i += 16) {
        $this->randomState = md5(microtime() . $this->randomState);

        if (PHP_VERSION >= '5') {
          $bytes .= md5($this->randomState, true);
        } else {
          $bytes .= pack('H*', md5($this->randomState));
        }
      }

      $bytes = substr($bytes, 0, $count);
    }

    return $bytes;
  }

  private function encodeBytes($input){
    // The following is code from the PHP Password Hashing Framework
    $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    $output = '';
    $i = 0;
    do {
      $c1 = ord($input[$i++]);
      $output .= $itoa64[$c1 >> 2];
      $c1 = ($c1 & 0x03) << 4;
      if ($i >= 16) {
        $output .= $itoa64[$c1];
        break;
      }

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 4;
      $output .= $itoa64[$c1];
      $c1 = ($c2 & 0x0f) << 2;

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 6;
      $output .= $itoa64[$c1];
      $output .= $itoa64[$c2 & 0x3f];
    } while (true);

    return $output;
  }
}

Bu kodu şu şekilde kullanabilirsiniz:

$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);

Alternatif olarak, Portable PHP Hashing Framework'ü de kullanabilirsiniz .


7
@ Kötü Pire: Sizi hayal kırıklığına uğrattığım için özür dileriz, aynı mt_rand()zamanda geçerli saat ve geçerli işlem kimliği kullanılarak da ekilir. Bakınız GENERATE_SEED()içinde/ext/standard/php_rand.h .
Andrew Moore

53
@Mike: Devam et, tam da bu nedenle orada!
Andrew Moore

14
GetSalt işlevinde $ salt dizesinin başlangıcını değiştirmeleri gerektiğini düşünen herkes için bu gerekli değildir. $ 2a $ __, CRYPT_BLOWFISH tuzunun bir parçasıdır. Dokümanlardan: "Blowfish aşağıdaki gibi bir tuz ile hash eder:" $ 2a $ ", iki basamaklı bir maliyet parametresi," $ "ve alfabeden 22 basamak".
jwinn

18
@MichaelLang: İyi bir şey crypt()hakemli ve doğrulanır. Yukarıdaki kod crypt(), POSIX crypt()işlevini çağıran PHP'leri çağırır . Yukarıdaki tüm kodlar, aramadan önce rastgele bir tuz (kriptografik olarak güvenli olması gerekmez, tuz bir sır olarak kabul edilmez) üretir crypt(). Belki kurt çağırmadan önce biraz araştırma yapmalısın.
Andrew Moore

31
Bu cevabın iyi olsa da yaşını göstermeye başladığını lütfen unutmayın. Bu kod (güvenilen herhangi bir PHP uygulaması gibi crypt()) 5.3.7 öncesi bir güvenlik açığına tabidir ve 5.3.7 sonrası (çok az) verimsizdir - ilgili sorunun ayrıntıları burada bulunabilir . Ayrıca, yeni parola karma API'sının ( geriye doğru uyumluluk lib ) artık uygulamanızda bcrypt parola karma uygulaması için tercih edilen yöntem olduğunu unutmayın.
DaveRandom

295

Yani, bcrypt kullanmak ister misin? Müthiş! Ancak, diğer şifreleme alanları gibi, bunu kendiniz yapmamalısınız. Anahtarları yönetmek, tuz depolamak veya rasgele sayılar üretmek gibi bir şey hakkında endişelenmeniz gerekiyorsa, bunu yanlış yapıyorsunuz.

Nedeni basit: bcrypt'i vidalamak çok kolay . Aslında, bu sayfadaki hemen hemen her kod parçasına bakarsanız, bunun bu yaygın sorunlardan en az birini ihlal ettiğini fark edeceksiniz.

Yüzleş, Kriptografi zor.

Uzmanlara bırakın. İşi bu kütüphaneleri korumak olan insanlar için bırakın. Bir karar vermeniz gerekiyorsa, yanlış yapıyorsunuz.

Bunun yerine bir kütüphane kullanın. İhtiyaçlarınıza bağlı olarak birkaç tane var.

Kütüphaneler

Aşağıda, daha yaygın olan bazı API'ların dökümü verilmiştir.

PHP 5.5 API - (5.3.7+ için kullanılabilir)

PHP 5.5'ten başlayarak, parolaları karmaleştirmek için yeni bir API tanıtılmaktadır. 5.3.7+ için (benim tarafımdan) korunan bir şim uyumluluk kütüphanesi de var. Bunun hakemli ve kullanımı kolay bir uygulama olma avantajı vardır .

function register($username, $password) {
    $hash = password_hash($password, PASSWORD_BCRYPT);
    save($username, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    if (password_verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Gerçekten, son derece basit olması amaçlanıyor.

Kaynaklar:

Zend \ Crypt \ Password \ Bcrypt (5.3.2+)

Bu, PHP 5.5'inkine benzer başka bir API ve benzer bir amaç yapıyor.

function register($username, $password) {
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    $hash = $bcrypt->create($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    if ($bcrypt->verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Kaynaklar:

PasswordLib

Bu, parola karma işlemine biraz farklı bir yaklaşımdır. PasswordLib sadece bcrypt'i desteklemek yerine çok sayıda karma algoritmasını destekler. Temel olarak, kontrolünüz dışında olabilecek eski ve farklı sistemlerle uyumluluğu desteklemeniz gereken bağlamlarda yararlıdır. Çok sayıda karma algoritmasını destekler. Ve 5.3.2+

function register($username, $password) {
    $lib = new PasswordLib\PasswordLib();
    $hash = $lib->createPasswordHash($password, '$2y$', array('cost' => 12));
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $lib = new PasswordLib\PasswordLib();
    if ($lib->verifyPasswordHash($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Referanslar:

  • Kaynak Kodu / Belgeler: GitHub

PHPASS

Bu, bcrypt'i destekleyen bir katmandır, ancak PHP> = 5.3.2'ye erişiminiz yoksa kullanışlı olan oldukça güçlü bir algoritmayı da destekler ... Aslında PHP 3.0+'yi destekler (bcrypt ile olmasa da).

function register($username, $password) {
    $phpass = new PasswordHash(12, false);
    $hash = $phpass->HashPassword($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $phpass = new PasswordHash(12, false);
    if ($phpass->CheckPassword($password, $hash)) {
        //login
    } else {
        // failure
    }
}

kaynaklar

Not: Açık duvarda barındırılmayan PHPASS alternatiflerini kullanmayın, bunlar farklı projelerdir !!!

BCrypt Hakkında

Dikkat ederseniz, bu kitaplıkların her biri tek bir dize döndürür. Bunun nedeni BCrypt'in dahili olarak nasıl çalıştığıdır. Ve bununla ilgili bir ton TON var. Burada yazdığım, buraya kopyalayamayacağım / yapıştıramayacağım, ancak bağlantı veren bir seçim:

Sarmak

Birçok farklı seçenek var. Seçtiğiniz size kalmış. Ancak, bunu sizin için yukarıdaki kütüphanelerden birini kullanmanızı şiddetle tavsiye ederim.

Yine, crypt()doğrudan kullanıyorsanız , muhtemelen yanlış bir şey yapıyorsunuzdur. Kodunuz doğrudan hash()(veya md5()veya sha1()) kullanıyorsa , neredeyse kesinlikle yanlış bir şey yapıyorsunuzdur.

Sadece bir kütüphane kullanın ...


7
Tuz rastgele üretilmelidir, ancak güvenli bir rastgele kaynaktan gelmesi gerekmez. Tuz bir sır değildir . Bir sonraki tuzu tahmin edebilmenin gerçek bir güvenlik etkisi yoktur; şifrelenen her şifre için farklı tuzlar üretmek için yeterince büyük bir veri havuzundan geldikleri sürece, iyidir. Unutmayın, eğer karmaşlarınız kötü ellere geçerse, gökkuşağı masalarının kullanımını önlemek için tuz var. Gizli değiller.
Andrew Moore

7
@AndrewMoore kesinlikle doğru! Bununla birlikte, tuzun istatistiksel olarak benzersiz olması için yeterli entropiye sahip olması gerekir. Sadece uygulamanızda değil, tüm uygulamalarda. Yani mt_rand()yeterince yüksek bir süreye sahiptir, ancak tohum değeri sadece 32 bittir. Bu yüzden mt_rand()etkili bir şekilde kullanmak sizi sadece 32 bit entropi ile sınırlar. Bu da Doğum Günü Sorunu sayesinde, sadece 7k üretilen tuzlarda (küresel olarak)% 50 çarpışma şansınız olduğu anlamına gelir. Yana bcrypttuz 128 bit kabul, hepsi 128 bit ;-) sağlayabilmektedir bir kaynak kullanmak daha iyidir. (128 bitte, 2e19 hash'de% 50 çarpışma şansı olur) ...
ircmaxell

1
@ircmaxell: "Yeterince büyük veri havuzu" nu küçültün. Bununla birlikte, kaynağınızın 128 bit için yeterince yüksek, ÇOK YÜKSEK bir entropi kaynağı olması gerekmez. Ancak, tüm kullanılabilir kaynaklarınızı tükettiyseniz (OpenSSL vb. Yok) ve tek geri dönüşünüz mt_rand () ise, hala alternatif olandan daha iyidir (rand ()).
Andrew Moore

4
@ AndrewMoore: kesinlikle. Bunu tartışmamak. Sadece bu mt_randve uniqid(ve dolayısıyla lcg_valueve rand) ilk seçenek değildir ...
ircmaxell

1
ircmaxell, 5.3.xx için password_compat kütüphanesi için çok teşekkür ederim, buna daha önce ihtiyacımız olmadı, ancak şimdi 5.3.xx php sunucusunda yapıyoruz ve bu mantığı yapmaya çalışmamanız için açık tavsiyeniz için teşekkür ederiz kendini.
Lizardx

47

The Rainbow Tables ile Yeter: Bir sürü bilgi alacaksınız : Güvenli Şifre Şemaları veya Taşınabilir PHP şifre hashing çerçevesi hakkında bilmeniz gerekenler .

Amaç, parola yavaş bir şey ile hash etmektir, bu yüzden parola veritabanınızı alan birisi onu kaba zorlamaya çalışırken ölecektir (parolayı kontrol etmek için 10 ms gecikme sizin için hiçbir şey değildir, kaba zorlamaya çalışan biri için çok fazladır). Bcrypt yavaştır ve ne kadar yavaş olduğunu seçmek için bir parametre ile kullanılabilir.


7
İstediğinizi zorlayın, kullanıcılar aynı şifreyi birden çok şeye bağlamayı başaracaklar. Bu yüzden mümkün olduğunca korumanız veya herhangi bir şifre (SSO, openID vb.) Saklamanıza izin vermeyen bir şey uygulamanız gerekir.
Arkh

41
Hayır. Parola karması bir saldırıya karşı korumak için kullanılır: birisi veritabanınızı çaldı ve açık metin giriş + parolaları almak istiyor.
Arkh

4
@Josh K. Bazı basit şifreleri ayarlanmış phpass aracılığıyla aldıktan sonra kırmaya çalışmanızı öneririm, böylece web sunucunuzda hesaplamak 1ms ve 10ms arasında sürer.
Arkh

3
Kabul. Ancak qwerty'yi şifre olarak kullanacak olan kullanıcı, karmaşık bir kişiyi (ve saldırganların) kolayca okuyabileceği türden bir kullanıcıyı işaretleyecek türden bir kullanıcıdır. Ne bcrypt kullanarak başarır db sizin irade karşı kamu gittiğinde, ^ | $$ & ZL6- £ gibi bazı şifre olan bu kullanıcıya bir geçişte sha512 kullanmak daha zor olacaktır.
Arkh

4
@coreyward, bunu yapmanın hiç engellemekten daha zararlı olduğunu belirtmeye değer; kolayca "hizmet reddi" vektörü olarak kabul edilir. Bilinen hesaplarda kötü girişlere spam göndermeye başlayın ve birçok kullanıcıyı çok, çok kolay bir şekilde bozabilirsiniz. Saldırganı, özellikle ücretli bir müşteriyse, erişimi engellemeyi reddetmekten daha iyi bir şekilde yapmak daha iyidir.
damianb

36

PHP'nin crypt()işlevini kullanarak ve uygun bir Blowfish tuzu geçirerek bcrypt ile tek yönlü bir karma oluşturabilirsiniz . Tüm denklemin en önemlisi, A) algoritmanın tehlikeye girmediği ve B) her şifreyi doğru şekilde tuzladığınızdır . Uygulama çapında bir tuz kullanmayın; tek bir Rainbow tablo kümesinden saldırmak için tüm uygulamanızı açar.

PHP - Crypt İşlevi


4
Bu doğru yaklaşımdır - crypt()birkaç farklı parola karma işlevini destekleyen PHP'nin işlevini kullanın . Kullanmadığınızdan emin olun CRYPT_STD_DESveya CRYPT_EXT_DES- desteklenen diğer türlerden herhangi biri iyidir (ve adın altında bcrypt içerir CRYPT_BLOWFISH).
caf

4
SHA'nın gerçekten de 'mermi' seçeneği ile bir maliyet parametresi vardır. Bunu kullanırken bcrypt'i tercih etmek için hiçbir neden göremiyorum.
Pieter Ennes

3
Aslında, bir şifrenin tek bir SHA-1'i (veya MD5), tuzlu veya tuzsuz olarak kolayca kolayca kaba-kuvvet uygulayabilmektedir (tuz, brüt zorlamaya karşı değil, gökkuşağı tablolarına karşı yardımcı olur). Bcrypt kullanın.
Paŭlo Ebermann

Ben php crypt () demek herkes "bcrypt" demek gibi görünüyor rahatsız edici.
Sliq

3
@Panique Neden? Algoritmaya bcrypt denir . cryptbcrypt CRYPT_BLOWFISHsabitine karşılık gelen birkaç parola karması ortaya koyar . Bcrypt şu anda desteklenen en güçlü algoritmadır cryptve desteklediği diğer bazıları oldukça zayıftır.
CodesInChaos

34

Düzenleme: 2013.01.15 - Sunucunuz destekleyecekse, bunun yerine martinstoeckli'nin çözümünü kullanın.


Herkes bunu daha karmaşık hale getirmek istiyor. Crypt () işlevi işin çoğunu yapar.

function blowfishCrypt($password,$cost)
{
    $chars='./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $salt=sprintf('$2y$%02d$',$cost);
//For PHP < PHP 5.3.7 use this instead
//    $salt=sprintf('$2a$%02d$',$cost);
    //Create a 22 character salt -edit- 2013.01.15 - replaced rand with mt_rand
    mt_srand();
    for($i=0;$i<22;$i++) $salt.=$chars[mt_rand(0,63)];
    return crypt($password,$salt);
}

Misal:

$hash=blowfishCrypt('password',10); //This creates the hash
$hash=blowfishCrypt('password',12); //This creates a more secure hash
if(crypt('password',$hash)==$hash){ /*ok*/ } //This checks a password

Açık olması gerektiğini biliyorum, ancak lütfen şifrenizi 'şifre' kullanmayın.


3
Tuzun oluşturulması geliştirilebilir (işletim sisteminin rastgele kaynağını kullanın), aksi takdirde bana iyi geliyor. Yeni PHP sürümleri için onu kullanmak daha iyidir 2yyerine 2a.
Mart

mcrypt_create_iv($size, MCRYPT_DEV_URANDOM)tuz için kaynak olarak kullanın .
CodesInChaos

Bir an aldığımda mcrypt_create_iv () 'e daha yakından bakacağım, başka bir şey yoksa performansı biraz iyileştirmelidir.
Jon Hulka

2
Base64 kodlaması ekleyin ve özel alfabe bcryptkullanır çevirir . mcrypt_create_iv(17, MCRYPT_DEV_URANDOM), str_replace('+', '.', base64_encode($rawSalt)),$salt = substr($salt, 0, 22);
CodesInChaos

1
@JonHulka - PHP'nin uyumluluk paketine bir göz atın [Line 127], bu basit bir uygulamadır.
martinstoeckli

29

PHP 5.5 sürümü BCrypt, fonksiyonları password_hash()ve için yerleşik destek olacaktır password_verify(). Aslında bunlar sadece işlevin etrafındaki sarmalayıcılardır crypt()ve doğru bir şekilde kullanılmasını kolaylaştıracaktır. Güvenli bir rastgele tuz üretilmesini sağlar ve iyi varsayılan değerler sağlar.

Bu işlevleri kullanmanın en kolay yolu:

$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

Bu kod, şifreyi BCrypt (algoritma 2y) ile hash eder , OS rasgele kaynağından rastgele bir tuz üretir ve varsayılan maliyet parametresini kullanır (şu anda 10'dur). İkinci satır, kullanıcının girdiği parolanın önceden kaydedilmiş bir karma değerle eşleşip eşleşmediğini kontrol eder.

Maliyet parametresini değiştirmek isterseniz, bunu şu şekilde yapabilirsiniz, maliyet parametresini 1 artırarak, karma değerini hesaplamak için gereken süreyi iki katına çıkarır:

$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 11));

"cost"Parametrenin aksine, parametreyi atlamak en iyisidir "salt", çünkü işlev zaten kriptografik olarak güvenli bir tuz oluşturmak için elinden gelenin en iyisini yapar.

PHP sürüm 5.3.7 ve üstü için, aynı yazarın işlevi yapan bir uyumluluk paketi vardır password_hash(). 5.3.7'den önceki PHP sürümleri için , unicode güvenli BCrypt algoritması crypt()ile destek yoktur 2y. Bunun yerine 2a, önceki PHP sürümleri için en iyi alternatif olan bunun yerine geçebilir .


3
Bunu okuduktan sonra, ilk düşüncem "üretilen tuzu nasıl saklıyorsun?" Dokümanlar üzerinde gezindikten sonra, password_hash () işlevi, şifreleme yöntemini, tuzu ve oluşturulan karmayı depolayan bir dize oluşturur. Yani, password_verify () işlevinin çalışması için gereken her şeyi tek bir dizede saklar. Sadece bundan bahsetmek istedim, çünkü bunu gördüklerinde başkalarına yardımcı olabilir.
jzimmerman2011

@ jzimmerman2011 - Tam olarak, başka bir cevapta bu depolama biçimini bir örnekle açıklamaya çalıştım.
martinstoeckli

7

Şu anki düşünce: karmalar mümkün olan en hızlı değil mümkün olan en yavaş olmalıdır. Bu gökkuşağı masası saldırılarını bastırır .

Ayrıca ilgili, ancak önlem: Bir saldırganın giriş ekranınıza asla sınırsız erişimi olmamalıdır. Bunu önlemek için: URI ile birlikte her isabeti kaydeden bir IP adresi izleme tablosu oluşturun. Beş dakikalık bir sürede aynı IP adresinden 5'ten fazla oturum açma denemesi gelirse, açıklamayı engelleyin. İkincil bir yaklaşım, bankalar gibi iki katmanlı bir şifre düzenine sahip olmaktır. İkinci geçişteki arızalar için bir kilitleme yapılması güvenliği artırır.

Özet: zaman alan karma işlevlerini kullanarak saldırganı yavaşlatır. Ayrıca, girişinize çok fazla erişimi engelleyin ve ikinci bir şifre katmanı ekleyin.


Saldırganın DB'imi başka bir yolla çalmayı başardığını ve şimdi paypal veya başka bir şeyde denemek için şifreleri çıkarmaya çalıştığını düşünüyorum.
Vilx-

4
2012'nin yarısı ve bu cevap hala sakat, yavaş karma algoritması gökkuşağı tablosu saldırılarını nasıl önler? Ben rastgele bir bayt aralığı tuz düşündüm? Her zaman hash algoritmasının hızının, belirli bir süre içinde aldıkları hash'a karşı kaç iterasyon gönderebileceğini belirtti. Ayrıca ASLA BAŞARISIZ GİRİŞ GİRİŞLERİNDEKİ BİR KULLANICIYI KESİNLİKLE Kullanıcılarınızın bıkacağına güveniyorum, genellikle bazı sitelerde bunun için şifremi hatırlamadan önce 5 kez daha giriş yapmam gerekiyor. Ayrıca ikinci geçiş katmanı çalışmıyor, cep telefonu kodu ile iki adım yetki olsa olabilir.
Sammaye

1
@ Sammaye Bunu bir noktaya katılıyorum. 5 başarısız giriş denemesinde bir bloğu hızlı bir şekilde 7'ye yükseltmeden önce, sonra 10 şimdi 20'de oturuyor. Normal bir kullanıcının 20 başarısız giriş denemesi olmamalı, ancak kaba kuvvet saldırılarını kolayca durduracak kadar düşük
Bruce Aldridge

@BruceAldridge Şahsen ben 7 başarısız oturum açma ve blok yerine bir captcha göstermek sonra söylemek, rastgele bir süre için komut dosyası duraklatmak için daha iyi olacağını düşünüyorum. Engelleme, çok agresif bir hamle.
Sammaye

1
@Sammaye Kalıcı blokların kötü olduğunu kabul ediyorum. Başarısız denemelerin sayısı ile artan geçici bir bloğa atıfta bulunuyorum.
Bruce Aldridge

7

İşte bu eski sorunun güncellenmiş bir cevabı!

5.5'ten beri PHP'de parolaları karıştırmanın password_hash()doğru yolu ve doğrulamak için doğru yol budur password_verify()ve bu PHP 8.0'da hala geçerlidir. Bu işlevler varsayılan olarak bcrypt karmalarını kullanır, ancak diğer daha güçlü algoritmalar eklenmiştir. password_hashParametreleri kullanarak çalışma faktörünü (şifrelemenin ne kadar "güçlü" olduğu etkin bir şekilde) değiştirebilirsiniz .

Bununla birlikte, hala yeterince güçlü olmasına rağmen, bcrypt artık son teknoloji olarak kabul edilmemektedir ; şifre hash algoritmalar daha iyi bir dizi olarak adlandırılan geldi etmiştir Argon2 Argon2i, Argon2d ile, ve Argon2id varyantları. Aralarındaki fark ( burada açıklandığı gibi ):

Argon2'nin bir birincil varyantı vardır: Argon2id ve iki tamamlayıcı varyant: Argon2d ve Argon2i. Argon2d, veriye bağlı bellek erişimini kullanır, bu da kripto para birimleri ve yan kanal zamanlama saldırılarından hiçbir tehdidi olmayan iş kanıtı uygulamaları için uygun olmasını sağlar. Argon2i, parola karması ve parola tabanlı anahtar türevi için tercih edilen veri bağımsız bellek erişimi kullanır. Argon2id, bellek üzerindeki ilk yinelemenin ilk yarısı için Argon2i ve geri kalanı için Argon2d olarak çalışır, böylece hem bellek kanalı dengesizlikleri nedeniyle hem yan kanal saldırı koruması ve kaba kuvvet maliyet tasarrufu sağlar.

PHP 7.2'de Argon2i desteği eklendi ve şu şekilde talep ettiniz:

$hash = password_hash('mypassword', PASSWORD_ARGON2I);

ve PHP 7.3'te Argon2id desteği eklendi:

$hash = password_hash('mypassword', PASSWORD_ARGON2ID);

Ortaya çıkan karma dize, oluşturulduğunda hangi algoritma, tuz ve çalışma faktörlerinin kullanıldığı hakkında bilgi içerdiğinden şifreleri doğrulamak için herhangi bir değişiklik gerekmez.

Oldukça ayrı (ve biraz fazla), libsodium (PHP 7.2'de eklenmiştir) , PHP yerleşikleriyle aynı şekilde çalışan sodium_crypto_pwhash_str ()ve sodium_crypto_pwhash_str_verify()işlevleri aracılığıyla Argon2 karma sağlar . Bunları kullanmanın olası bir nedeni, PHP'nin bazen libargon2 olmadan derlenebilmesidir, bu da Argon2 algoritmalarını password_hash işlevi için kullanılamaz hale getirir; PHP 7.2 ve sonraki sürümlerde her zaman libsodium etkin olmalıdır, ancak olmayabilir - ancak en azından bu algoritmada iki yol vardır. Libsodium ile Argon2id karmasını nasıl oluşturabileceğiniz aşağıda açıklanmıştır (PHP 7.2'de bile, aksi takdirde Argon2id desteğinden yoksundur):

$hash = sodium_crypto_pwhash_str(
    'mypassword',
    SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
    SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

Bir tuzu elle belirtmenize izin vermediğini unutmayın; bu, libsodium etosunun bir parçasıdır - kullanıcıların güvenliği tehlikeye atabilecek değerlere param ayarlamasına izin vermeyin - örneğin, PHP'nin password_hashişlevine boş bir tuz dizesi geçirmenizi engelleyen hiçbir şey yoktur ; libsodium bu kadar saçma bir şey yapmanıza izin vermez!



1

Hepimizin bildiği gibi, şifreyi veritabanında açık metin olarak saklamak güvenli değildir. bcrypt bir karma şifre tekniğidir. şifre güvenliği oluşturmak için kullanılır. bcrypt'in şaşırtıcı işlevlerinden biri, parolayı saldırılara karşı korumak için kullanılan korsanlardan bizi kurtarmasıdır, çünkü parola bcrypted formunda saklanır.

password_hash () işlevi yeni bir şifre karması oluşturmak için kullanılır. Güçlü ve sağlam bir karma algoritması kullanır. Password_hash () işlevi crypt () işleviyle çok uyumludur. Bu nedenle, crypt () tarafından oluşturulan parola karmaları password_hash () ve tersi ile kullanılabilir. Password_verify () ve password_hash () işlevleri yalnızca crypt () işlevinin etrafındaki sarmalayıcıları kullanır ve doğru olarak kullanılmasını çok kolaylaştırır.

SÖZDİZİMİ

string password_hash($password , $algo , $options)

Aşağıdaki algoritmalar şu anda password_hash () işlevi tarafından desteklenmektedir:

PASSWORD_DEFAULT PASSWORD_BCRYPT PASSWORD_ARGON2I PASSWORD_ARGON2ID

Parametreler: Bu işlev yukarıda belirtildiği ve aşağıda açıklanan üç parametreyi kabul eder:

password : Kullanıcının şifresini saklar. algo : Şifrenin karması gerçekleştiğinde kullanılacak algoritmayı belirtirken sürekli kullanılan şifre algoritması sabitidir. options : Seçenekleri içeren ilişkilendirilebilir bir dizidir. Bu çıkarılır ve içermezse, rastgele bir tuz kullanılır ve varsayılan bir maliyetin kullanılması gerçekleşir. Dönüş Değeri : Başarıyla karma parolasını veya başarısız olduğunda False değerini döndürür.

Örnek :

Input : echo password_hash("GFG@123", PASSWORD_DEFAULT); Output : $2y$10$.vGA19Jh8YrwSJFDodbfoHJIOFH)DfhuofGv3Fykk1a

Aşağıdaki programlar PHP'deki password_hash () işlevini göstermektedir:

<?php echo password_hash("GFG@123", PASSWORD_DEFAULT); ?>

ÇIKTI

$2y$10$Z166W1fBdsLcXPVQVfPw/uRq1ueWMA6sLt9bmdUFz9AmOGLdM393G

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.