Tạo mã thông báo an toàn bằng mật mã


83

Để tạo mã thông báo 32 ký tự để truy cập vào API của chúng tôi, chúng tôi hiện đang sử dụng:

$token = md5(uniqid(mt_rand(), true));

Tôi đã đọc rằng phương pháp này không an toàn bằng mật mã vì nó dựa trên đồng hồ hệ thống và đó openssl_random_pseudo_bytessẽ là giải pháp tốt hơn vì nó sẽ khó dự đoán hơn.

Nếu đúng như vậy, mã tương đương sẽ như thế nào?

Tôi đoán một điều như thế này, nhưng tôi không biết liệu điều này có đúng không ...

$token = md5(openssl_random_pseudo_bytes(32));

Ngoài ra, độ dài nào có ý nghĩa mà tôi nên chuyển cho hàm?


4
Tại sao md5 nó mặc dù? Chỉ cần chuyển đổi bytestream để hex: bạn đang nhận được 32 byte trở lại từ openssl_random_pseudo_bytes (), làm cho mỗi người trong số những byte như một hexvalue với BIN2HEX () như trong tài liệu PHP ví dụ
Mark Baker

Tôi chỉ muốn có 32 ký tự? Làm thế nào tôi sẽ làm điều đó?
cháy

10
md5()tạo ra một chuỗi 32 ký tự, nhưng chỉ có 128bit giá trị dữ liệu trong đó. openssl_random_pseudo_bytes()trả về dữ liệu nhị phân thực, do đó có 32 * 8 = 256 bit ngẫu nhiên. Bằng cách nhồi chuỗi ngẫu nhiên 32 byte của bạn qua md5, bạn đang cắt giảm một cách hiệu quả tính độc nhất của nó đi một lượng lớn.
Marc B

1
Vì vậy, là $token = bin2hex(openssl_random_pseudo_bytes(16));đủ hay tôi cần một vòng lặp gồm 16 lần lặp đi qua 1 là độ dài và nối bằng hex vào một chuỗi?
cháy

Giải pháp cuối cùng với 16 byte được chuyển đổi thành hex là chính xác. Nhưng bạn không thực sự nên dựa vào OpenSSL ở đây # 1 # 2 # 3 . Ngay sau khi bạn đang sử dụng PHP 7.0+, thực sự không còn lý do gì để sử dụng nó nữa. Thay vì OpenSSL và mã hóa hex, hãy thử Random::alphanumericString($length), nó phù hợp với "entropy" gấp khoảng 2 tỷ lần vào 16 ký tự đó.
caw

Câu trả lời:


187

Đây là giải pháp chính xác:

$token = bin2hex(openssl_random_pseudo_bytes(16));

# or in php7
$token = bin2hex(random_bytes(16));

1
Tôi đã thêm một câu trả lời khác về cách bạn có thể tạo mã thông báo duy nhất bằng cách sử dụng openssl_random_pseudo_bytes với CryptoLib. Điều này cho phép bạn tạo mã thông báo với tất cả các ký tự thay vì chỉ 0-9, AF.
mjsa

4
Hỗ trợ PHP 5.x cho random_bytes () và random_int () github.com/paragonie/random_compat
MTK

4
Bạn cũng có thể muốn bin2hex(random_bytes($length/2))bởi vì bạn có thể có 2 ký tự hex cho mỗi byte, vì thế số ký tự sẽ luôn luôn được tăng gấp đôi $lengthmà không có nó
Một người bạn

3
@AFriend Đồng ý. Nếu bạn muốn tạo một hàm tạo ra một chuỗi $lengthsố ký tự (thay vì quan tâm đến kích thước byte), bạn sẽ muốn chuyển random_bytes($length/2).
BadHorsie

10

Nếu bạn muốn sử dụng openssl_random_pseudo_bytes, tốt nhất là sử dụng triển khai của CrytoLib, điều này sẽ cho phép bạn tạo tất cả các ký tự chữ và số, việc gắn bin2hex xung quanh openssl_random_pseudo_bytes sẽ chỉ dẫn đến việc bạn nhận được AF (mũ) và số.

