Как сохранить учетные данные для базовой аутентификации HTTP в базе данных на стороне сервера?

В целях обучения я создал простое PHP-приложение, которое реализует веб-сервис с базовым механизмом аутентификации. Я знаю, что базовая аутентификация — не лучший механизм, но я просто хочу начать с этого механизма, прежде чем начинать с OAuth2.0 или чего-то еще.

Итак, моя текущая среда выглядит так:

Несколько клиентов предоставляют данные в JSON-представлении только через соединение https.

Эти ресурсы защищены с помощью основного заголовка аутентификации, и клиенты предоставляют данные, только если учетные данные действительны:

public function provideData()
{
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="Example BasicAuth"');
header('HTTP/1.0 401 Unauthorized');
die('Authentication failed');
}

$user = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];

// not relevant database stuff ...

$password = hash('sha512', $password . $saltDb);

if (!hash_equals($password, $passwordDb)) {
die('Authentication failed');
}

// not relevant data handling stuff ...

return json_encode($data);
}

Таким образом, каждый клиент сохраняет свои собственные учетные данные в клиентской базе данных и предоставляет данные только в том случае, если введенные данные являются действительными. (Я не хочу хранить учетные данные в виде простого текста в клиентской базе данных, поэтому я храню соленые хешированные пароли.). Это прекрасно работает для меня, но теперь наступает момент, когда я попал в беду:

Есть сервер, который должен собирать данные всех этих клиентов. По этой причине я могу создать несколько клиентских объектов на стороне сервера, которые содержат такие данные, как URL ресурса, имя пользователя, пароль и т. Д., Но я не хочу хранить пароли клиента в виде простого текста в базе данных сервера, но я также не может хранить хешированные пароли клиентов на стороне сервера, потому что сервер не будет знать о реальном пароле.

Поэтому я думаю, что единственное решение — реализовать пользовательскую функцию шифрования и дешифрования для хранения зашифрованного пароля клиента в базе данных сервера. Тогда только сервер знает о шифровании и дешифровании и может справиться с этим, или есть лучший способ сохранить необходимые учетные данные клиента на стороне сервера?

РЕДАКТИРОВАТЬ

Я постараюсь уточнить, «сервер не будет знать о реальном пароле». Пожалуйста, прервите меня, если я ошибаюсь, но базовая HTTP-аутентификация будет использовать простые данные клиента (имя пользователя и пароль) и отправит их в кодировке base64, например, Msgstr «Авторизация: Basic dXNlcjpwYXNzd29yZA ==» для получения доступа к ресурсу. По этой причине сервер должен использовать пароль в виде открытого текста для создания запроса с базовым заголовком аутентификации.

Проблема в том, что когда я создаю объект клиента на стороне сервера, мне нужно сохранить учетные данные в базе данных сервера, и я могу хэшировать пароль там, но хеш-функции являются односторонними функциями, поэтому сервер не сможет получить простой пароль из хешированного пароля обратно, без сохранения простого пароля, но если серверу нужен простой пароль для доступа к ресурсу, я не могу использовать хэш-функцию для «защиты» пароля в базе данных.

1

Решение

Если я понимаю, что вы пытаетесь сделать (что я, вероятно, не понимаю), мне кажется, что это хорошо подходит для асимметричного шифрования (например, RSA)

Асимметричное шифрование имеет 2 ключа, открытый и закрытый ключ:

  • открытый ключ может декодировать только то, что зашифровано закрытым ключом
  • закрытый ключ может декодировать только то, что зашифровано открытым ключом

Это, кажется, соответствует тому, что вам нужно:

  1. Вы можете зашифровать пароль с открытым ключом на клиенте
  2. Вы можете хранить зашифрованный пароль в клиентской базе данных
  3. Вы можете безопасно отправить зашифрованный пароль на сервер
  4. Сервер может декодировать его используя свой закрытый ключ
  5. Многие клиенты могут использовать один и тот же открытый ключ, что упрощает развертывание.
  6. Любой данный клиент не может декодировать пароль другого клиента, поскольку только закрытый ключ может декодировать данные, закодированные открытым ключом.

Быстрая реализация с использованием openSSL (для этого необходимо включить и расширение) и сертификаты (это может быть самозаверяющий сертификат)

Открытый ключ реализация на клиенте:

public function asymEncodePublic($string){
//public cert
$file = __DIR__.'/public/server.crt';
if(file_exists($file)){
$fp = fopen($file,"r");
$public_key = fread($fp,8192);
openssl_get_publickey(public_key);
fclose($fp);

//var to store output
$crypttext = '';
openssl_public_encrypt($string, $crypttext, $pub_key);
//convert from bin to hex
$crypttext = bin2hex($crypttext);
return $crypttext;
}
}

Закрытый ключ Реализация на сервере:

public function asymDecodePrivate($crypttext){
//private key
$file = __DIR__.'/private/server.key';
if(file_exists($file)){
$fp = fopen($file,"r");
$private_key = fread($fp,8192);
openssl_get_publickey($private_key);
fclose($fp);
//convert hex to bin
$crypttext = hex2bin($crypttext);
//var to store output
$decrypted = '';
//decrypt
openssl_private_decrypt($crypttext, $decrypted, $private_key);

return $decrypted;
}
}

Одна вещь, если я правильно помню, длина данных, которые вы можете зашифровать (с помощью openSSL) за один раз, зависит от сложности сертификата. Так, например, с сертификатом 2048 вы можете зашифровать только 256 байт за раз. У меня было какое-то время чувство, что мне приходилось иметь дело с этим, поэтому я точно не помню.

Несколько заметок
Что-то мне не понятно.

потому что сервер не будет знать о реальном пароле, то

Действительно ли серверу нужно знать «настоящий» пароль. Единственная причина, по которой я мог бы подумать, что сервер должен знать, — это пароль для стороннего приложения. Примером может служить sFTP на клиентской машине.

Это может быть использовано для извлечения или размещения файлов на удаленном клиенте с сервера. В этом случае серверу всегда будет необходим доступ к текстовой версии пароля. Таким образом, он может войти на удаленный компьютер. В этом случае нет реального способа обеспечить его 100%. Вы можете сделать это более сложным. Например, для OpenSSL хакеру потребуется зашифрованный пароль, закрытый ключ и, возможно, ваша реализация шифрования OpenSSL.

Отказ от ответственности:

В целях обучения я создал простое PHP-приложение

Я не претендую на звание эксперта по криптографии

0

Другие решения

Базовая аутентификация HTTP требует наличия учетных данных открытого текста, которые должны быть закодированы в base64. Таким образом, сервер должен хранить учетные данные в виде открытого текста для каждого клиента в базе данных, например, если это должно работать, НО это действительно плохо, потому что если кто-то украл базу данных сервера, он получил доступ к данным всех клиентов. Чтобы скрыть, пароли ведут к безопасности через неясность и не совсем лучше.

Так что это неправильный путь. Кажется, что базовая аутентификация HTTP не подходит для межмашинного взаимодействия через REST API, и я должен использовать надлежащий и безопасный механизм, такой как предложенный OAuth2.0 или @ArtisticPhoenix.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector