암호화 된 보안 토큰 생성


84

API에 액세스하기위한 32 자 토큰을 생성하기 위해 현재 다음을 사용합니다.

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

이 방법은 시스템 시계를 기반으로하기 때문에 암호 학적으로 안전하지 않으며 openssl_random_pseudo_bytes예측하기가 더 어렵 기 때문에 더 나은 솔루션이 될 것이라고 읽었습니다 .

이 경우 동등한 코드는 어떻게 생겼습니까?

나는 이런 것을 추측하지만 이것이 옳은지 모르겠습니다 ...

$token = md5(openssl_random_pseudo_bytes(32));

또한 함수에 전달해야하는 길이는 어느 정도입니까?


4
그래도 왜 md5입니까? 그냥 진수로 바이트 스트림으로 변환 : 당신이 32를 얻고있는 것은 같이) BIN2HEX (와 hexvalue로 그 바이트의 각 렌더링) openssl_random_pseudo_bytes (에서 다시 바이트 PHP의 문서의
마크 베이커

32 자만 원하십니까? 어떻게할까요?
화재

10
md5()32 자 문자열을 생성하지만 그 안에 128 비트의 데이터 만 있습니다. openssl_random_pseudo_bytes()진정한 바이너리 데이터를 반환하므로 32 * 8 = 256 비트의 임의성이 있습니다. md5를 통해 32 바이트 임의 문자열을 채우면 고유성을 대량으로 효과적으로 줄일 수 있습니다.
Marc B

1
그래서 $token = bin2hex(openssl_random_pseudo_bytes(16));충분합니까 아니면 길이로 1을 전달하고 16 진수를 문자열에 추가하는 16 반복 루프가 필요합니까?
화재

16 바이트를 16 진수로 변환 한 최종 솔루션이 맞습니다. 하지만 여기서 OpenSSL에 실제로 의존해서는 안됩니다. # 1 # 2 # 3 . PHP 7.0 이상을 사용하자마자 더 이상 사용할 이유가 없습니다. OpenSSL 및 16 진수 인코딩 대신 try Random::alphanumericString($length). 16 자에 "엔트로피"가 약 20 억 배 더 들어갑니다.
caw

답변:


189

올바른 해결책은 다음과 같습니다.

$token = bin2hex(openssl_random_pseudo_bytes(16));

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

1
CryptoLib와 함께 openssl_random_pseudo_bytes를 사용하여 고유 토큰을 생성하는 방법에 대한 또 다른 답변을 추가했습니다. 이를 통해 0-9, AF가 아닌 모든 문자로 토큰을 생성 할 수 있습니다.
mjsa 2014

4
random_bytes () 및 random_int ()에 대한 PHP 5.x 지원 github.com/paragonie/random_compat
MTK

4
또한 bin2hex(random_bytes($length/2))모든 바이트에 2 개의 16 진수 문자를 가질 수 있으므로 문자 수가 $length없으면 문자 수가 항상 두 배가되기 때문에 원할 수 있습니다.
A Friend

3
@AFriend 동의합니다. $length(바이트 크기에 신경을 쓰지 않고) 문자 수의 문자열을 생성하는 함수를 만들고 싶다면 random_bytes($length/2).
BadHorsie

10

openssl_random_pseudo_bytes를 사용하려면 CrytoLib의 구현을 사용하는 것이 가장 좋습니다. 이렇게하면 모든 영숫자 문자를 생성 할 수 있습니다.

path / to /를 cryptolib.php 파일을 넣은 위치로 바꿉니다 (GitHub에서 찾을 수 있음 : https://github.com/IcyApril/CryptoLib ).

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

전체 CryptoLib 문서는 https://cryptolib.ju.je/ 에서 볼 수 있습니다 . 다른 많은 임의 방법, 계단식 암호화, 해시 생성 및 유효성 검사를 다룹니다. 하지만 필요한 경우 거기에 있습니다.


동일한 openssl_random_pseudo_bytes(16)바이트 수 : 각 바이트는 임의의 값 (0-255)을 가질 수있는 반면, randomString(16)각 바이트는 바이트 당 62 개의 조합 인 az Az 0-9 만 가질 수 있습니다. Yup randomString은 bin2hex가 비효율적 인 인코딩 (50 %)이므로 string 길이 당 더 좋습니다 . 더 base64_encode(openssl_random_pseudo_bytes(16))짧은 문자열과 정확히 알려진 보안 바이트 수에 사용 하는 것이 더 좋습니다 (이 경우 16이지만 필요에 따라 변경)
Rodney

1
@Rodney Bear는 base 64도 +, /=문자를 포함하는 문자열 을 생성하므로 사용자 친화적 인 토큰 (예 : API 키)을 생성하려는 경우 이상적이지 않습니다.
BadHorsie

9

암호화 된 보안 난수 생성기가있는 경우 출력을 해시 할 필요가 없습니다. 사실 당신은 원하지 않습니다. 그냥 사용

$token  = openssl_random_pseudo_bytes($BYTES,true)

그러나 $ BYTES는 원하는 데이터의 수입니다. MD5에는 128 비트 해시가 있으므로 16 바이트가 가능합니다.

참고로, 원래 코드에서 호출하는 함수는 암호 학적으로 안전하지 않으며, 대부분은 하나만 사용하면 안전한 다른 함수와 결합하더라도 안전하지 않을 정도로 충분히 해 롭습니다. MD5에는 보안 문제가 있습니다 (이 응용 프로그램에서는 관련이 없을 수 있음). Uniqid는 기본적으로 암호 학적으로 임의의 바이트를 생성하지 않을뿐만 아니라 (시스템 클럭을 사용하기 때문에), 추가 된 엔트로피는 암호 학적으로 안전하지 않은 선형 합동 생성기를 사용하여 결합됩니다. 실제로 서버 시계의 가치를 알지 못하더라도 일부에 대한 액세스 권한이 부여 된 모든 API 키를 추측 할 수 있음을 의미합니다. 마지막으로, 추가 엔트로피로 사용하는 mt_rand ()도 안전한 난수 생성기가 아닙니다.


27
openssl_random_pseudo_bytes ()에 대한 두 번째 인수는 참조로 전달 된 변수 여야합니다. openssl_random_pseudo_bytes 이후, openssl이 강력한 암호화 알고리즘을 사용할 수 있으면 해당 변수는 true 또는 false가됩니다. 이는 openssl에게 암호 적으로 강력한 알고리즘을 사용하도록 지시하는 데 사용되지 않으며 어쨌든 시도 할 것입니다.
Jonathan Amend

-1

신뢰할 수있는 암호 ASCII 문자 a-zA-Z숫자 0-9 로만 만들 수 있습니다 . 가장 좋은 방법은 PHP7의 random_int () 또는 random_bytes () 와 같은 암호화 보안 메서드 만 사용 하는 것입니다. rest functions as base64_encode () 문자열의 신뢰성을 높이고 ASCII 문자로 변경하기위한 지원 함수로만 사용할 수 있습니다 .

mt_rand () 는 안전하지 않으며 매우 오래되었습니다. 임의의 문자열에서 random_int ()를 사용해야합니다. 바이너리 문자열에서 바이너리 문자열을 신뢰할 수있게 만들려면 base64_encode () 를 사용해야합니다 . 이 함수의 구현을 참조하십시오. 모든 언어를 사용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.