Thay thế đường dẫn / đến / bằng nơi bạn đặt tệp cryptolib.php (bạn có thể tìm thấy nó trên GitHub tại: https://github.com/IcyApril/CryptoLib )

<?php
  require_once('path/to/cryptolib.php');
  $token = IcyApril\CryptoLib::randomString(16);
?>

Tài liệu đầy đủ về CryptoLib có sẵn tại: https://cryptolib.ju.je/ . Nó bao gồm rất nhiều phương pháp ngẫu nhiên khác, mã hóa theo tầng, tạo và xác nhận hàm băm; nhưng nó ở đó nếu bạn cần.


Đối với cùng một số byte: openssl_random_pseudo_bytes(16) mỗi byte có thể có bất kỳ giá trị nào (0-255), trong khi randomString(16)mỗi byte chỉ có thể có az Az 0-9 là 62 kết hợp trên mỗi byte. Yup randomString tốt hơn trên mỗi độ dài của chuỗi , vì bin2hex là mã hóa không hiệu quả (50%); tốt hơn để sử dụng base64_encode(openssl_random_pseudo_bytes(16))cho một chuỗi ngắn hơn và một con số chính xác được biết đến của byte của an ninh (16 trong trường hợp này nhưng thay đổi nếu cần thiết)
Rodney

1
@Rodney Gấu trong cơ sở tâm 64 cũng sẽ tạo ra một chuỗi chứa +, /=nhân vật, vì vậy nếu bạn đang cố gắng để tạo ra một mã thông báo người dùng thân thiện (ví dụ như một khóa API) nó không phải là lý tưởng.
BadHorsie

9

Nếu bạn có trình tạo số ngẫu nhiên an toàn bằng mật mã, bạn không cần băm đầu ra của nó. Trong thực tế, bạn không muốn. Chỉ dùng

$token  = openssl_random_pseudo_bytes($BYTES,true)

Tuy nhiên $ BYTES là bao nhiêu byte dữ liệu bạn muốn. MD5 có một băm 128 bit, vì vậy 16 byte sẽ làm được.

Lưu ý thêm, không có chức năng nào bạn gọi trong mã gốc của mình là an toàn về mặt mật mã, hầu hết đều có hại đến mức chỉ sử dụng một chức năng sẽ không an toàn ngay cả khi kết hợp với các chức năng bảo mật khác. MD5 có vấn đề về bảo mật (mặc dù đối với ứng dụng này, chúng có thể không liên quan). Uniqid không chỉ không tạo ra các byte ngẫu nhiên mã hóa theo mặc định (vì nó sử dụng đồng hồ hệ thống), entropy được thêm vào mà bạn chuyển vào được kết hợp bằng cách sử dụng bộ tạo đồng dư tuyến tính, không an toàn về mặt mật mã. Trên thực tế, nó có thể có nghĩa là người ta có thể đoán tất cả các khóa API của bạn được cấp quyền truy cập vào một vài trong số chúng ngay cả khi họ không biết giá trị của đồng hồ máy chủ của bạn. Cuối cùng, mt_rand (), thứ mà bạn sử dụng làm entropy bổ sung, cũng không phải là một trình tạo số ngẫu nhiên an toàn.


27
Đối số thứ hai của openssl_random_pseudo_bytes () phải là một biến được truyền bằng tham chiếu. Sau openssl_random_pseudo_bytes, biến đó sẽ đúng hoặc sai nếu openssl có thể sử dụng thuật toán mật mã mạnh. Nó không được sử dụng để yêu cầu openssl sử dụng thuật toán mạnh về mặt mật mã, mà nó sẽ cố gắng thực hiện bất cứ điều gì.
Jonathan sửa đổi

-1

Mật khẩu đáng tin cậy Bạn chỉ có thể tạo từ các ký tự ascii a-zA-Z và các số 0-9 . Để làm điều đó, cách tốt nhất là chỉ sử dụng các phương thức an toàn bằng mật mã, như random_int () hoặc random_bytes () từ PHP7. Các hàm còn lại dưới dạng base64_encode () Bạn chỉ có thể sử dụng như các hàm hỗ trợ để tạo độ tin cậy cho chuỗi và thay đổi nó thành các ký tự ASCII .

mt_rand () không an toàn và rất cũ. Từ bất kỳ chuỗi nào Bạn phải sử dụng random_int (). Từ chuỗi nhị phân Bạn nên sử dụng base64_encode () để làm cho chuỗi nhị phân đáng tin cậy hoặc bin2hex, nhưng sau đó Bạn sẽ chỉ cắt byte xuống còn 16 vị trí (giá trị). Xem việc thực hiện các chức năng này của tôi. Nó sử dụng tất cả các ngôn ngữ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.