欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Laravel 中如何对大文件进行加密?

程序员文章站 2022-05-04 11:16:50
在 Laravel 项目中,用户可以上传任何大小的文件,出于安全目的,需要对这些文件进行静态加密。 Laravel 提供 encryption, 但它们主要用于加密值。 使用 encrypt 助手方法对像图像这样的小文件进行加密可以很好地工作,但是在此过程中,文件内容需要加载到内存中,这对于大文件来 ......

在 laravel 项目中,用户可以上传任何大小的文件,出于安全目的,需要对这些文件进行静态加密。

laravel 提供 encryption, 但它们主要用于加密值。 使用 encrypt 助手方法对像图像这样的小文件进行加密可以很好地工作,但是在此过程中,文件内容需要加载到内存中,这对于大文件来说是个问题。

 

我已经搜索过用于解决此问题的软件包或解决方案,并遇到了这个 stack overflow 回答和这个 php 解决方案,该解决方案基本上是 stack overflow 所描述的解决方案的 php 实现。

 

我决定创建一个为 laravel 设计的扩展包,使用简单,优雅的语法提供简单的文件加密 / 解密功能。

 

我将其称为 filevault 包,您可以 github 上查看它。 如果您想跳过本教程,可以直接转到 github 存储库并开始使用此软件包。 该扩展包包括了详细的使用文档。

 

教程

在这个教程中,我会详细描述加密大文件需要的所有步骤。

首先, 使用 laravel 安装器 创建一个新的 laravel 项目, 命名为 security-app:

laravel new security-app

  

在撰写本教程时,我正在使用 laravel v6.5.2。

 

因为我们已经使用了 laravel 安装程序,所以我们已经生成了一个应用程序密钥并将其添加到我们的 .env 文件中。 如果您使用其他安装方法,请不要忘记使用以下方法生成新的应用程序密钥:

 

php artisan key:generate

  

因为我们正在使用 laravel valet,所以应该已经为我们创建了 security-app.test 域名。 如果使用其他开发环境,则应添加一个本地域名指向新项目。

 

由于自 laravel 6 以来前端脚手架已被移至 laravel ui 中,因此我们将安装 laravel/ui 扩展包。

 

composer require laravel/ui — dev

  

接下来,我们将安装 bootstrap 和 auth 脚手架:

php artisan ui bootstrap --auth

  

并编译所有内容:

npm install && npm run dev

  

我们还需要在 .env 文件中配置数据库访问凭据并运行初始迁移:

php artisan migrate

  

现在,我们可以创建一个新用户并登录查看用户仪表板。

注意:在本演示中,我们将创建一个基本的上传表单,但是在您的应用程序中,您应该考虑使用更复杂的上传功能,对大文件使用分块上传。

 

您可以使用一个非常好的扩展包是 pion/laravel-chunk-upload.

 

laravel auth 脚手架为我们创建了一个 /home 路由,一个 homecontroller 和一个 home.blade.php 视图文件。

 

让我们编辑 home.blade.php 文件并添加一个表单和一个上传字段:

 

<form action="{{ route('uploadfile') }}" method="post" enctype="multipart/form-data" class="my-4">
    @csrf

    <div class="form-group">
        <div class="custom-file">
            <input type="file" class="custom-file-input" id="userfile" name="userfile">
            <label class="custom-file-label" for="userfile">choose a file</label>
        </div>
    </div>

    <button type="submit" class="btn btn-primary">upload</button>

    @if (session()->has('message'))
        <div class="alert alert-success mt-3">
            {{ session('message') }}
        </div>
    @endif
</form>

  

然后添加相应的路由:

route::post(‘/home’, ‘homecontroller@store’)->name(‘uploadfile’);

在 homecontroller 中新增 store 方法。 此方法会将上传的文件存储在具有当前用户 id 的文件目录中 (storage/app/files/{user-id}) 。

 

注意:这是不正确的做法,不应在生产环境中使用。 为了使本教程更加小巧,我们使用文件系统来获取用户的文件,但是在生产环境中,需要使用数据库来跟踪每个用户上传的文件。

 

