uwdoem / secure-upload
使用非对称加密进行安全文件上传。
Requires (Dev)
- athens/standard: *
- codeclimate/php-test-reporter: dev-master
- phpdocumentor/phpdocumentor: 2.7.*
- phpunit/phpunit: 4.5.*
This package is not auto-updated.
Last update: 2024-09-14 19:31:03 UTC
README
Secure-Upload
此库旨在帮助保护上传文档的内容,防止攻击者通过获得PHP网络应用程序的文件系统读取访问权限来攻击。
使用此库涉及三个主要组件
- 一个公钥/私钥对。
- 一个用于接收上传文档的Web服务器。上传的文档在上传时立即使用公钥加密,然后立即销毁未加密的文档。
- 一个文件服务器,您的授权用户可以从该服务器检索上传的文档。您将提供一种从Web服务器检索加密文档并使用私钥在文件服务器上解密这些文档的过程。当然,您需要维护一个您信任的文件服务器,以托管这些未加密的文档。
请注意,私钥不存储在Web服务器上。如果攻击者在此期间获得对您的Web服务器的读取访问权限,则攻击者只能看到一组加密的文档,他们无法检索私钥,这会给他们解密这些文档的能力。
示例
对于此示例,我们假设
- 您的Web服务器正在运行Apache、*nix,当然还有PHP。
- 您的文件服务器可以是*nix或Windows。
- 我们使用(Composer)[https://getcomposer.org.cn/] 进行包管理,但您可以将示例修改为不使用Composer。
此示例 不解决 如何将加密文件从Web服务器移动到文件服务器。在*nix上,您可能会选择使用 rsync --delete ...
命令移动它们。在Windows上,您可以使用WinSCP。使用 authorized_keys
文件,您可以在*nix或Windows上创建一个自动作业,自动移动这些文件。
创建私钥/公钥对
在*nix中创建私钥/公钥对
openssl genrsa -out my_key_name.pem 4096
openssl rsa -in my_key_name.pem -pubout > my_key_name.pub
您应将您的密钥的公共副本(my_key_name.pub
)放置在您的Web服务器上。但您 不应 将您的密钥的私用副本(my_key_name.pem
)放置在您的Web服务器上。您的密钥的私用副本需要放置在您的文件服务器上。
示例Web应用程序
Web应用程序结构
mywebapp
├── composer.json
├── index.php
├── cert
├── .htaccess
└── my_key_name.pub
└── uploads
└── .htaccess
目录 uploads
必须可写给您的Apache用户。例如,您可能会使用 chmod o+w uploads
。
在 composer.json
中指定 uwdoem/secure-upload
包为必需项。您需要运行 composer install
安装此包和 vendor
目录。
composer.json
{
"require": {
"uwdoem/secure-upload": "^0.2.0"
}
}
我们将放置 .htaccess
文件,以阻止访问 cert
和 uploads
目录。
cert/.htaccess
deny from all
uploads/.htaccess
deny from all
index.php
是我们的主页面。
index.php
<?php
require_once(__DIR__ . '/vendor/autoload.php');
use UWDOEM\SecureUploads\Cipher;
// Turn on error reporting, but only for troubleshooting and development
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if ($_SERVER['REQUEST_METHOD'] === 'GET') { ?>
<html>
<body>
<form method="POST" action="." enctype="multipart/form-data">
<input type="file" name="myFile">
<input type="submit" value="Submit">
</form>
</body>
</html>
<?php } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
$thereWereUploadErrors = $_FILES['myFile']['error'] || $_FILES['myFile']['size'] === 0;
if ($thereWereUploadErrors) { echo "Error uploading document"; die(); }
// The path to your public key
$publicKeyLocation = __DIR__ . '/cert/my_key_name.pub';
// The path of the file, as uploaded by Apache
$fileLocation = $_FILES['myFile']['tmp_name'];
// The path to your uploads directory, where encrypted files shall be
// stored.
$destination = __DIR__ . '/uploads/';
// The name of the uploaded file, as chosen by the submitter
$oldFilename = $_FILES['myFile']['name'];
// Here we determine what the name of the file will be when it is
// decrypted onto the file server. The `Cipher` class provides a static
// method for "scrubbing" the file name, but you could also choose to
// prepend the file name with some identifying information, such as the
// visitor's UWNetID, if you're forcing NetID authentication.
$newFilename = Cipher::cleanFilename($oldFilename);
Cipher::encrypt($newFilename, $fileLocation, $destination, $publicKeyLocation);
?>
<html>
<body>
<p>Your file has been uploaded.</p>
</body>
</html>
<?php
}
对于每个上传的文件,都会创建四个加密文件。例如,719b5e92a27aefb858982131e8d3be56.data
、719b5e92a27aefb858982131e8d3be56.data.key
、719b5e92a27aefb858982131e8d3be56.info
和 719b5e92a27aefb858982131e8d3be56.info.key
。每个上传的文件都将有一个唯一的哈希值,前缀为 .data
、.data.key
、.info
和 .info.key
文件。
这四个文件都必须移动到您的解密脚本中,才能解密上传的文件。
示例解密脚本
在下面的树中,我已使用上述网页应用上传了两个文档,并将生成的文件移动到了我的解密脚本中
mydecrypter
├── cert
│ └── my_key_name.pem
├── composer.json
├── decrypt.php
├── in
│ ├── 719b5e92a27aefb858982131e8d3be56.data
│ ├── 719b5e92a27aefb858982131e8d3be56.data.key
│ ├── 719b5e92a27aefb858982131e8d3be56.info
│ ├── 719b5e92a27aefb858982131e8d3be56.info.key
│ ├── 7a3f189af2fc309128e144f2fc3d419e.data
│ ├── 7a3f189af2fc309128e144f2fc3d419e.data.key
│ ├── 7a3f189af2fc309128e144f2fc3d419e.info
│ └── 7a3f189af2fc309128e144f2fc3d419e.info.key
├── out
└── processed
在 composer.json
中指定 uwdoem/secure-upload
包为必需项。您需要运行 composer install
安装此包和 vendor
目录。
composer.json
{
"require": {
"uwdoem/secure-upload": "^0.2.0"
}
}
下面是执行解密的脚本。将您的加密数据文件放入 in
目录后,您可以使用 php decrypt.php
来运行脚本。
decrypt.php
<?php
require_once dirname(__FILE__) . '/vendor/autoload.php';
use UWDOEM\SecureUploads\Cipher;
// The directory where the encrypted files are
$in = __DIR__ . '/in/';
// The directory that files shall be decrypted to
$out = __DIR__ . '/out/';
// A directory to put encrypted files after they have been decrypted
$processed = __DIR__ . '/processed/';
// The path to your pirvate key
$privateKeyLocation = __DIR__ . '/cert/my_key_name.pem';
// Scan through all of the files in the input directory...
$files = scandir($in);
foreach ($files as $file) {
// If this is a data file...
if (pathinfo($file, PATHINFO_EXTENSION) === 'data') {
// Then identify the hash...
$hash = strtok($file, '.');
// Decrypt the file to the $out directory...
Cipher::decrypt($in . $file, $out, $privateKeyLocation);
// And move all of the encrypted/key/data files for this upload into
// the $processed directory.
foreach (["data", "data.key", "info", "info.key"] as $suffix) {
rename("$in//$hash.$suffix", "$processed//$hash.$suffix");
}
}
}