2009-03-12 43 views
36

Tôi đang tìm cách tạo một hàm có thể tái sử dụng sẽ tạo ra một khóa ngẫu nhiên với các ký tự ACSII có thể in có độ dài được chọn (bất cứ nơi nào từ 2 đến 1000+). Tôi nghĩ rằng ký tự ASCII có thể in sẽ là 33-126. Khóa chính không cần phải hoàn toàn độc đáo, chỉ duy nhất nếu được tạo chính xác cùng một mili giây (vì vậy uniqid() sẽ không hoạt động).Cách tốt nhất để tạo ra một khóa ngẫu nhiên trong PHP là gì?

Tôi nghĩ rằng sự kết hợp của chr()mt_rand() có thể hoạt động.

Đây có phải là cách để đi hay phương pháp nào khác là phương pháp tốt nhất?

Chỉnh sửa:uniqid() cũng sẽ không hoạt động do không có tham số chiều dài, nó chỉ là bất kỳ PHP nào cung cấp cho bạn.

Idea My: Đây là những gì tôi đã đưa ra:

function GenerateKey($length = 16) { 
    $key = ''; 

    for($i = 0; $i < $length; $i ++) { 
     $key .= chr(mt_rand(33, 126)); 
    } 

    return $key; 
} 

Có bất kỳ vấn đề với điều này?

Một chỉnh sửa khác: Hầu hết các câu hỏi khác giải quyết việc tạo mật khẩu. Tôi muốn có nhiều ký tự hơn và tôi không quan tâm đến số 1 so với l. Tôi muốn số lượng chìa khóa tối đa có thể thực hiện được.

Lưu ý: khóa được tạo không nhất thiết phải bảo mật về mặt mã hóa.

+0

máy phát điện số ngẫu nhiên làm độc đáo không thường _guarantee_, ngay cả khi “Được tạo ra ở chính xác cùng một phần nghìn giây.” Để đảm bảo tính duy nhất, bạn cần có khả năng phát hiện xung đột. – danorton

+0

Đã thêm cảnh báo lớn về bảo mật, nếu không tôi sẽ phải từ chối mọi câu trả lời. Được cảnh báo rằng một số các chức năng trong các câu trả lời trả về nhị phân, những người khác trở lại hex, những người khác base64 vv vv. –

Trả lời

54

Cập nhật (12/2015): Đối với PHP 7.0, bạn nên sử dụng random_int() thay vì mt_rand vì nó cung cấp "giá trị mã hóa an toàn"

Cá nhân, tôi thích sử dụng sha1(microtime(true).mt_rand(10000,90000)) nhưng bạn đang tìm kiếm hơn một cách tiếp cận tùy biến, vì vậy hãy thử chức năng này (đó là một sự sửa đổi để yêu cầu của bạn this answer):

function rand_char($length) { 
    $random = ''; 
    for ($i = 0; $i < $length; $i++) { 
    $random .= chr(mt_rand(33, 126)); 
    } 
    return $random; 
} 

Tuy nhiên, điều này có lẽ sẽ chậm hơn so uniqid đáng kể(), md5(), hoặc sha1().

Chỉnh sửa: Có vẻ như bạn đã làm điều đó trước, xin lỗi. : D

Chỉnh sửa 2: tôi quyết định làm một thử nghiệm nhỏ đẹp trên máy tính Debian của tôi với PHP 5 và eAccelerator (tha mã dài):

function rand_char($length) { 
    $random = ''; 
    for ($i = 0; $i < $length; $i++) { 
    $random .= chr(mt_rand(33, 126)); 
    } 
    return $random; 
} 

function rand_sha1($length) { 
    $max = ceil($length/40); 
    $random = ''; 
    for ($i = 0; $i < $max; $i ++) { 
    $random .= sha1(microtime(true).mt_rand(10000,90000)); 
    } 
    return substr($random, 0, $length); 
} 

function rand_md5($length) { 
    $max = ceil($length/32); 
    $random = ''; 
    for ($i = 0; $i < $max; $i ++) { 
    $random .= md5(microtime(true).mt_rand(10000,90000)); 
    } 
    return substr($random, 0, $length); 
} 

$a = microtime(true); 
for ($x = 0; $x < 1000; $x++) 
    $temp = rand_char(1000); 

echo "Rand:\t".(microtime(true) - $a)."\n"; 

$a = microtime(true); 
for ($x = 0; $x < 1000; $x++) 
    $temp = rand_sha1(1000); 

echo "SHA-1:\t".(microtime(true) - $a)."\n"; 

$a = microtime(true); 
for ($x = 0; $x < 1000; $x++) 
    $temp = rand_md5(1000); 

echo "MD5:\t".(microtime(true) - $a)."\n"; 

Kết quả:

