Подтвердить что ты не робот

Создание зашифрованного zip-архива с помощью PHP

Я ищу способ зашифровать файл .txt в zip, но защищенным паролем способом. Моя цель - отправить мне этот файл по электронной почте, без возможности прочитать содержание вложения.

Кто-нибудь знает простой и, прежде всего, безопасный способ добиться этого? Я могу создавать zip-архивы, но я не знаю, как их зашифровать, или насколько это безопасно.

4b9b3361

Ответ 1

Примечание: этот ответ рекомендует криптографический метод, который известен небезопасный, даже с хорошим паролем. Пожалуйста, см. Ссылку из комментариеви Winzip QA на AES. Поддержка шифрования in-php AES zip прибывает с php 7.2libzip 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 на клиентском декодере (для вещей, которые я хочу быстро заглянуть в браузер).