etc./StackOverFlow

PHP에서 암호 해싱에 bcrypt를 어떻게 사용합니까?

청렴결백한 만능 재주꾼 2023. 4. 14. 22:02
반응형

질문자 :Vilx-


때때로 "PHP에 암호를 저장하는 데 bcrypt 사용, bcrypt 규칙"이라는 조언을 듣습니다.

그러나 bcrypt 는 무엇입니까? PHP는 그러한 기능을 제공하지 않으며, Wikipedia는 파일 암호화 유틸리티에 대해 떠들고 있으며 웹 검색은 다른 언어로 된 Blowfish의 몇 가지 구현을 보여줍니다. mcrypt 를 통해 PHP에서도 사용할 수 있지만 비밀번호를 저장하는 데 어떻게 도움이 될까요? Blowfish는 범용 암호이며 두 가지 방식으로 작동합니다. 암호화할 수 있으면 해독할 수 있습니다. 암호에는 단방향 해싱 기능이 필요합니다.

설명은 무엇입니까?



bcrypt 는 하드웨어로 확장 가능한(구성 가능한 라운드 수를 통해) 해싱 알고리즘입니다. 속도가 느리고 여러 라운드가 있기 때문에 공격자가 암호를 해독할 수 있도록 막대한 자금과 하드웨어를 배포해야 합니다. 암호별 솔트 ( bcrypt )에 추가하면 엄청난 자금이나 하드웨어 없이는 공격이 사실상 불가능하다는 것을 확신할 수 있습니다.

bcrypt 는 Eksblowfish 알고리즘을 사용하여 암호를 해시합니다. Eksblowfish와 복어의 암호화 단계는 동일하지만, Eksblowfish의 주요 일정 단계 이후의 상태가 모두 소금과 키 (사용자 암호)에 의존한다는 것을 보장하고, 어떤 상태는 모두의 지식없이 미리 계산 될 수 없다. 이러한 주요 차이점 때문에 bcrypt 는 단방향 해싱 알고리즘입니다. 솔트, 라운드 및 키 (비밀번호)를 모르면 일반 텍스트 비밀번호를 검색할 수 없습니다. [ 출처 ]

bcrypt를 사용하는 방법:

PHP >= 5.5-DEV 사용

비밀번호 해싱 기능 이 이제 PHP >= 5.5에 직접 내장되었습니다 . 이제 password_hash() 를 사용하여 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

기존 해시에 대해 사용자가 제공한 비밀번호를 확인하려면 다음과 같이 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(또한 RedHat PHP >= 5.3.3) 사용

GitHub 에는 원래 C로 작성된 위 기능의 소스 코드를 기반으로 생성된 호환성 라이브러리 가 있으며 동일한 기능을 제공합니다. 호환성 라이브러리가 설치되면 사용법은 위와 동일합니다(아직 5.3.x 분기에 있는 경우 축약형 배열 표기법 제외).

PHP < 5.3.7 사용(더 이상 사용되지 않음)

crypt() 함수를 사용하여 입력 문자열의 bcrypt 해시를 생성할 수 있습니다. 이 클래스는 자동으로 솔트를 생성하고 입력에 대해 기존 해시를 확인할 수 있습니다. 5.3.7 이상의 PHP 버전을 사용하는 경우 내장 함수 또는 compat 라이브러리를 사용하는 것이 좋습니다 . 이 대안은 역사적 목적으로만 제공됩니다.

 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; } }

이 코드를 다음과 같이 사용할 수 있습니다.

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

또는 Portable PHP Hashing Framework를 사용할 수도 있습니다.


Community Wiki

그래서, 당신은 bcrypt를 사용하고 싶습니까? 엄청난! 그러나 다른 암호화 영역과 마찬가지로 직접 수행해서는 안 됩니다. 키 관리, 솔트 저장 또는 난수 생성과 같은 것에 대해 걱정해야 한다면 잘못하고 있는 것입니다.

그 이유는 간단합니다. bcrypt를 망치 는 것은 매우 간단합니다. 사실, 이 페이지에 있는 거의 모든 코드 조각을 보면 이러한 일반적인 문제 중 하나 이상을 위반하고 있음을 알 수 있습니다.

Face It, 암호화는 어렵습니다.

전문가에게 맡기십시오. 이 라이브러리를 유지 관리하는 것이 직업인 사람들을 위해 남겨두십시오. 결정을 내려야 한다면 잘못하고 있는 것입니다.

대신 라이브러리를 사용하십시오. 요구 사항에 따라 여러 가지가 있습니다.

도서관

다음은 보다 일반적인 API에 대한 분석입니다.

PHP 5.5 API - (5.3.7 이상에서 사용 가능)