<?php
   /**
     * store a user uploaded file
     *
     * @param  \illuminate\http\request $request
     * @return \illuminate\http\response
     */
    public function store(request $request)
    {
        if ($request->hasfile('userfile') && $request->file('userfile')->isvalid()) {
            storage::putfile('files/' . auth()->user()->id, $request->file('userfile'));
        }

        return redirect()->route('home')->with('message', 'upload complete');
    }

  

到了加密用户上传文件 的阶段。我们将安装 file-vault 扩展包:

composer require soarecostin/file-vault

该软件包允许访问 filevault 门面, 其中提供了一些用于加密和解密文件的方法,还提供了一些方法来设置选项,例如为每个文件设置不同的加密密钥,或指定该文件的 laravel 文件系统磁盘。

 

我们将使用 filevault::encrypt($file) 方法来加密用户上传的文件。 此功能将删除原始的未加密文件,并将其替换为具有相同名称和附加 .enc 扩展名的文件。

 

如果您想使用不同的名称命名文件,则可以将所需的名称作为第二个参数传递给 encrypt 方法。 如果您想保留原始文件,可以使用 encryptcopy 方法。

 

这就是我们的 store 方法现在的样子:

 

<?php
    /**
     * store a user uploaded file
     *
     * @param  \illuminate\http\request $request
     * @return \illuminate\http\response
     */
    public function store(request $request)
    {
        if ($request->hasfile('userfile') && $request->file('userfile')->isvalid()) {
            $filename = storage::putfile('files/' . auth()->user()->id, $request->file('userfile'));

            // check to see if we have a valid file uploaded
            if ($filename) {
                filevault::encrypt($filename);
            }
        }

        return redirect()->route('home')->with('message', 'upload complete');
    }

  

接下来,我们需要查看所有用户上传的文件,还需要一种下载它们的方法。

 

我们将在 homecontroller 中创建一个新的 downloadfile 路由和一个新的 downloadfile 方法:

route::get(‘/files/{filename}’, ‘homecontroller@downloadfile’)->name(‘downloadfile’);

  

 

<?php
    /**
     * download a file
     *
     * @param  string  $filename
     * @return \illuminate\http\response
     */
    public function downloadfile($filename)
    {
        // basic validation to check if the file exists and is in the user directory
        if (!storage::has('files/' . auth()->user()->id . '/' . $filename)) {
            abort(404);
        }

        return response()->streamdownload(function () use ($filename) {
            filevault::streamdecrypt('files/' . auth()->user()->id . '/' . $filename);
        }, str::replacelast('.enc', '', $filename));
    }

  

downloadfile 使用 laravel 原生的 streamdownload response, 接收一个回调.

 

在回调中,我们正在调用扩展包 filevault 提供的 streamdecrypt 方法,它将对文件进行解密并将其逐段提供给 streamdownload 方法,从而允许您的用户直接下载解密文件。

现在,我们需要在上传表单下方显示所有用户的文件。 为此,我们将 $files 变量从 homecontroller 的 index 方法发送到 home.blade.php 视图文件,并在上传表格的下面显示用户文件。

<?php

    /**
     * show the application dashboard.
     *
     * @return \illuminate\contracts\support\renderable
     */
    public function index()
    {
        $files = storage::files('files/' . auth()->user()->id);

        return view('home', compact('files'));
    }

  

home.blade.php

<ul class="list-group">
    @forelse ($files as $file)
        <li class="list-group-item">
            <a href="{{ route('downloadfile', basename($file)) }}">
                {{ basename($file) }}
            </a>
        </li>
    @empty
        <li class="list-group-item">you have no files</li>
    @endforelse
</ul>

  

就是这样! 我们现在在使用静态加密! 我们创建了供用户上传文件的表单,对这些文件进行加密,并且仅在上传文件的用户要求时才对其解密。

当然,在生产中,需要采取更多的安全措施,而 filevault 扩展包旨在这方面为您提供帮助。

如,您可能希望将用户上传的大文件存储在 amazon s3 中,该扩展包支持文件加密 / 流解密。

 

您可能还想为每个用户或每个文件使用不同的加密密钥,这对于 filevault 扩展包也是可能的。

 

资源

    • 您可以在 github 中找到在本教程中创建的整个 laravel 应用.