Функция шифрования с PHP [duplicate]

Недавно я пытался реализовать свою собственную безопасность в сценарии входа в систему, который я наткнулся на интернет. После попытки попытаться научиться создавать собственный скрипт для создания соли для каждого пользователя, я наткнулся на password_hash.

Из того, что я понимаю (основанный на чтении на этой странице: http://php.net/manual/en/faq.passwords.php), соль уже сгенерирована в строке, когда вы используете password_hash. Это правда?

Еще один вопрос, который у меня был, было бы разумно иметь 2 соли? Один непосредственно в файле и один в БД? Таким образом, если кто-то компрометирует вашу соль в БД, у вас все еще есть один непосредственно в файле? Я читал здесь, что хранение солей никогда не является умной идеей, но это всегда путало меня, что люди подразумевали под этим.

41
задан 16 May 2015 в 21:56

5 ответов

Да, это правда. Почему вы сомневаетесь в php faq для функции? :)

Результат работы password_hash() имеет четыре части:

в алгоритме использованы параметры соль фактический пароль hash

Итак, как вы можете видеть, хэш является его частью.

Конечно, у вас может быть дополнительная соль для дополнительного уровня безопасности, но я, честно говоря, считаю, что это слишком много в обычном php-приложении. Алгоритм bcrypt по умолчанию хорош, а опция blowfish, возможно, даже лучше.

5
ответ дан 15 August 2018 в 14:36
  • 1
    BCrypt - это функция хэширования , а Blowfish - алгоритм шифрования . Однако BCrypt происходит от алгоритма Blowfish. – martinstoeckli 16 May 2015 в 21:43
  • 2
    Да это верно. – Joel Hinz 16 May 2015 в 21:47

Никогда не используйте md5 () для защиты вашего пароля, даже с солью, это всегда опасно !!

Сделайте свой пароль с последними алгоритмами хеширования, как показано ниже.

<?php

// Your original Password
$password = '121@121';

//PASSWORD_BCRYPT or PASSWORD_DEFAULT use any in the 2nd parameter
/*
PASSWORD_BCRYPT always results 60 characters long string.
PASSWORD_DEFAULT capacity is beyond 60 characters
*/
$password_encrypted = password_hash($password, PASSWORD_BCRYPT);

?>

] Для сопоставления с зашифрованным паролем базы данных и введенным пользователем паролем используйте следующую функцию.

<?php 

if (password_verify($password_inputted_by_user, $password_encrypted)) {
    // Success!
    echo 'Password Matches';
}else {
    // Invalid credentials
    echo 'Password Mismatch';
}

?>

Если вы хотите использовать свою соль, используйте свою собственную созданную функцию для нее, просто следуйте ниже, но я не рекомендую это, поскольку он найден устаревшим в последних версиях PHP.

прочитайте это http://php.net/manual/en/function.password-hash.php перед использованием ниже кода.

<?php

$options = [
    'salt' => your_custom_function_for_salt(), 
    //write your own code to generate a suitable & secured salt
    'cost' => 12 // the default cost is 10
];

$hash = password_hash($your_password, PASSWORD_DEFAULT, $options);

?>

Надеюсь, что все это поможет !!

