PHP хэш-пароль для входа все время меняется

1

Привет, ребята, у меня есть некоторые проблемы с хэш-тегом для моего пароля: у меня проблема с логированием, потому что этот хэш всегда освежает..

И у меня еще один вопрос - это безопасный вход в систему?

Авторизоваться:

$email = htmlentities(addslashes($_POST['email']));
$password = create_hash($_POST['password']);
$ip_adresa = $_SERVER['REMOTE_ADDR'];

if(isset($_POST) && $email!='' && $password!=''){
    $test = mysql_fetch_array(mysql_query("SELECT * FROM users WHERE email='$email'"));
    $password = validate_password($password, $test['password']);

    $kveri = mysql_query("SELECT * FROM users WHERE email='$email' AND password='$password'");
    if (mysql_num_rows($kveri)) {
    $user = mysql_fetch_array($kveri);
    $_SESSION['userid'] = $user['userid'];
    $_SESSION['email'] = $user['email'];
    $mesec = 24*60*60*31; // mesec dana

    $sesija = md5($user['email'] . $cpass);

    if (isset($_POST['remember'])) {
        /* Set cookie to last 1 year */
        setcookie('email', $_POST['email'], time()+ $mesec);
        setcookie('password', md5($_POST['password']), time()+ $mesec);
    } else {
        /* Cookie expires when browser closes */
        setcookie('email', $_POST['email'], false);
        setcookie('password', md5($_POST['password']), false);
    }

    setcookie("userid", $user['userid'], time()+ $mesec);
    setcookie("email", $user['email'], time()+ $mesec);
    setcookie("sesija", $sesija, time() + $mesec);
    $_SESSION['ok'] = "Uspesno";
    mysql_query("UPDATE users SET ip='$ip_adresa',sesija='$sesija' WHERE userid='$_SESSION[userid]'");
    header("Location:/index.php");

    } else {
    $_SESSION['error'] = "Password or email are incorrect";
    header("Location:/index.php#sign-in");
    die();          
    }
} else {
    $_SESSION['error'] = "Email or password are empty";
    header("Location:/index.php#sign-in");
    die();
}

функции i, используемые для хеширования:

define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTE_SIZE", 24);
define("PBKDF2_HASH_BYTE_SIZE", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SIZE, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTE_SIZE,
            true
        ));
}

function validate_password($password, $correct_hash)
{
    $params = explode(":", $correct_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
    if($count <= 0 || $key_length <= 0)
        trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);

    if (function_exists("hash_pbkdf2")) {
        // The output length is in NIBBLES (4-bits) if $raw_output is false!
        if (!$raw_output) {
            $key_length = $key_length * 2;
        }
        return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
    }

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
  • 3
    вы открыты для инъекций sql; использовать подготовленное заявление
  • 0
    Что вы подразумеваете под "с хэш-тегом для моего пароля"? Как сказал Фред, вы уязвимы для sqlinjection. Также функция pbkdf2 выглядит как ваша попытка создать функцию записи. Вы должны ВСЕГДА использовать встроенные функции шифрования на языке, поскольку они будут намного более безопасными, чем ваша собственная реализация.
Показать ещё 3 комментария
Теги:
hash

1 ответ

2

У вас там пара WTF.

1) Как сказано в комментариях, SQL Injection является серьезной проблемой.
Вы используете htmlentities чтобы избежать $email но эта функция хороша только для того, чтобы вы не вводили html в сайт. Что касается предотвращения того, чтобы что-то испортилось с вашей БД? Не так много. Он не убегает '. Он предполагает ISO-8859 и т.д.... вы всегда должны использовать htmlentities при написании контента для пользователя. Не при получении контента у пользователя. Взгляните на подготовленные заявления, чтобы избежать SQL.

2) После проверки пользователя вы отправляете пароль md5'а назад и вперед в качестве файла cookie.
Зачем? Не имеет никакого смысла. Non salted MD5 легко расшифровывается, используя один из многих таблиц радуги. Просто посмотрите, как легко взломать несолистый пароль. И это не очень хороший сеансовый ключ. Если вы хотите вывести сеансы из сервера, а база данных для массового размаха, посмотрите, что Laravel/php, Play Framework/java и другие делают вдохновение в зашифрованных файлах RoR/ruby.

3) Хотя PBKDF2 в порядке, вы, вероятно, должны пойти с php password_hash.
Это проще, имеет дело с солью совершенно прозрачным способом, уступает место обновлениям как в шифровании, так и в хэш-времени и поставляется в комплекте с хорошим API.

  • 0
    Я абсолютно согласен с вашим ответом, может быть, вы могли бы переименовать «crypt» в «password_hash», чтобы избежать путаницы? Сама функция crypt не обрабатывает соль и может быть легко использована неправильно.
  • 0
    @martinstoeckli спасибо за предложение!
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню