Создание зашифрованного zip-архива с помощью PHP
Я ищу способ зашифровать файл .txt в zip, но защищенным паролем способом. Моя цель - отправить мне этот файл по электронной почте, без возможности прочитать содержание вложения.
Кто-нибудь знает простой и, прежде всего, безопасный способ добиться этого? Я могу создавать zip-архивы, но я не знаю, как их зашифровать, или насколько это безопасно.
Ответы
Ответ 1
Примечание: этот ответ рекомендует криптографический метод, который известен небезопасный, даже с хорошим паролем. Пожалуйста, см. Ссылку из комментариеви Winzip QA на AES. Поддержка шифрования in-php AES zip прибывает с php 7.2 (и libzip 1.2.0), что означает ответ скоро тоже устареет. До тех пор см. Этот ответ за то, как вызывать 7z вместо zip-команды, которая поддерживает winzip's AES.
Вы можете использовать это:
<?php echo system('zip -P pass file.zip file.txt'); ?>
Если pass - пароль, а file.txt будет заархивирован в файл .zip. Это должно работать на Windows и Linux, вам просто нужно получить бесплатную версию zip для Windows (http://www.info-zip.org/Zip.html#Win32)
Такая защита может быть нарушена атаками грубой силы, атаками в словарях и т.д. Но это не так просто, особенно если вы выбрали длинный и трудноудаляющий пароль.
Ответ 2
Начиная с версии 7.2 (которая была выпущена несколько часов назад), правильный способ сделать это - использовать дополнительные функции, включенные в ZipArchive собственный код php. (спасибо Абрахаму-Тугалову за указание на то, что это изменение наступает)
Теперь простой ответ выглядит примерно так:
<?php
$zip = new ZipArchive();
if ($zip->open('test.zip', ZipArchive::CREATE) === TRUE) {
$zip->setPassword('secret_used_as_default_for_all_files'); //set default password
$zip->addFile('thing1.txt'); //add file
$zip->setEncryptionName('thing1.txt', ZipArchive::EM_AES_256); //encrypt it
$zip->addFile('thing2.txt'); //add file
$zip->setEncryptionName('thing2.txt', ZipArchive::EM_AES_256); //encrypt it
$zip->close();
echo "Added thing1 and thing2 with the same password\n";
} else {
echo "KO\n";
}
?>
Но вы также можете установить метод шифрования по индексу, а не по имени, и вы можете установить каждый пароль для каждого файла отдельно... а также указать более слабые параметры шифрования, используя недавно поддерживаемые параметры шифрования.
Этот пример демонстрирует эти более сложные варианты.
<?php
$zip = new ZipArchive();
if ($zip->open('test.zip', ZipArchive::CREATE) === TRUE) {
//being here means that we were able to create the file..
//setting this means that we do not need to pass in a password to every file, this will be the default
$zip->addFile('thing3.txt');
//$zip->setEncryptionName('thing3.txt', ZipArchive::EM_AES_128);
//$zip->setEncryptionName('thing3.txt', ZipArchive::EM_AES_192);
//you should just use ZipArchive::EM_AES_256 unless you have super-good reason why not.
$zip->setEncryptionName('thing3.txt', ZipArchive::EM_AES_256, 'password_for_thing3');
$zip->addFile('thing4.txt');
//or you can also use the index (starting at 0) of the file...
//which means the following line should do the same thing...
//but just referencing the text.txt by index instead of name..
//$zip->setEncryptionIndex(1, ZipArchive::EM_AES_256, 'password_for_thing_4'); //encrypt thing4, using its index instead of its name...
$zip->close();
echo "Added thing3 and thing4 with two different passwords\n";
} else {
echo "KO\n";
}
?>
Базовая поддержка zip-шифрования включена, потому что в libzip 1.2.0 появилась поддержка шифрования. Таким образом, вам понадобится php 7.2 и libzip 7.2, чтобы запустить этот код... Надеюсь, эта заметка будет бессмысленной в ответе "очень скоро"
Ответ 3
Хотя PHP является зрелым языком, не существует адекватного метода (исключая пользовательское расширение или что-то в этом роде) для решения такой простой задачи с использованием чистого PHP.
Вы также можете подождать, пока PHP 7.2 не станет доступным для производства (поскольку ZipArchive :: setEncryptionName реализовано (спасибо Пьеру и Реми)).
Но до тех пор вы также можете попытаться перенести php_zip > = 1.14.0 на PHP & lt; 7.2, но в настоящее время нет доступных скомпилированных двоичных файлов, поэтому вы должны скомпилировать их самостоятельно и попробовать, если это вообще возможно (я верю, что это так).
PS Я бы попробовал, но на моем ПК сейчас нет VS2015+.
Ответ 4
Все больше и больше инструментов поддерживают AES-зашифрованные ZIP файлы. Он работает, он защищен.
EDIT2: вы можете использовать DotNetZip из PHP, чтобы динамически генерировать зашифрованные ZIP-архивы AES с PHP. DotNetZip - это библиотека .NET, предназначенная для языков .NET(С#, VB и т.д.). Он работает только в Windows:( Но DotNetZip делает AES, и он бесплатный, и он работает с PHP.
Это код, который я использовал. (PHP v5.2.9 на Win32)
<?php
try
{
$fname = "zip-generated-from-php-" . date('Y-m-d-His') . ".zip";
$zipOutput = "c:\\temp\\" . $fname;
$zipfact = new COM("Ionic.Zip.ZipFile");
$zip->Name = $zipOutput;
$dirToZip= "c:\\temp\\psh";
# Encryption: 3 => 256-bit AES.
# 2 => 128-bit AES.
# 1 => PKZIP (Weak).
# 0 => None
$zip->Encryption = 3;
$zip->Password = "AES-Encryption-Is-Secure";
$zip->AddDirectory($dirToZip);
$zip->Save();
$zip->Dispose();
if (file_exists($zipOutput))
{
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type: application/x-zip');
header('Content-Disposition: attachment; filename=' . $fname);
header('Content-Length: ' . filesize($zipOutput));
readfile($zipOutput);
unlink($zipOutput);
}
else
{
echo '<html>';
echo ' <head>';
echo ' <title>Calling DotNetZip from PHP through COM</title>';
echo ' <link rel="stylesheet" href="basic.css"/>';
echo ' </head>';
echo '<body>';
echo '<h2>Whoops!</h2>' . "<br/>\n";
echo '<p>The file was not successfully generated.</p>';
echo '</body>';
echo '</html>';
}
}
catch (Exception $e)
{
echo '<html>';
echo ' <head>';
echo ' <title>Calling DotNetZip from PHP through COM</title>';
echo ' <link rel="stylesheet" href="basic.css"/>';
echo ' </head>';
echo '<body>';
echo '<h2>Whoops!</h2>' . "<br/>\n";
echo '<p>The file was not successfully generated.</p>';
echo '<p>Caught exception: ', $e->getMessage(), '</p>', "\n";
echo '<pre>';
echo $e->getTraceAsString(), "\n";
echo '</pre>';
echo '</body>';
echo '</html>';
}
?>
Мне пришлось модифицировать DotNetZip, чтобы заставить его работать с PHP: мне нужно было сделать свойство Name read/write, и мне пришлось сделать его COM-вызываемым. Это изменение впервые доступно в v1.8.2.3 release.
Ответ 5
Вот как я это сделал.
Это с превосходным, но это то же самое.
- Пусть php создает случайное кодовое имя.
- Сохраните кодовое имя в db или в файле, который будет включен в файл retrieve.php.
-
Напишите себе кодовое имя.
-
Доступ через веб-адрес retrieve.php? codename = [кодовое имя]
- Пусть php проверяет правильность кодового имени. (возможно, даже возраст).
- Создайте excel/textfile в памяти из данных, которые необходимо отправить вам.
- Создайте код шифрования, добавив локальный пароль (который только вы знаете) с кодовым именем. (Я говорю добавить, но также может быть смешанным или xor-ed или substr...)
- Зашифровать "на лету" с помощью созданного кода шифрования.
- Удалить кодовое имя из db или файла конфигурации.
- Вернуть этот зашифрованный документ в почтовом ящике (по размеру).
-
Возможно, добавьте два первых символа из кодового имени в почте, чтобы узнать, какое локальное полное кодовое имя использовать.
-
Используйте локальное дешифрование script для декодирования загруженного файла. Используйте один и тот же алгоритм кодового имени/пароля для создания ключа дешифрования.
Я использую gibberish-aes-php. (https://github.com/ivantcholakov/gibberish-aes-php)
Потому что тогда я могу использовать https://github.com/mdp/gibberish-aes как javascript на клиентском декодере (для вещей, которые я хочу быстро заглянуть в браузер).