4
ответ дан 15 August 2018 в 14:36
  • 1
    Опция соли устарела по уважительным причинам, потому что функция делает все возможное, чтобы создать криптографически безопасную соль, и почти невозможно сделать это лучше. – martinstoeckli 1 June 2017 в 16:23
  • 2
    @martinstoeckli, да, вы правы, я только что обновил свой ответ, спасибо! – Mahesh Yadav 2 June 2017 в 09:37
  • 3
    if (isset ($ _ POST ['btn-signup'])) {$ uname = mysql_real_escape_string ($ _ POST ['uname']); $ email = mysql_real_escape_string ($ _ POST ['email']); $ upass = md5 (mysql_real_escape_string ($ _ POST ['pass'])); Это код, используемый в login.php .. Я хочу обойтись без использования escape и md5. Я хочу использовать хэш пароля. – rashmi sm 19 July 2017 в 08:37
  • 4
    PASSWORD_DEFAULT - Использовать алгоритм bcrypt (Требовать PHP 5.5.0). Обратите внимание, что эта константа предназначена для изменения с течением времени, когда новые и более сильные алгоритмы добавляются в PHP. По этой причине длина результата от использования этого идентификатора может меняться со временем. – Adrian P. 25 January 2018 в 05:36

Да, вы поняли это правильно, функция password_hash () будет генерировать соль сама по себе и включает ее в полученное хеш-значение.

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($_POST['password'], PASSWORD_DEFAULT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($_POST['password'], $existingHashFromDb);

Вторая соль, которую вы упомянули (тот, который хранится в файле), на самом деле является перцем или серверной стороной ключ. Если вы добавите его перед хэшированием (например, соль), добавьте перец. Однако есть лучший способ, вы можете сначала вычислить хэш, а затем зашифровать (двухсторонний) хеш с помощью серверного ключа. Это дает вам возможность изменить ключ, когда это необходимо.

В отличие от соли, этот ключ должен храниться в секрете. Люди часто смешивают его и пытаются скрыть соль, но лучше разрешить соль выполнять свою работу и добавить секрет с помощью ключа.

13
ответ дан 15 August 2018 в 14:36

Существует явное отсутствие обсуждения обратной и передовой совместимости, встроенной в функции паролей PHP. Примечательно:

Обратная совместимость. Функции пароля - это, по сути, хорошо написанная оболочка вокруг crypt() и по своей сути обратно совместимы с хешами crypt() -формата, даже если они используют устаревшие и / или небезопасные хэш-алгоритмов. Нападающие Совместимость. Вставка password_needs_rehash() и немного логики в ваш рабочий процесс проверки подлинности может сохранить ваши хешы в актуальном состоянии с текущими и будущими алгоритмами с потенциально нулевыми будущими изменениями рабочего процесса. Примечание. Любая строка, которая не соответствует указанному алгоритму, будет помечена для необходимости повторного использования, включая хэши, не совместимые с криптографическим кодом.

Например:

class FakeDB {
    public function __call($name, $args) {
        printf("%s::%s(%s)\n", __CLASS__, $name, json_encode($args));
        return $this;
    }
}

class MyAuth {
    protected $dbh;
    protected $fakeUsers = [
        // old crypt-md5 format
        1 => ['password' => '$1$AVbfJOzY$oIHHCHlD76Aw1xmjfTpm5.'],
        // old salted md5 format
        2 => ['password' => '3858f62230ac3c915f300c664312c63f', 'salt' => 'bar'],
        // current bcrypt format
        3 => ['password' => '$2y$10$3eUn9Rnf04DR.aj8R3WbHuBO9EdoceH9uKf6vMiD7tz766rMNOyTO']
    ];

    public function __construct($dbh) {
        $this->dbh = $dbh;
    }

    protected function getuser($id) {
        // just pretend these are coming from the DB
        return $this->fakeUsers[$id];
    }

    public function authUser($id, $password) {
        $userInfo = $this->getUser($id);

        // Do you have old, turbo-legacy, non-crypt hashes?
        if( strpos( $userInfo['password'], '$' ) !== 0 ) {
            printf("%s::legacy_hash\n", __METHOD__);
            $res = $userInfo['password'] === md5($password . $userInfo['salt']);
        } else {
            printf("%s::password_verify\n", __METHOD__);
            $res = password_verify($password, $userInfo['password']);
        }

        // once we've passed validation we can check if the hash needs updating.
        if( $res && password_needs_rehash($userInfo['password'], PASSWORD_DEFAULT) ) {
            printf("%s::rehash\n", __METHOD__);
            $stmt = $this->dbh->prepare('UPDATE users SET pass = ? WHERE user_id = ?');
            $stmt->execute([password_hash($password, PASSWORD_DEFAULT), $id]);
        }

        return $res;
    }
}

$auth = new MyAuth(new FakeDB());

for( $i=1; $i<=3; $i++) {
    var_dump($auth->authuser($i, 'foo'));
    echo PHP_EOL;
}

Выход:

MyAuth::authUser::password_verify
MyAuth::authUser::rehash
FakeDB::prepare(["UPDATE users SET pass = ? WHERE user_id = ?"])
FakeDB::execute([["$2y$10$zNjPwqQX\/RxjHiwkeUEzwOpkucNw49yN4jjiRY70viZpAx5x69kv.",1]])
bool(true)

MyAuth::authUser::legacy_hash
MyAuth::authUser::rehash
FakeDB::prepare(["UPDATE users SET pass = ? WHERE user_id = ?"])
FakeDB::execute([["$2y$10$VRTu4pgIkGUvilTDRTXYeOQSEYqe2GjsPoWvDUeYdV2x\/\/StjZYHu",2]])
bool(true)

MyAuth::authUser::password_verify
bool(true)

В качестве последней заметки, учитывая, что вы можете только повторно использовать пароль пользователя при входе в систему, вы следует учитывать «заходящие» ненадежные устаревшие хэши для защиты ваших пользователей. Под этим я подразумеваю, что после определенного льготного периода вы удаляете все неустойчивые [например: голые MD5 / SHA / в противном случае слабые] хэши и ваши пользователи полагаются на механизмы сброса пароля вашего приложения.

2
ответ дан 15 August 2018 в 14:36

Я создал функцию, которую я все время использую для проверки пароля и создания паролей, например. для их хранения в базе данных MySQL. Он использует случайно сгенерированную соль, которая более безопасна, чем использование статической соли.

function secure_password($user_pwd, $multi) {

/*
    secure_password ( string $user_pwd, boolean/string $multi ) 

    *** Description: 
        This function verifies a password against a (database-) stored password's hash or
        returns $hash for a given password if $multi is set to either true or false

    *** Examples:
        // To check a password against its hash
        if(secure_password($user_password, $row['user_password'])) {
            login_function();
        } 
        // To create a password-hash
        $my_password = 'uber_sEcUrE_pass';
        $hash = secure_password($my_password, true);
        echo $hash;
*/

// Set options for encryption and build unique random hash
$crypt_options = ['cost' => 11, 'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)];
$hash = password_hash($user_pwd, PASSWORD_BCRYPT, $crypt_options);

// If $multi is not boolean check password and return validation state true/false
if($multi!==true && $multi!==false) {
    if (password_verify($user_pwd, $table_pwd = $multi)) {
        return true; // valid password
    } else {
        return false; // invalid password
    }
// If $multi is boolean return $hash
} else return $hash;

}
1
ответ дан 15 August 2018 в 14:36
  • 1
    Лучше всего опустить параметр salt, он будет автоматически сгенерирован функцией password_hash () , следуя лучшим практикам. Вместо PASSWORD_BCRYPT можно использовать PASSWORD_DEFAULT для записи будущего кода. – martinstoeckli 23 August 2017 в 14:29
  • 2
    Спасибо, что посоветуйте. Я, должно быть, наблюдал за этим в документации. Прошли долгие ночи. – Gerrit Fries 24 August 2017 в 16:41
  • 3
    Согласно secure.php.net/manual/en/function.password-hash.php «Опция salt устарела с PHP 7.0.0. Теперь предпочтительно использовать соль, которая генерируется по умолчанию. & Quot; – derelict 26 February 2018 в 02:18
  • 4
    Большое спасибо. Отличная работа. – sajushko 10 August 2018 в 06:37

Другие вопросы по тегам:

Похожие вопросы: