2013-02-21 1 views
31

사용자를 위해 암호를 저장하고 싶다고 가정하면 PHP 5.5의 password_hash() 함수 (또는 PHP 5.3.7 이상에서는이 버전을 사용하는 것이 올바른 방법일까요? https://github.com/ircmaxell/password_compat)? PHP 5.5의 password_hash 및 password_verify 함수 사용

$options = array("cost" => 10, "salt" => uniqid()); 
$hash = password_hash($password, PASSWORD_BCRYPT, $options); 

은 그럼 내가 할 것이다 : 데이터베이스에 삽입하려면

mysql_query("INSERT INTO users(username,password, salt) VALUES($username, $hash, " . $options['salt']); 

.

그런 다음 확인 :

$row = mysql_fetch_assoc(mysql_query("SELECT salt FROM users WHERE id=$userid")); 
$salt = $row["salt"]; 
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10, "salt" => $salt)); 

if (password_verify($password, $hash) { 
    // Verified 
} 
+1

흠, 뭔가 여기에 이상한 거기, 당신은 배열을이 작동하지 않습니다 –

+0

고정 후? "비용"=> 10, 아무것도. –

+0

을 당신은 여전히 ​​누락)? 또한 5.5에서 사용되지 않는'ext/mysql'을 사용하고 있습니다. –

답변

57

을 지금 데이터베이스 문에 문제를 무시하고, 나는 password_hash에 대한 질문에 답변 해 드리겠습니다.

간단히 말해서, 어떻게 그럴 수는 없습니다. 소금 만 저장하고 싶지는 않습니다. 해시와 소금을 모두 저장 한 다음 두 가지를 모두 사용하여 암호를 확인해야합니다. password_hash은 둘 모두를 포함하는 문자열을 반환합니다.

password_hash 함수는 해시와 소금을 모두 포함하는 문자열을 반환합니다. 그래서 그런 다음

$hashAndSalt = password_hash($password, PASSWORD_BCRYPT); 
// Insert $hashAndSalt into database against user 

은 확인합니다 :

// Fetch hash+salt from database, place in $hashAndSalt variable 
// and then to verify $password: 
if (password_verify($password, $hashAndSalt)) { 
    // Verified 
} 

을 또한, 보안에 관심이 mysqli보고 할 수 있습니다 경우 코멘트 (ext/mysql PHP5.5에서 더 이상 사용되지 않습니다) 제안으로 , 그리고 SQL 주입에 관한이 기사 : http://php.net/manual/en/security.database.sql-injection.php

+0

당신은 소금 메커니즘을 사용하고 소금을 저장하지 않을 것을 제안합니까? 그렇다면 원래 해시를 만드는 데 사용 된 원래 소금을 검색하여 사용자가 로그인을 시도 할 때 확인하는 방법은 무엇입니까? –

+1

salt와 hash는 password_hash에 의해 단일 문자열로 함께 반환됩니다. – Pete

+0

지금 데이터베이스 문과 관련된 문제를 무시할 것이라고 말하면 게시물 하단에 언급 된 문제가 있습니까? –

4

당신은 자신의 소금을 넣지 말고, 소금을 비워 두어라. 함수는 좋은 무작위 소금을 생성 할 것이다.

함수에서 반환 한 문자열 전체를 데이터베이스 (또는 파일 또는 기타 사용하는 것)에 삽입하십시오. 그것은 다음을 포함합니다 : 알고리즘의 id, 비용, 소금 (22 문자) 및 해시 암호.

password_verify()를 사용하려면 전체 문자열이 필요합니다. 소금은 무작위이며 해를 끼치 지 않고 해를 입지 않습니다 (해시 된 암호 사용). 이렇게하면 준비된 세트의 암호 및 해시 목록 인 레인보우 테이블을 사용할 수 없게됩니다 (또는 매우 어려움).

비용 매개 변수 추가를 고려해야합니다. 기본값 (생략 된 경우) 은 1입니다. 더 높으면 함수 해시가 더 길어집니다. 1 비용 증가, 이중 시간 (이 암호를 중단하는 데 걸리는 시간 때문에 길게)

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

당신이 당신의 서버에서 속도 체크를 기반으로이 매개 변수를 설정해야합니다을 해시를 생성 할 필요가 있었다. 이 기능은 100ms +를 수행하는 것이 좋습니다 (일부는 250ms가되도록하는 것이 좋습니다). 보통 비용 = 10 또는 11이 좋은 선택입니다 (2015 년).

보안을 강화하려면 암호에 긴 (50-60자를 선택하는 것이 좋습니다) 비밀 문자열을 추가 할 수 있습니다. password_hash() 또는 password_verify()를 사용하기 전에.ALGO 매개 변수의 사용 PASSWORD_BCRYPT

$secret_string = '[email protected]#[email protected]#$234'; 
$password = trim($_POST['user_password']) . $secret_string; 
// here use password_* function 

주의 72 개 문자의 최대 길이로 절단되는 암호 파라미터 될 것이다.

$ password가 72자를 초과하고 73 자 또는 90자를 변경하거나 추가하면 해시가 변경되지 않습니다. 선택 사항 인 $ secret_string을 붙이면 끝 부분에 있어야합니다 (사용자의 비밀번호가 아닌 이전의 비밀번호 뒤에 있어야 함).

6

참고이

소금 옵션을 경고 php.net

에서 PHP 7.0.0의로 사용되지 않습니다. 기본적으로 생성되는 소금을 단순히 사용하는 것이 선호되는 지금은 입니다.

결론? 소금 옵션은 잊어 버려.

이것은 PHP 7, its use is deprecated의 같은, 아주 * password_hash('password', PASSWORD_DEFAULT)만큼 (또는 _BCRYPT)

9

가 자신의 소금은 사용하지 않는 것이 좋습니다 사용하고있을 것이다. read the author's thoughts

한 가지가 나에게 풍부하게 명백 해졌다, 이유를 이해하려면 다음과 소금 옵션은 위험 입니다. 나는 아직까지도 도 괜찮은 소금 옵션의 한 가지 사용법을 보았습니다. 모든 사용 범위는 mt_rand() 출력을 전달하는 나쁜 (나쁜 문자열)에서 정신 나간 (암호 을 고유 한 소금으로 전달)의 범위입니다.

나는 사용자가 에 소금을 지정하도록 허용하지 않아야한다고 결론을 내 렸습니다.