사용자의 비밀번호를 안전하게 저장하려면 어떻게해야합니까?
일반 MD5 보다 훨씬 더 안전 합니까? 방금 비밀번호 보안을 조사하기 시작했습니다. 저는 PHP를 처음 접했습니다.
$salt = 'csdnfgksdgojnmfnb';
$password = md5($salt.$_POST['password']);
$result = mysql_query("SELECT id FROM users
WHERE username = '".mysql_real_escape_string($_POST['username'])."'
AND password = '$password'");
if (mysql_num_rows($result) < 1) {
/* Access denied */
echo "The username or password you entered is incorrect.";
}
else {
$_SESSION['id'] = mysql_result($result, 0, 'id');
#header("Location: ./");
echo "Hello $_SESSION[id]!";
}
암호 저장 체계를 안전하게 유지하는 가장 쉬운 방법 은 표준 라이브러리 를 사용하는 것 입니다.
보안은 대부분의 프로그래머가 단독으로 처리 할 수있는 것보다 훨씬 더 복잡하고 보이지 않는 스크류 업 가능성으로 인해 표준 라이브러리를 사용하는 것이 가장 쉽고 가장 안전한 옵션 일뿐입니다.
새로운 PHP 비밀번호 API (5.5.0+)
PHP 버전 5.5.0 이상을 사용하는 경우 새로운 단순화 된 비밀번호 해싱 API를 사용할 수 있습니다
PHP의 비밀번호 API를 사용하는 코드의 예 :
<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);
// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}
(여전히 레거시 5.3.7 이상을 사용하는 경우 내장 기능에 액세스 할 수 있도록 ircmaxell / password_compat 를 설치할 수 있습니다 )
소금에 절인 해시 개선 : 후추 추가
보안을 강화하려면 지금 보안 담당자 (2017)는 소금에 절인 암호 해시에 ' 후추 '를 추가 할 것을 권장 합니다.
Netsilik / PepperedPasswords ( github ) 는이 패턴을 안전하게 구현하는 클래스가 간단하고 좋습니다 .
MIT 라이센스와 함께 제공되므로 독점 프로젝트에서도 원하는대로 사용할 수 있습니다.
다음을 사용하는 코드 예 Netsilik/PepperedPasswords
:
<?php
use Netsilik/Lib/PepperedPasswords;
// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');
$hasher = new PepperedPasswords($config['pepper']);
// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);
// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}
OLD 표준 라이브러리
참고 : 더 이상 필요하지 않아야합니다! 이것은 역사적인 목적을 위해서만 여기에 있습니다.
Take a look at: Portable PHP password hashing framework: phpass and make sure you use the CRYPT_BLOWFISH
algorithm if at all possible.
Example of code using phpass (v0.2):
<?php
require('PasswordHash.php');
$pwdHasher = new PasswordHash(8, FALSE);
// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );
// $hash would be the $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}
PHPass has been implemented in some quite well known projects:
- phpBB3
- WordPress 2.5+ as well as bbPress
- the Drupal 7 release, (module available for Drupal 5 & 6)
- others
The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.
For more information on password storage schemes, read Jeff`s blog post: You're Probably Storing Passwords Incorrectly
Whatever you do if you go for the 'I'll do it myself, thank you' approach, do not use MD5
or SHA1
anymore. They are nice hashing algorithm, but considered broken for security purposes.
Currently, using crypt, with CRYPT_BLOWFISH is the best practice.
CRYPT_BLOWFISH in PHP is an implementation of the Bcrypt hash. Bcrypt is based on the Blowfish block cipher, making use of it's expensive key setup to slow the algorithm down.
Your users will be much safer if you used parameterized queries instead of concatenating SQL statements. And the salt should be unique for each user and should be stored along with the password hash.
A better way would be for each user to have a unique salt.
The benefit of having a salt is that it makes it harder for an attacker to pre-generate the MD5 signature of every dictionary word. But if an attacker learns that you have a fixed salt, they could then pre-generate the MD5 signature of every dictionary word prefixed by your fixed salt.
A better way is each time a user changes their password, your system generate a random salt and store that salt along with the user record. It makes it a bit more expensive to check the password (since you need to look up the salt before you can generate the MD5 signature) but it makes it much more difficult for an attacker to pre-generate MD5's.
With PHP 5.5 (what I describe is available to even earlier versions, see below) around the corner I'd like to suggest to use its new, built-in solution: password_hash()
and password_verify()
. It provides several options in order to achieve the level of password security you need (for example by specifying a "cost" parameter through the $options
array)
<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));
$options = array(
'cost' => 7, // this is the number of rounds for bcrypt
// 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>
will return
string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
As you might see, the string contains the salt as well as the cost that was specified in the options. It also contains the algorithm used.
Therefore, when checking the password (for example when the user logs in), when using the complimentary password_verify()
function it will extract the necessary crypto parameters from the password hash itself.
When not specifying a salt, the generated password hash will be different upon every call of password_hash()
because the salt is generated randomly. Therefore comparing a previous hash with a newly generated one will fail, even for a correct password.
Verifying works like this:
var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
I hope that providing these built-in functions will soon provide better password security in case of data theft, as it reduces the amount of thought the programmer has to put into a proper implementation.
There is a small library (one PHP file) that will give you PHP 5.5's password_hash
in PHP 5.3.7+: https://github.com/ircmaxell/password_compat
That's fine with me. Mr Atwood wrote about the strength of MD5 against rainbow tables, and basically with a long salt like that you're sitting pretty (though some random punctuation/numbers, it could improve it).
You could also look at SHA-1, which seems to be getting more popular these days.
I want to add:
- Don't limit users passwords by length
For compatibility with old systems often set a limit for the maximum length of the password. This is a bad security policy: if you set restriction, set it only for the minimum length of passwords.
- Don't send user passwords via email
For recovering a forgotten password you should send the address by which user can change the password.
- Update the hashes of users passwords
The password hash may be out of date (parameters of the algorithm may be updated). By using the function password_needs_rehash()
you can check it out.
참고URL : https://stackoverflow.com/questions/1581610/how-can-i-store-my-users-passwords-safely
'Programming' 카테고리의 다른 글
getResourceAsStream () 대 FileInputStream (0) | 2020.05.26 |
---|---|
#include 종속성을 추적하는 도구 (0) | 2020.05.26 |
T-SQL에서 백분율 기호를 어떻게 이스케이프합니까? (0) | 2020.05.26 |
반투명 배경을 만들려면 어떻게해야합니까? (0) | 2020.05.26 |
루비 클래스 인스턴스 변수와 클래스 변수 (0) | 2020.05.26 |