Rand: 2.09621596336 
SHA-1: 0.611464977264 
MD5: 0.618473052979 

Vì vậy, đề nghị của tôi, nếu bạn muốn tốc độ (nhưng không đầy đủ bộ ký tự), là để dính vào MD5, SHA-1, hoặc Uniqid (mà tôi đã không kiểm tra .. chưa)

+1

Đánh bại ya chỉ bằng một vài giây. –

+3

Đánh bại ya chỉ sau vài tháng;) – lpfavreau

+0

+1 cho câu trả lời và sửa đổi rõ ràng đối với mã ban đầu, điều này tốt hơn khi sử dụng mt_rand() – lpfavreau

0

that question có quan tâm đến bạn không?

Tôi không chắc tại sao uniqid() không hoạt động cho bạn và trong trường hợp nào bạn cần một số duy nhất trong cùng một phần nghìn giây nhưng không nhất thiết phải khác; bạn đang tạo ra cái gì quá nhanh đến mức trong cùng một phần nghìn giây bạn có thể có một va chạm? Tôi tự hỏi bao nhiêu thời gian để uniqid() chỉ cần tạo ra số của nó. Nếu bạn muốn, hãy sử dụng tham số tiền tố của hàm uniqid() với một vài chữ cái ngẫu nhiên và bạn nên an toàn.

Nếu đó là để tạo tệp, bạn có thể muốn xem tmpfile() hoặc tempname().

Trong mọi trường hợp, tùy thuộc vào những gì bạn đang cố gắng đạt được, bạn chỉ có thể lặp lại và xác minh xem id duy nhất đã được lấy chưa (trong một mảng, với tệp_exists, v.v.) .


Ngoài ra, như tôi không chắc là tôi hiểu câu hỏi của bạn một cách chính xác, tôi sẽ chỉ cho bạn những câu hỏi khác mà âm thanh khá tương tự khi tôi nhận được sự khác biệt của bạn:

Điều đầu tiên sẽ được quan tâm nếu bạn đang tìm kiếm một id duy nhất mà con người có thể đọc được. Cách thứ hai có thể hữu ích nếu bạn muốn chơi với các số ngẫu nhiên và md5/sha1. Mặc dù, một lần nữa, tôi nghĩ rằng uniqid() có thể đã là những gì bạn đang tìm kiếm.

7

Bạn vẫn có thể u se uniqid(), chỉ cần thực hiện một số xử lý bổ sung để mở rộng giá trị của nó cho số ký tự bạn cần.

Ví dụ, để mở rộng nó đến 32 ký tự, bạn có thể làm

$id = md5(uniqid()); 

Để mở rộng đến 64 ký tự, chỉ cần nối thêm md5 của md5, như vậy

$first = md5(uniqid()); 
$id = $first . md5($first); 

Sau đó, trucate khi cần thiết, nếu bạn cần ít hơn một số bội số của 32.

Có thể bạn có thể gặp phải va chạm, nhưng nó không chắc. Nếu bạn hoang tưởng về điều đó, chỉ cần sử dụng cùng một ý tưởng, nhưng chug uniqid() thông qua một mật mã đối xứng như AES thay vì băm nó.

27

Không có câu trả lời nào ở đây là đủ nếu bạn muốn ngẫu nhiên cường độ mã hóa (có kẻ tấn công được xác định nào đang cố gắng đoán các phím ngẫu nhiên của bạn là gì không?). Hashing thời gian không an toàn, kẻ tấn công có thể tăng tốc độ tìm kiếm của họ bằng cách đoán khoảng thời gian họ nghĩ rằng máy chủ của bạn đã tạo khóa và dễ dàng tìm kiếm trong tất cả mili giây trong một năm nhất định, ngay cả trên máy tính xách tay hàng hóa (đó là 35 không gian tìm kiếm bit). Ngoài ra, đề xuất chỉ chạy kết quả của uniqid() hoặc một số nguồn ngẫu nhiên yếu khác thông qua hàm băm để "mở rộng" là nguy hiểm - điều này không làm cho tìm kiếm của kẻ tấn công khó hơn khi họ phát hiện ra rằng bạn đã thực hiện điều này.

Nếu bạn thực sự cần an ninh crypto-level, bạn nên đọc từ/dev/ngẫu nhiên, đoạn mã sau sẽ làm việc cho bạn trong bất kỳ hệ thống POSIX-compliant (bất cứ điều gì nhưng Windows):

#Generate a random key from /dev/random 
function get_key($bit_length = 128){ 
    $fp = @fopen('/dev/random','rb'); 
    if ($fp !== FALSE) { 
     $key = substr(base64_encode(@fread($fp,($bit_length + 7)/8)), 0, (($bit_length + 5)/6) - 2); 
     @fclose($fp); 
     return $key; 
    } 
    return null; 
} 