PHP 5.5부터 비밀번호 해싱을 위한 새로운 API가 도입됩니다. 5.3.7 이상에서 (저에 의해) 유지 관리되는 shim 호환성 라이브러리도 있습니다. 이 피어 검토 및 간단한 사용으로 구현되는 장점을 가지고있다.

 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 } }

정말, 그것은 매우 간단하게 목표로 하고 있습니다.

자원:

Zend\Crypt\Password\Bcrypt (5.3.2+)

이것은 PHP 5.5와 유사한 또 다른 API이며 유사한 목적을 수행합니다.

 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 } }

자원:

비밀번호 라이브러리

이것은 암호 해싱에 대한 약간 다른 접근 방식입니다. 단순히 bcrypt를 지원하는 것이 아니라 PasswordLib는 수많은 해싱 알고리즘을 지원합니다. 제어할 수 없는 레거시 및 이종 시스템과의 호환성을 지원해야 하는 상황에서 주로 유용합니다. 많은 해싱 알고리즘을 지원합니다. 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 } }

참조:

  • 소스 코드 / 문서: GitHub

패스패스

이것은 bcrypt를 지원하는 계층이지만 PHP >= 5.3.2에 액세스할 수 없는 경우에 유용한 상당히 강력한 알고리즘도 지원합니다. 실제로 PHP 3.0 이상을 지원합니다(bcrypt는 지원하지 않음).

 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 } }

자원

참고: 오픈월에서 호스팅되지 않는 PHPASS 대안을 사용하지 마십시오. 다른 프로젝트입니다!!!

BCrypt 소개

이러한 라이브러리는 모두 단일 문자열을 반환합니다. BCrypt가 내부적으로 작동하는 방식 때문입니다. 그리고 그것에 대한 수많은 답변이 있습니다. 여기에 내가 작성한 선택 항목이 있으며 여기에 복사/붙여넣기가 아니라 다음 링크로 연결됩니다.

마무리

다양한 선택이 있습니다. 당신이 선택하는 것은 당신에게 달려 있습니다. 그러나, 내가보기 엔 당신이 당신을 위해 이것을 처리하기위한 위의 라이브러리 중 하나를 사용하는 것이 추천 할 것입니다.

다시 말하지만, crypt() 직접 사용한다면 아마도 뭔가 잘못하고 있을 것입니다. 코드가 hash() (또는 md5() 또는 sha1() )를 직접 사용하는 경우 거의 확실히 뭔가 잘못하고 있는 것입니다.

그냥 도서관 이용하세요...


ircmaxell

Enough With The Rainbow Tables: 보안 암호 체계 또는 휴대용 PHP 암호 해싱 프레임워크에 대해 알아야 할 사항 에서 많은 정보를 얻을 수 있습니다.

목표는 암호를 느린 것으로 해시하는 것이므로 암호 데이터베이스를 얻는 사람이 무차별 암호 대입 시도를 하다가 죽을 것입니다(암호를 확인하는 데 10ms 지연은 아무 것도 아니며 암호를 강제로 적용하려는 누군가에게는 많은 시간입니다). Bcrypt 는 느리고 매개변수와 함께 사용하여 속도를 선택할 수 있습니다.


Arkh

crypt() 함수를 사용하고 적절한 Blowfish 솔트를 전달하여 bcrypt로 단방향 해시를 생성할 수 있습니다. 전체 방정식에서 가장 중요한 것은 A) 알고리즘이 손상되지 않았으며 B) 각 암호를 적절하게 솔트링 한다는 것입니다. 애플리케이션 전체에 솔트를 사용하지 마십시오. 단일 레인보우 테이블 세트에서 공격할 수 있도록 전체 애플리케이션을 엽니다.

PHP - 암호화 기능


coreyward


편집: 2013.01.15 - 서버에서 지원한다면 martinstoeckli의 솔루션을 대신 사용하십시오.


모두가 이것을 더 복잡하게 만들고 싶어합니다. crypt() 함수는 대부분의 작업을 수행합니다.

 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); }

예시:

 $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

분명히 해야 한다는 것을 알고 있지만 '비밀번호'를 비밀번호로 사용하지 마십시오.


Jon Hulka

PHP 버전 5.5는 BCrypt, password_hash()password_verify() 기능을 기본적으로 지원합니다. crypt() 함수를 감싸는 래퍼일 뿐이며 올바르게 사용하기가 더 쉽습니다. 안전한 랜덤 솔트 생성을 처리하고 좋은 기본값을 제공합니다.

이 기능을 사용하는 가장 쉬운 방법은 다음과 같습니다.

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

이 코드는 BCrypt(알고리즘 2y )로 비밀번호를 해시하고 OS 임의 소스에서 임의의 솔트를 생성하며 기본 비용 매개변수(현재 10)를 사용합니다. 두 번째 줄은 사용자가 입력한 암호가 이미 저장된 해시 값과 일치하는지 확인합니다.

비용 매개변수를 변경하려면 다음과 같이 비용 매개변수를 1씩 늘리면 해시 값을 계산하는 데 필요한 시간이 두 배가 됩니다.

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

"cost" 매개변수와 달리 "salt" 매개변수를 생략하는 것이 가장 좋습니다. 함수가 이미 암호학적으로 안전한 솔트를 생성하기 위해 최선을 다하고 있기 때문입니다.

PHP 버전 5.3.7 이상 password_hash() 함수를 만든 동일한 작성자 의 호환성 팩이 있습니다. 5.3.7 이전 PHP 버전의 경우 유니코드 안전 BCrypt 알고리즘인 2y crypt() 가 지원되지 않습니다. 대신 이전 PHP 버전에 대한 최상의 대안인 2a 대체할 수 있습니다.


martinstoeckli

현재 생각: 해시는 가능한 가장 빠른 것이 아니라 가장 느린 것이어야 합니다. 이것은 레인보우 테이블 공격을 억제합니다.

또한 관련이 있지만 예방 조치를 취해야 합니다. 공격자는 로그인 화면에 무제한으로 액세스할 수 없습니다. 그것을 방지하려면: URI와 함께 모든 적중을 기록하는 IP 주소 추적 테이블을 설정하십시오. 5분 동안 동일한 IP 주소에서 5회 이상 로그인 시도가 발생하면 설명과 함께 차단합니다. 두 번째 접근 방식은 은행과 같이 2단계 암호 체계를 사용하는 것입니다. 두 번째 패스에서 실패에 대한 잠금을 설정하면 보안이 강화됩니다.

요약: 시간이 많이 걸리는 해시 함수를 사용하여 공격자의 속도를 늦춥니다. 또한 로그인에 대한 너무 많은 액세스를 차단하고 두 번째 암호 계층을 추가하십시오.


FYA

이 오래된 질문에 대한 업데이트된 답변이 있습니다!

5.5 이후 PHP에서 비밀번호를 해시하는 올바른 방법은 password_hash() 를 사용하는 것이고 비밀번호를 확인하는 올바른 방법은 password_verify() 를 사용하는 것이며 이는 PHP 8.0에서도 여전히 유효합니다. 이러한 함수는 기본적으로 bcrypt 해시를 사용하지만 더 강력한 다른 알고리즘이 추가되었습니다. password_hash 매개변수를 통해 작업 요소(암호화의 "강력한" 효과)를 변경할 수 있습니다.

그러나 여전히 충분히 강력하지만 bcrypt는 더 이상 최신 기술로 간주되지 않습니다 . Argon2i, Argon2d 및 Argon2id 변형이 포함된 더 나은 암호 해시 알고리즘 세트가 Argon2 로 도착했습니다. 그들 사이의 차이점( 여기에 설명됨):

Argon2에는 Argon2id라는 기본 변형과 Argon2d 및 Argon2i라는 두 가지 추가 변형이 있습니다. Argon2d는 데이터 종속 메모리 액세스를 사용하므로 사이드 채널 타이밍 공격의 위협 없이 암호화폐 및 작업 증명 애플리케이션에 적합합니다. Argon2i는 암호 해싱 및 암호 기반 키 파생에 선호되는 데이터 독립 메모리 액세스를 사용합니다. Argon2id는 메모리에 대한 첫 번째 반복의 전반부 동안 Argon2i로 작동하고 나머지는 Argon2d로 작동하므로 시간 메모리 트레이드오프로 인해 부채널 공격 보호와 무차별 대입 비용 절감을 제공합니다.

Argon2i 지원은 PHP 7.2에 추가되었으며 다음과 같이 요청합니다.

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

PHP 7.3에 Argon2id 지원이 추가되었습니다.

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

생성된 해시 문자열에는 생성 시 사용된 알고리즘, 솔트 및 작업 요소에 대한 정보가 포함되어 있으므로 암호 확인을 위해 변경할 필요가 없습니다.

꽤 별도로(그리고 다소 중복적으로), libsodium(PHP 7.2에 추가됨)은 또한 sodium_crypto_pwhash_str ()sodium_crypto_pwhash_str_verify() 함수를 통해 Argon2 해싱을 제공합니다. 이 함수는 PHP 내장 기능과 거의 동일한 방식으로 작동합니다. 이것을 사용하는 한 가지 가능한 이유는 PHP가 때때로 libargon2 없이 컴파일되어 Argon2 알고리즘을 password_hash 함수에서 사용할 수 없게 만들기 때문입니다. PHP 7.2 이상에서는 항상 libsodium이 활성화되어 있어야 하지만 그렇지 않을 수도 있습니다. 그러나 적어도 두 가지 방법으로 해당 알고리즘을 사용할 수 있습니다. 다음은 libsodium을 사용하여 Argon2id 해시를 생성하는 방법입니다(PHP 7.2에서도 Argon2id 지원이 부족함).

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

수동으로 소금을 지정할 수는 없습니다. 이것은 libsodium의 정신의 일부입니다. 사용자가 매개변수를 보안을 손상시킬 수 있는 값으로 설정하는 것을 허용하지 마십시오. 예를 들어 빈 솔트 문자열을 PHP의 password_hash 함수에 전달하는 것을 막는 것은 없습니다. libsodium은 그렇게 어리석은 일을 하도록 내버려 두지 않습니다!


Synchro

OAuth 2 비밀번호의 경우:

 $bcrypt = new \Zend\Crypt\Password\Bcrypt; $bcrypt->create("youpasswordhere", 10)

Shemeer M Ali

우리 모두 알고 있듯이 데이터베이스에 암호를 일반 텍스트로 저장하는 것은 안전하지 않습니다. bcrypt는 해싱 암호 기술입니다. 암호 보안을 구축하는 데 사용됩니다. bcrypt의 놀라운 기능 중 하나는 암호가 bcrypted 형식으로 저장되기 때문에 해킹 공격으로부터 암호를 보호하는 데 사용되는 해커로부터 우리를 저장한다는 것입니다.

password_hash() 함수는 새 암호 해시를 만드는 데 사용됩니다. 강력하고 강력한 해싱 알고리즘을 사용합니다. password_hash() crypt() 함수와 매우 호환됩니다. crypt() 의해 생성된 암호 해시 password_hash() 와 함께 사용될 수 있으며 그 반대의 경우도 마찬가지입니다. password_verify()password_hash() crypt() 함수를 감싸는 래퍼일 뿐이며 정확하게 사용하기가 훨씬 쉽습니다.

통사론

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

password_hash() 함수는 다음 알고리즘을 지원합니다.

  • PASSWORD_DEFAULT
  • PASSWORD_BCRYPT
  • PASSWORD_ARGON2I
  • PASSWORD_ARGON2ID

매개변수: 이 함수는 위에서 언급하고 아래에 설명된 대로 세 개의 매개변수를 허용합니다.

$password : 사용자의 비밀번호를 저장합니다.

$algo : 암호 해싱이 일어날 때 사용할 알고리즘을 나타내면서 지속적으로 사용되는 암호 알고리즘 상수이다.

$options : 옵션을 포함하는 연관 배열입니다. 이것이 제거되고 포함되지 않으면 임의의 솔트가 사용되며 기본 비용의 사용이 발생합니다.

반환 값 : 성공 시 해시된 암호를 반환하고 실패 시 False를 반환합니다.

:

입력:

 echo password_hash("GFG@123", PASSWORD_DEFAULT);

산출:

 $2y$10$.vGA19Jh8YrwSJFDodbfoHJIOFH)DfhuofGv3Fykk1a

아래 프로그램은 PHP password_hash()

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

산출

 $2y$10$Z166W1fBdsLcXPVQVfPw/uRq1ueWMA6sLt9bmdUFz9AmOGLdM393G

Nayab Muhammad

PHP의 password_hash() 함수는 다른 알고리즘과 옵션으로 새 암호 해시를 만드는 데 사용되는 내장 함수입니다. 이 함수는 강력한 해싱 알고리즘을 사용합니다.

이 함수는 2개의 필수 매개변수인 $password$algorithm 과 1개의 선택적 매개변수 $options 취합니다.

 $strongPassword = password_hash( $password, $algorithm, $options );

password_hash() 허용되는 알고리즘은 다음과 같습니다.

  • PASSWORD_DEFAULT
  • PASSWORD_BCRYPT
  • PASSWORD_ARGON2I
  • PASSWORD_ARGON2ID

예시:

 echo password_hash("abcDEF", PASSWORD_DEFAULT);

답변:

 $2y$10$KwKceUaG84WInAif5ehdZOkE4kHPWTLp0ZK5a5OU2EbtdwQ9YIcGy

예시:

 echo password_hash("abcDEF", PASSWORD_BCRYPT);

답변:

 $2y$10$SNly5bFzB/R6OVbBMq1bj.yiOZdsk6Mwgqi4BLR2sqdCvMyv/AyL2

BCRYPT 를 사용하려면 $options 에서 옵션 cost=12 를 설정하고 첫 번째 매개변수 $password "wgt167yuWBGY@#1987__" 와 같은 강력한 암호로 변경합니다.

예시:

 echo password_hash("wgt167yuWBGY@#1987__", PASSWORD_BCRYPT, ['cost' => 12]);

답변:

 $2y$12$TjSggXiFSidD63E.QP8PJOds2texJfsk/82VaNU8XRZ/niZhzkJ6S

subhadip pahari

출처 : http:www.stackoverflow.com/questions/4795385/how-do-you-use-bcrypt-for-hashing-passwords-in-php

반응형