Pull to refresh

Безопасная авторизация с передачей хешированного пароля

Reading time 4 min
Views 29K
При разработке одного проекта, появилась задача осуществить защиту в случае просмотра трафика, и просмотра исходника (могут узнать хеш пароля) злоумышленниками. Имея доступ ко всем данным, никто не должен авторизоваться на сервере, не зная исходный пароль. Варианты подмены IP адреса, получение пароля непосредственно в момент ввода (keylog), или брутфорс исключаем, это уже не забота веб сайта.

Пароль по сети передаваться не будет, поэтому используется хеширование прямо в браузере, для этого использую небольшую библиотеку JavaScript SHA-1. Почему SHA-1, а не, допустим, MD5? Считается, что SHA-1 немного надежнее, да и сама JavaScript библиотека меньше, чем аналогичная (на том же сайте) для MD5.

Вместо самого пароля передается хеш hash2 = sha1_hmac(login, password), однако на сервере хранится не он, а его хеш с логином: sha1_hmac(hash2, login). Этим отсекаем возможность залогиниться, если кто-то украл захешированные данные с сервера, например, взяли из базы данных, или прочитали php файл, если хеш данные находятся в нем, как в примере ниже.

Для защиты от перехваченного трафика, с формой авторизации передается хеш, сформированный на основе random данных, IP адреса, и обратного хеша на основе логин-пароль: hash1 = sha1_hmac(password, login); key = sha1(hash1, random_key+remote_addr). Случайно сформированный ключ для хеширования хранится в сессии.

Пример:
В файле храним два хеша на основе логина и пароля, один обратный sha1_hmac(pass, login), и один прямой двойной sha1_hmac(sha1_hmac(login, pass), login).
Логин у меня не меняется, так как для моей задачи так надо, желающие могут сделать как им угодно (достаточно заменить type="hidden" на type="text").
Исходный код auth.php:
<?php

$login = 'test';
//echo hash_hmac('sha1', 'pass', $login).'<br>';
$pass1 = '7cc031be8f6cf4073cc4302af78a0c7f555620cb';
//echo hash_hmac('sha1', hash_hmac('sha1', $login, 'pass'), $login).'<br>';
$pass2 = '186e9f6871599932a75ba9c4d2be6e858ebbc268';

function key_session($regenerate = false) {
  if (isset($_SESSION['key']) and ! $regenerate) {
    $key = $_SESSION['key'];
  } else {
    $key = hash_hmac('sha1', microtime(), mt_rand());
    $_SESSION['key'] = $key;
  }
  return $key;
}

function auth() {
  global $login, $pass1, $pass2;
  $key = key_session();
  $remote_addr = $_SERVER['REMOTE_ADDR'];
  $hash = hash_hmac('sha1', $key.$remote_addr, $pass1);
  if (($_POST['key'] === $hash) and (hash_hmac('sha1', $_POST['password'], $login) === $pass2)) {
    //unset($_SESSION['key']);
    key_session(true);
    $_SESSION['remote_addr'] = $remote_addr;
    header('Location: auth.php?mode=login');
  } else {
    $key = key_session(true);
    echo <<<EOF
<script type="text/javascript" src="sha1.js"></script>
<script type="text/javascript" src="jquery-1.4.2.min.js"></script>
<form name="auth" action="auth.php" method="post">
<input type="hidden" name="remote_addr" value="$remote_addr">
<input type="hidden" name="key" value="$key">
<input type="hidden" name="login" value="$login">
$login:
<input type="password" name="password" value="">
<input type="submit">
</form>
<script>
var key = $('input[name=key]').val();
var remote_addr = $('input[name=remote_addr]').val();
$('form[name=auth]').submit(function() {
  var login = $('input[name=login]').val();
  var password = $('input[name=password]').val();
  var key_hash = hex_hmac_sha1(hex_hmac_sha1(login, password), key+remote_addr);
  $('input[name=key]').val(key_hash);
  var pass_hash = hex_hmac_sha1(password, login);
  $('input[name=password]').val(pass_hash);
});
$('input[name=password]').focus();
</script>
EOF;
  }
}

session_start();
if (isset($_SESSION['remote_addr']) and ($_SESSION['remote_addr'] === $_SERVER['REMOTE_ADDR'])) {
  if ($_GET['mode'] === 'logout') {
    unset($_SESSION['remote_addr']);
    auth();
  } else {
    print_r($_SESSION);
    echo '<a href="?mode=logout">Exit</a>';
  }
} else {
  auth();
}

* This source code was highlighted with Source Code Highlighter.


Скачать исходники: auth.zip

Пример: auth.php — пароль: pass

P.S. jQuery используется потому, что он мне нужен в дальнейшем, в принципе в нем нет необходимости для вышеописанного.

P.P.S. обратите внимание, что порядок аргументов у функции хеширования в JavaScript обратный, чем в тех же функциях PHP
Tags:
Hubs:
+3
Comments 66
Comments Comments 66

Articles