Nếu bạn cần tốc độ cao hơn một chút, thay vào đó bạn có thể đọc từ 'dev/urandom'.

+4

Chỉ muốn lưu ý - Tôi đã có một tập lệnh lấy thêm 50 giây để tải, và hóa ra sử dụng/dev/random thay vì/dev/urandom là nguyên nhân. Trên môi trường thử nghiệm địa phương của tôi, điều này không bao giờ xảy ra. – whichdan

+4

'/ dev/urandom' nên là mặc định, bằng cách sử dụng'/dev/random/'sẽ làm cạn kiệt nhóm entropy ngẫu nhiên quá sớm (trên các hệ thống không có trình tạo số ngẫu nhiên dành riêng cho'/dev/random'). Trên thực tế, vì nó sẽ là một cách tốt đẹp cho kẻ tấn công để thực hiện một cuộc tấn công DoS, tôi không nghĩ rằng chức năng nên được tiếp xúc ở tất cả, nó chỉ hữu ích cho các ứng dụng/thư viện với PRNG riêng của họ. –

3

Tại sao không sử dụng openssl_random_pseudo_bytes http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php

+0

Câu trả lời này sẽ hiệu quả hơn nếu bạn cho thấy một ví dụ về cách nó sẽ giúp ích. – ethrbunny

+0

Tôi đang sử dụng thành công phần trên như sau $ sessionkey = bin2hex (openssl_random_pseudo_bytes (1024)); Điều này tạo ra một khóa ngẫu nhiên mật mã an toàn ... Đây là câu trả lời cho .. 'cách tốt nhất để tạo ra một khóa ngẫu nhiên' ... Đó là một cách rất tốt như .. a) nó sử dụng một chức năng nhanh chóng đơn giản ... nó crypo an toàn, nó rõ ràng là ngẫu nhiên .. và bạn có thể tạo ra các khóa của bất kỳ chiều dài ... –

0

$ key = md5 (microtime() rand().);

Microtime tự nó không an toàn vì nó chỉ để lại 1/1000 cơ hội được đoán.

Rand của chính nó cũng không phải là rất an toàn, nhưng băm của họ nối chúng lại với nhau mang lại một ngẫu nhiên khá vững chắc.

+0

"Rand của chính nó cũng không phải là rất an toàn, nhưng băm của họ nối chúng lại với nhau mang lại một ngẫu nhiên rắn chắc chắn." Không. Bạn có một giá trị dự đoán được với giới hạn trên của 32 bit entropy từ 'rand()'. Nếu chúng ta giả sử 'microtime()' chứa 10 bit entropy, bạn kết thúc với khoảng 42 bit. Các va chạm sinh nhật sau mỗi 2 triệu mẫu, nhưng 'rand()' có thể dự đoán được. Giải pháp tốt hơn: Sử dụng CSPRNG để tạo khóa. –

1

Câu trả lời trước của tôi lấy hàm băm uniqid() kết hợp với muối bắt nguồn từ biến hệ thống, nhưng không tạo ra một khóa ngẫu nhiên, chỉ một câu có nhiều khả năng là duy nhất. Tương tự, đầu ra từ rand() hoặc mt_rand() không đủ ngẫu nhiên cho các mục đích mã hóa.

Để tạo một khóa ngẫu nhiên, bạn cần phải đi đến một nguồn dữ liệu ngẫu nhiên tốt, và các chức năng openssl_random_pseudo_bytes() được thiết kế để làm điều đó:

$randkey = base64_encode(openssl_random_pseudo_bytes(32)); 

Các base64_encode() là để làm cho nó thành ký tự in được.

Lý do các câu trả lời khác không khuyên bạn nên openssl_random_pseudo_bytes() có lẽ là nó đã được giới thiệu trong PHP 5.3, và câu hỏi này là gần 6 tuổi.

-1

Ngoài ra bạn có thể tạo một khóa ngẫu nhiên và kiểm tra quan trọng trong DB của bạn nếu chính là lối thoát hiểm, bạn có thể tạo phím khác bằng phương pháp này

 function activation($lengt=20){ 
    $modalpage =new Modal;//you can call your modal page and check the key 

    $characters = "1234567890abcdefghijklmnopqrstuvwxyz"; 
    for($i=0;$i<$lengt;$i++) 

    {  

    $key .= $characters{rand(0,35)}; 
    $check= array(
    ":key" => $key, 
    ); 

    $result = $modalpage->findkey($check); 

    if($result==true){ //if the key is exits return the function and generate another key ! 

     return activation($lengt); 

    }else //if the key is not exits return the key 
    return $key; 
    } 


      } 

$mykey=activation(15); 
Các vấn đề liên quan