我正在使用API后端上的Laravel和VueJS作为前端应用程序来开发文件存储和共享Web应用程序。 我必须使用CRON例程每分钟启动的BASH脚本对上传的文件进行加密,但是我需要使用Laravel / PHP从控制器将其解密为StreamDownload响应(我需要逐块解密文件,因为大块文件需要解密为我们的服务器使用过多的内存)。 我们决定从外部例程对文件进行加密,以防止用户等待文件被加密,有时在文件上传后几分钟。
我在Debian 4.9服务器上使用Laravel 5.7和PHP 7.3,但是我在Windows 10以及WAMP和PHP 7.3的本地计算机上进行了测试。我正在使用Git Bash来运行和测试我的shell命令。
我当前的FileController包含许多方法,包括“创建”和“下载”。 “创建”只是将文件存储到Laravel的存储目录中,并在数据库中创建一个新的“文件”资源,而“下载”则尝试取回加密的文件,然后解密并将其发送给客户端。
这是我的Create方法。它只是创建资源并以“ .decrypted”前缀扩展名存储文件。 (我留了很多空白,因为此方法的逻辑与加密无关)
//App\Http\Controllers\Files\FileController.php
public function create(Request $request)
{
...
$file = File::create([
'name' => $name,
'uuid' => $uuid,
...
]);
...
$output->move($userPath, $uuid.'.decrypted');
...
return new FileResource($file);
}
然后,这是我编写的BASH脚本,用于每分钟加密后缀文件(我用一些'###'替换了敏感信息,不用担心。)
#encrypt.sh
#!/bin/bash
set -euo pipefail
# PARAMETERS
APP_KEY='######'
FILES_PATH='/###/.../storage/app/files/'
FILES_LIST=$(find "$FILES_PATH" -type f -name '*.decrypted' )
KEY=$(echo "$APP_KEY" | base64 -d -i | xxd -p -c 64)
while read -r file; do
INPUT_PATH=$file
OUTPUT_PATH=${file%.decrypted}
IV=$(openssl rand -hex 16)
openssl AES-256-CBC -K $KEY -iv $IV -in $INPUT_PATH -out $OUTPUT_PATH
done < <(echo "$FILES_LIST")
echo 'Done'
据我所知,这段代码运行良好。
然后,这是我的最后一段代码:下载方法。
//App\Http\Controllers\Files\FileController.php
public function download(File $file, Request $request)
{
...
$dlFile = Storage::disk('files')->path($file->path);
...
return response()->streamDownload(
/* Note: $dlFile is the path, $file is the Laravel resource */
function () use ($dlFile, $log, $file) {
$cipher = config('app.cipher'); // AES-256-CBC
/* Note: the app key is stored in format "base64:#####...", this is why there's a substr() inside a base64() */
$key = base64_decode(substr(config('app.key'), 7));
if ($fpIn = fopen($dlFile, 'rb')) {
$iv = fread($fpIn, 16);
while (!feof($fpIn)) {
$ciphertext = fread($fpIn, $this->memoryLimit());
$plaintext = openssl_decrypt($ciphertext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
print($plaintext);
}
fclose($fpIn);
}
},
$fileName,
[
'Content-Type' => $file->mime,
'Content-Length' => $file->size
],
'inline'
);
}
我从this page获得了最后一段代码。
我想我的PHP脚本制作得不好,因为解密后的输出是错误的。有人有帮助我的想法吗?
答案 0 :(得分:0)
由于Laravel的加密方式是如何设计的,对这个问题没有一个简单的答案。
您可以重新实现Defuse Security's PHP Encryption library用于在低内存设备上加密/解密大文件的逻辑。但是,这是一个非常复杂的问题,必须模拟提供给HMAC的JSON序列化。
对于这些文件,您也可以从Laravel的内置加密库切换到Defuse的库。它具有内置的File
API,可满足您的需求。这可能是最省力的解决方案。