Шифрование / дешифрование пользовательских данных PHP, MySQL и AES

Я новичок в шифровании AES, но пытаюсь создать решение, которое:

  • Принимает данные потребителей
  • Шифрует эти данные с помощью AES и «открытого» ключа.
  • Храните эти данные в базе данных MySQL.
  • Иметь возможность извлекать и расшифровывать данные ТОЛЬКО с помощью закрытого ключа (хранящегося на моей личной машине, а не на самом сервере).

Я понимаю, что это может быть излишним, но хочу, чтобы мои данные потребителя были чрезмерно защищены.

Несколько замечаний:

  1. Это не информация о кредитной карте, поэтому, пожалуйста, не пишите мне о PCI-DSS, это другая форма личной информации, длина каждого поля не превышает 500 символов.
  2. Я могу хранить части информации о потребителях и другие данные во второй базе данных, связанных вместе уникальным идентификатором участника для дополнительной безопасности.
  3. Входящие вызовы MySQL могут осуществляться только на мой сервер напрямую с моего статического IP-адреса.
  4. Корень SSH отключен, порты изменены и так далее, поэтому я чувствую, что мой сервер находится в отличной форме, чтобы предотвратить любое «простое» неправильное использование.

Я искал статьи в Интернете и ТАК, но не нашел многого с точки зрения полного сохранения закрытого ключа на сервере. Даже если мне нужно оставить сам сервер - мои мысли или предложения о том, как двигаться дальше, приветствуются.

РЕДАКТИРОВАТЬ - УТОЧНЕНИЕ

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

  • Клиент вводит свой номер телефона онлайн.

  • Введенный номер телефона зашифрован онлайн с использованием ключа A и хранится в базе данных mysql.

  • На этом этапе клиент никогда не сможет снова увидеть телефон полностью, но, безусловно, сможет обновить его (выполняя процесс с клавишей A в энный раз)

  • Как системный администратор, я могу получить доступ к данным только путем загрузки и расшифровки данных на моем локальном компьютере (это или я должен сначала загрузить временный файл, который затем используется для расшифровки нужных мне данных).

РЕДАКТИРОВАТЬ 2 - Я идиот

Я использую ответ Эндрю Купера ниже, но мне не удается заставить мой скрипт прочитать содержимое созданного мной файла .pem. На основе приведенного ниже кода - как мне получить открытый ключ $, соответствующий определенному файлу .pem на моем сервере?

<?php

if (isset($_SERVER['HTTPS']) )
{
    echo "SECURE: This page is being accessed through a secure connection.<br><br>";
}
else
{
    echo "UNSECURE: This page is being access through an unsecure connection.<br><br>";
}


// Create the keypair
$res=openssl_pkey_new();

// Get private key
openssl_pkey_export($res, $privatekey);

// Get public key
$publickey=openssl_pkey_get_details($res);
$publickey=$publickey["key"];

echo "Private Key:<BR>$privatekey<br><br>Public Key:<BR>$publickey<BR><BR>";

$cleartext = '1234 5678 9012 3456';

echo "Clear text:<br>$cleartext<BR><BR>";

openssl_public_encrypt($cleartext, $crypttext, $publickey);

echo "Crypt text:<br>$crypttext<BR><BR>";

openssl_private_decrypt($crypttext, $decrypted, $privatekey);

echo "Decrypted text:<BR>$decrypted<br><br>";
?>

РЕДАКТИРОВАТЬ 3 - возможно, не «идиот», но точки с запятой меня ненавидят

Я поставил точку с запятой не на своем месте. Я использую функцию file_get_contents (), но есть ли более предпочтительный метод чтения данных для файла .pem?


person JM4    schedule 25.10.2010    source источник


Ответы (3)


Вы должны иметь возможность сгенерировать пару открытого / закрытого ключей на своем персональном компьютере, а затем опубликовать открытый ключ в своем приложении, чтобы данные можно было зашифровать. Таким образом, сервер никогда не видит закрытый ключ, и если сервер будет взломан, данные останутся в безопасности.

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

Обновить

Ознакомьтесь с http://plugins.jquery.com/project/jQuery-Gibberish-AES. Это плагин JQuery, который, похоже, допускает такой сценарий. У меня нет опыта в его использовании, но мне кажется, что это хорошее начало.

Новое обновление

Просто чтобы прояснить то, что я предлагаю, и отреагировать на ваше редактирование:

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

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

  1. На вашей частной машине создайте пару открытого / закрытого ключей и сохраните закрытый ключ в безопасности.
  2. Поместите открытый ключ в код, который вы отправляете клиенту.
  3. When the user submits the form the client code:
    1. Generates a random AES key (the session key)
    2. Шифрует данные формы
    3. Использует ваш открытый ключ и алгоритм RSA для шифрования сеансового ключа.
    4. Отменяет сеансовый ключ открытого текста
    5. Отправляет зашифрованные данные формы и зашифрованный ключ сеанса на ваш сервер
  4. Ваш сервер принимает зашифрованные данные формы и сохраняет их вместе с зашифрованным ключом в базе данных.

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

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

Следуя этой схеме, когда вы хотите получить данные, вы должны выгружать необходимые данные в зашифрованном виде из базы данных на свой частный компьютер. Для каждого фрагмента зашифрованных данных:

  1. Расшифруйте сеансовый ключ, используя алгоритм RSA и свой закрытый ключ.
  2. Расшифруйте данные с помощью AES с ключом сеанса из шага 1.

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

person Andrew Cooper    schedule 25.10.2010
comment
Я не уверен, как это должно работать: AES_ENCRYPT может зашифровать, используя только одну строку и один ключ. Везде, у кого есть доступ к ключу, есть доступ ко всему, что содержится в большом двоичном объекте, который шифрует ключ. Как сервер может что-то зашифровать, не имея доступа к этому ключу? - person cwallenpoole; 26.10.2010
comment
@Christopher W. Allen-Poole - Вы предполагаете, что шифрование происходит на сервере. Если это происходит на клиенте, а затем клиент отправляет зашифрованные данные и ключ, зашифрованный с помощью открытого ключа, тогда на сервере нет ничего, что могло бы их расшифровать. Серверу не нужно знать сеансовый ключ, используемый для шифрования данных. - person Andrew Cooper; 26.10.2010
comment
@Andrew Cooper - я посмотрел на тарабарщину, код jquery, но, похоже, не всегда работает так, как указано, и документация ужасна. Я добавил новую правку, чтобы подробнее объяснить свою цель. - person JM4; 28.10.2010
comment
@ JM4: Как я уже сказал, у меня нет опыта работы с тарабарщиной - я только что нашел его через Google. Я уверен, что есть инструменты, которые вам помогут. См. Мое обновление для более подробного объяснения предлагаемого мной подхода. - person Andrew Cooper; 28.10.2010
comment
@ Эндрю Купер - Я уже начал процесс использования вашего метода, и мне он нравится больше всего. Не могли бы вы взглянуть на мою последнюю редакцию, если у вас есть шанс. - person JM4; 28.10.2010
comment
У меня отсутствовала точка с запятой (да ...), но я использую file_get_contents (); есть ли более предпочтительный метод? - person JM4; 28.10.2010
comment
@ JM4 - я не знаю, есть ли предпочтительный метод. Если file_get_contents (); работает, то я бы придерживался этого. - person Andrew Cooper; 28.10.2010

Шифрует эти данные с помощью AES и «открытого» ключа ... расшифровывать данные ТОЛЬКО с помощью закрытого ключа

Но AES - это симметричный алгоритм шифрования, то есть для шифрования и дешифрования используется один и тот же ключ.

Или вы имеете в виду, что хотите реализовать что-то вроде SSL, где какой-то асимметричный алгоритм используется для шифрования случайно сгенерированного ключа, а конечные точки используют этот ключ для симметричного алгоритма? Такой подход приносит пользу только тогда, когда размер данных, подлежащих шифрованию, значительно превышает размер используемых ключей - так ли это здесь?

