복붙노트

사용자의 비밀번호를 안전하게 저장하려면 어떻게해야합니까?

PHP

사용자의 비밀번호를 안전하게 저장하려면 어떻게해야합니까?

일반 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]!";
}

해결법

  1. ==============================

    1.

    암호 저장 체계를 안전하게하는 가장 쉬운 방법은 표준 라이브러리를 사용하는 것입니다.

    대부분의 프로그래머가 단독으로 처리 할 수있는 것보다 보안이 훨씬 복잡해지고 눈에 보이지 않는 스크류 업 가능성이 있기 때문에 표준 라이브러리를 사용하는 것이 가장 쉽고 안전한 방법입니다.

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

    다음을보십시오 : 휴대용 PHP 암호 해싱 프레임 워크 : phpass 그리고 가능하다면 CRYPT_BLOWFISH 알고리즘을 사용해야합니다.

    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는 꽤 잘 알려진 프로젝트에서 구현되었습니다.

    좋은 점은 세부 사항에 대해 걱정할 필요가 없다는 것입니다. 세부 사항은 경험이있는 사람들이 프로그래밍하고 인터넷에서 많은 사람들이 검토했습니다.

    암호 저장 방식에 대한 자세한 내용은 Jeff의 블로그 게시물 (패스워드를 잘못 저장 한 것 같습니다)을 읽어보십시오.

    '내가 직접 할게, 고맙다.'접근 방법을 택하면 MD5 나 SHA1을 더 이상 사용하지 마십시오. 그들은 좋은 해싱 알고리즘이지만 보안 목적으로는 깨진 것으로 간주됩니다.

    현재 CRYPT_BLOWFISH와 함께 crypt를 사용하는 것이 가장 좋습니다. PHP에서 CRYPT_BLOWFISH는 Bcrypt 해시를 구현 한 것입니다. Bcrypt는 Blowfish 블록 암호를 기반으로하며 알고리즘을 느리게하는 비싼 키 설정을 사용합니다.

  2. ==============================

    2.

    SQL 문을 연결하는 대신 매개 변수가있는 쿼리를 사용하면 사용자가 훨씬 안전 해집니다. 그리고 소금은 각 사용자마다 고유해야하며 암호 해시와 함께 저장해야합니다.

  3. ==============================

    3.

    더 나은 방법은 각 사용자가 고유 한 소금을 사용하는 것입니다.

    소금을 가지고있는 이점은 공격자가 모든 사전 단어의 MD5 서명을 미리 생성하는 것을 어렵게 만드는 것입니다. 그러나 침입자가 고정 된 소금을 가지고 있다는 것을 알게되면 고정 소금이 붙은 모든 사전 단어의 MD5 서명을 미리 생성 할 수 있습니다.

    더 좋은 방법은 사용자가 암호를 변경할 때마다 시스템에서 임의의 소금을 생성하고 소금을 사용자 기록과 함께 저장하는 것입니다. MD5 서명을 생성하기 전에 소금을 조사해야하기 때문에 암호를 확인하는 것이 약간 더 비쌉니다. 그러나 공격자가 MD5를 미리 생성하기가 훨씬 어려워집니다.

  4. ==============================

    4.

    모서리에서 PHP 5.5 (필자가 설명한 것은 이전 버전에서도 사용할 수 있습니다. 아래 참조)를 사용하여 새로운 내장 솔루션 인 password_hash () 및 password_verify ()를 사용하는 것이 좋습니다. 필요한 암호 보안 수준을 달성하기 위해 몇 가지 옵션을 제공합니다 (예 : $ options 배열을 통해 "비용"매개 변수 지정)

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

    돌아올거야.

    string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
    string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
    

    보시다시피, 문자열에는 소금과 옵션에 지정된 비용이 포함되어 있습니다. 그것은 또한 사용 된 알고리즘을 포함합니다.

    따라서 암호를 확인할 때 (예를 들어 사용자가 로그인 할 때), 무료 password_verify () 함수를 사용할 때 암호 해시 자체에서 필요한 암호 매개 변수를 추출합니다.

    salt를 지정하지 않을 경우 생성 된 암호 해시는 salt가 임의로 생성되므로 password_hash ()를 호출 할 때마다 달라집니다. 따라서 이전 암호 해시와 새로 생성 된 해시 암호를 비교하면 올바른 암호 일지라도 실패합니다.

    확인 작업은 다음과 같습니다.

    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.'));
    

    필자는 프로그래머가 적절한 구현에 투입해야하는 사고의 양을 줄이기 때문에 이러한 기본 제공 함수를 제공하면 곧 데이터 절도의 경우 암호 보안이 향상 될 것으로 기대합니다.

    PHP 5.3.7+에서 PHP 5.5의 password_hash를 제공하는 작은 라이브러리 (하나의 PHP 파일)가 있습니다 : https://github.com/ircmaxell/password_compat

  5. ==============================

    5.

    그게 나에게 좋다. 앳 우드 (Mr Atwood)는 무지개 테이블에 대한 MD5의 힘에 대해 썼습니다. 기본적으로 당신이 꽤 앉아있는 것처럼 긴 소금을 사용합니다. (무작위로 구두점 / 숫자를 사용해도 개선 될 수 있지만).

    SHA-1도보실 수 있습니다. SHA-1은 요즘 인기를 얻고있는 것 같습니다.

  6. ==============================

    6.

    나는 다음과 같이 덧붙이고 싶다.

    이전 시스템과의 호환성을 위해 종종 암호의 최대 길이 제한을 설정하십시오. 이는 잘못된 보안 정책입니다. 제한을 설정 한 경우 암호의 최소 길이에 대해서만 설정하십시오.

    잊어 버린 비밀번호를 복구하려면 사용자가 비밀번호를 변경할 수있는 주소를 보내야합니다.

    암호 해시가 유효하지 않을 수 있습니다 (알고리즘 매개 변수가 업데이트 될 수 있음). password_needs_rehash () 함수를 사용하여 체크 아웃 할 수 있습니다.

  7. from https://stackoverflow.com/questions/1581610/how-can-i-store-my-users-passwords-safely by cc-by-sa and MIT lisence