【问题标题】:Create an encrypted zip archive with PHP使用 PHP 创建一个加密的 zip 存档
【发布时间】:2009-03-14 16:24:56
【问题描述】:

我正在寻找一种将 .txt 文件加密为 zip 的方法,但要以安全的密码保护方式进行。我的目标是将此文件通过电子邮件发送给我,而任何人都无法阅读附件的内容。

有没有人知道一个简单的,最重要的是,安全的方法来完成这个?我可以创建 zip 存档,但我不知道如何加密它们,或者,这有多安全。

【问题讨论】:

    标签: php encryption zip


    【解决方案1】:

    从 php 7.2(几小时前发布)开始,正确的做法是使用 ZipArchive 原生 php 代码中包含的附加功能。 (感谢abraham-tugalov 指出这一变化即将到来)

    现在简单的答案看起来像这样:

    <?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";
    }
    ?>
    

    但是您也可以通过索引而不是名称来设置加密方法,并且您可以基于每个文件设置每个密码...以及指定较弱的加密选项,使用newly supported encryption options.

    本示例练习了这些更复杂的选项。

    <?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 才能运行此代码...希望此注释“很快”会在此答案上变得很简单

    【讨论】:

    • 哇,这确实有效。您必须为每个文件单独设置加密主题,这非常违反直觉。
    【解决方案2】:

    注意:此答案推荐一种已知的加密方法 不安全,即使密码很好。请see link from commentsthe Winzip QA on AES。支持 in-php AES zip 加密 与php 7.2(和libzip 1.2.0)一起到达,这意味着 答案也将很快过时。在那之前see this answer for how to call out to 7z instead of the zip command, which supports winzip's AES encryption

    你可以用这个:

    <?php echo system('zip -P pass file.zip file.txt'); ?>
    

    pass 是密码,file.txt 会被压缩成file.zip。这应该适用于 Windows 和 Linux,您只需要获得适用于 Windows 的免费版本的 zip (http://www.info-zip.org/Zip.html#Win32)

    这种安全性可以被蛮力攻击、字典攻击等破坏。但这并不容易,特别是如果你选择了一个长且难以猜到的密码。

    【讨论】:

    • 谢谢,我会试试这个。它在我正在工作的 linuxserver 上,因此不需要附加组件。
    • ZIP 加密实际上很弱,有些攻击会在相对较短的时间内产生有效密码(如果不一定与最初使用的密码相同)。
    • 这个答案非常危险。这个答案使用的加密非常弱。它不是现代的基于 AES 的加密。
    • 许多托管环境都阻止了“系统”功能。使用 ZipArchive 类更好。
    • 不确定需要什么样的安全措施。但是先进行加密,然后给自己邮寄一个压缩文件可能是更好的方法。或者甚至给自己邮寄一个链接,并在访问该链接时按需创建文件。
    【解决方案3】:

    虽然 PHP 是一门成熟的语言,但没有足够的方法(不包括自定义扩展或类似的东西)来用纯 PHP 完成如此简单的任务。

    您还可以做的是等到PHP 7.2 可用于生产(因为ZipArchive::setEncryptionName 已实现(感谢 Pierre 和 Remi))。

    但是,在那之前您也可以尝试将php_zip >= 1.14.0 移植到 PHP

    PS 我想试试,但我的电脑上现在没有 VS2015+。

    【讨论】:

      【解决方案4】:

      越来越多的工具支持 AES 加密的 ZIP 文件。它有效,它是安全的。

      EDIT2:您可以使用 PHP 中的 DotNetZip 从 PHP 动态生成 AES 加密的 zip 存档。 DotNetZip 是一个 .NET 库,专为 .NET 语言(C#、VB 等)而设计。它只能在 Windows 上运行 :(。但 DotNetZip 使用 AES,而且它是免费的,并且可以在 PHP 上运行。

      这是我使用的代码。 (Win32 上的 PHP v5.2.9)

      <?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 属性为读/写,并且我必须使其可被 COM 调用。此更改首先在 v1.8.2.3 release 中提供。

      【讨论】:

      • 你知道我如何在 php 脚本中使用它吗?非常感谢!
      • 如果您在 Windows 上运行 PHP,则有支持 AES 加密 zip 的 DotNetZip (dotnetzip.codeplex.com)。 PHP 可以调用 .NET 组件。巴达兵,巴达繁荣。
      • 不幸的是,我的大多数服务器都运行在 linux 上。但我可以将此解决方案用于 Windows 上的解决方案。非常感谢!
      • 我会用 gibberish-aes-php 加密数据。压缩(或不压缩),下载并运行本地 cli-php-script 来解密。还有一个 gibberish-aes 的 javascript 实现,因此客户端也可以是 javascript。 (github.com/ivantcholakov/gibberish-aes-php)
      • 这是一个很好的答案。但既然支持在 php 7.2 中,它应该会有所下降......
      【解决方案5】:

      我就是这样做的。 是用excel,但是是一样的。

      • 让 php 创建一个随机代号。
      • 将代号保存在db 或retrieve.php 包含的文件中。
      • 将代号邮寄给自己。

      • 通过网络访问retrieve.php?codename=[codename]

      • 让 php 检查代号是否正确。 (甚至可能是年龄)。
      • 根据需要发送给您的数据在内存中创建 excel/文本文件。
      • 通过添加带有代号的本地密码(只有您知道)来创建加密代码。(我说添加但也可以混合或异或或子...)
      • 使用创建的加密代码即时加密。
      • 从数据库或配置文件中删除代号。
      • 在邮件中返回此加密文档(压缩或未压缩大小)。
      • 可以在邮件中添加代号的前两个字符,以了解要使用的本地完整代号。

      • 使用本地解密脚本对下载的文件进行解码。使用相同的代号/密码算法创建解密密钥。

      我使用乱码-aes-php。 (https://github.com/ivantcholakov/gibberish-aes-php)
      因为那时我可以在客户端解码器上使用https://github.com/mdp/gibberish-aes 作为javascript(对于我想在浏览器中快速浏览的东西)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-25
        • 1970-01-01
        • 1970-01-01
        • 2010-11-12
        相关资源
        最近更新 更多