Bir cevap göndereceğim çünkü mevcut cevaplardan bazıları yakın ama şunlardan birine sahip:
- kaba kuvvet zorlamanın daha kolay olması veya aynı entropi için parolanın daha uzun olması için istediğinizden daha küçük bir karakter alanı
- şifreli olarak güvenli kabul edilmeyen bir RNG
- bazı üçüncü taraf kütüphaneleri için bir gereklilik ve bunu kendiniz yapmak için ne gerektiğini göstermenin ilginç olabileceğini düşündüm
Bu cevap count/strlen
, oluşturulan parolanın güvenliği, en azından IMHO, oraya nasıl ulaştığınızı aştığından sorunu ortadan kaldıracaktır . Ben de PHP> 5.3.0 olduğunu varsayacağım.
Sorunu kurucu parçalara ayıralım:
- rasgele veri almak için güvenli bir rasgelelik kaynağı kullanın
- bu verileri kullanın ve bazı yazdırılabilir dize olarak temsil edin
İlk kısım için PHP> 5.3.0 fonksiyonu sağlar openssl_random_pseudo_bytes
. Çoğu sistem kriptografik olarak güçlü bir algoritma kullanırken, bir paketleyici kullanmamız için kontrol etmeniz gerektiğini unutmayın:
/**
* @param int $length
*/
function strong_random_bytes($length)
{
$strong = false; // Flag for whether a strong algorithm was used
$bytes = openssl_random_pseudo_bytes($length, $strong);
if ( ! $strong)
{
// System did not use a cryptographically strong algorithm
throw new Exception('Strong algorithm not available for PRNG.');
}
return $bytes;
}
İkinci kısım için, base64_encode
bir bayt dizesi aldığından ve orijinal soruda belirtilene çok yakın bir alfabeye sahip bir dizi karakter üreteceğinden kullanacağız. Biz sahip aldırmadı ise +
, /
ve =
karakterler son dizede görünür ve biz en azından bir sonuç istiyorum $n
karakterden, biz sadece kullanabilirsiniz:
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
3/4
Faktör nedeniyle base64 bayt dize daha az üçte daha büyük bir uzunluğa sahip olan bir dizede sonuçları kodlayan gerçeği etmektir. Sonuç, $n
aksi takdirde 4'ün katları ve 3 karaktere kadar daha uzun olması için kesin olur . Fazladan karakterler ağırlıklı olarak dolgu karakteri olduğundan =
, bir nedenden dolayı parolanın tam bir uzunluk olduğu konusunda bir kısıtlamamız olsaydı, onu istediğimiz uzunlukta kısaltabiliriz. Bunun nedeni, özellikle $n
, belirli bir şifre için tüm şifrelerin aynı sayı ile bitmesi ve sonuç şifresine erişimi olan bir saldırganın tahmin edilmesi gereken en az 2 karaktere sahip olmasıdır.
Ekstra kredi için, OP'nin sorusundaki spesifikasyonu karşılamak istersek, biraz daha fazla iş yapmamız gerekirdi. Burada temel dönüşüm yaklaşımından vazgeçeceğim ve hızlı ve kirli bir yaklaşımla gideceğim. Her ikisi de 62 giriş uzunluğundaki alfabe nedeniyle sonuçta kullanılacak olandan daha fazla rasgelelik üretmelidir.
Sonuçtaki ekstra karakterler için, bunları elde edilen dizeden atabiliriz. Bayt dizemizde 8 baytla başlarsak, base64 karakterlerinin yaklaşık% 25'i bu "istenmeyen" karakterler olur, böylece bu karakterleri atmak OP'den daha kısa olmayan bir dizeyle sonuçlanır. O zaman kesin uzunluğa inmek için kısaltabiliriz:
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
Daha uzun parolalar oluşturursanız, dolgu karakteri =
ara sonucun daha küçük ve daha küçük bir oranını oluşturur, böylece PRNG için kullanılan entropi havuzunun boşaltılması endişe verici ise daha yalın bir yaklaşım uygulayabilirsiniz.