Имейте Google для PHP и RSA или ELGamal для алгоритмов ассиметричного шифрования. (обратите внимание, что, вероятно, будет значительно быстрее и проще программировать, если вы используете что-то вроде GPG для шифрования - для этого есть оболочки на phpclasses).

C.

person symcbean    schedule 26.10.2010
comment
+1 за использование GPG, идеально соответствует требованиям, и вам не придется пачкать руки криптовалютой. - person SimonJ; 26.10.2010
comment
Только не забудьте где-нибудь сделать резервную копию ключа :) - person SimonJ; 26.10.2010
comment
в конечном счете, я только пытаюсь гарантировать, что кто-то не сможет «расшифровать» данные в моей базе данных, если сервер будет скомпрометирован (и, имея единственный «ключ дешифрования», хранящийся локально, я думал, что это, по крайней мере, сильная мера безопасности). - person JM4; 28.10.2010

... Это не кажется мне возможным. Метод MySQL AES_DECRYPT требует закодированного сообщения, а также исходного ключа, чтобы что-то расшифровать. Это означает, что любой, кто может получить ключ шифрования, может расшифровать сообщение.

person cwallenpoole    schedule 25.10.2010
comment
Но он не хочет его расшифровывать. Он хочет хранить данные в базе данных в зашифрованном виде. Правильно @ JM4? - person Andrew Cooper; 26.10.2010
comment
Это правильно - я могу расшифровать онлайн, используя свой собственный ключ во временных ситуациях, но я никогда не хочу иметь возможность смотреть прямо в БД и видеть открытые данные - person JM4; 26.10.2010
comment
Если я пытаюсь использовать ключ foo для шифрования, тогда PHP должен где-то иметь AES_ENCRYPT ($ password, 'foo'). Это означает, что любой, кто имеет доступ для чтения к файлу, который контролирует шифрование, может затем расшифровать базу данных. Однако, если он единственный, у кого есть доступ для чтения, не имеет значения, где находится закрытый ключ. - person cwallenpoole; 26.10.2010
comment
Ответ - не шифруйте на сервере. Зашифруйте данные на стороне клиента и отправьте на сервер (а затем сохраните в базе данных) в зашифрованном виде вместе с ключом сеанса, зашифрованным с помощью открытого ключа. Единственный способ расшифровать данные - сначала расшифровать сеансовый ключ с помощью закрытого ключа, который хранится, ммм, закрытым. - person Andrew Cooper; 26.10.2010
comment
Я предполагаю, что шифрование происходит на стороне сервера, потому что он сказал, что хочет использовать AES. AES просто не работает так, как вы предлагаете (stackoverflow.com/questions/273396/). - person cwallenpoole; 26.10.2010
comment
@Christopher W. Allen-Poole: Я понимаю, как работает AES. Вы можете зашифровать сообщение, используя AES (симметричное шифрование) и сеансовый ключ. Затем вы можете зашифровать сеансовый ключ с помощью алгоритма RSA и открытого ключа. Затем вы отправляете оба блока зашифрованного текста на другой конец. Единственный способ расшифровать - это расшифровать сеансовый ключ с помощью RSA и закрытого ключа, связанного с открытым ключом, который использовался для шифрования. Затем вы можете использовать расшифрованный сеансовый ключ для расшифровки данных с помощью AES. - person Andrew Cooper; 27.10.2010
comment
@ Кристофер В. Аллен-Пул: Он действительно просил AES. Он также спросил об использовании открытого ключа, отсюда и мое решение. Прелесть этого способа заключается в том, что все его веб-серверы и серверы баз данных когда-либо видели зашифрованный текст. Ни в одной из этих систем данные никогда не находятся в открытом доступе, поэтому компрометация сервера не может поставить под угрозу данные. - person Andrew Cooper; 27.10.2010