You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WildFly与PrimeFaces文件上传定制:加密临时文件

实现WildFly 26(Undertow)与PrimeFaces上传临时文件加密

针对Undertow原生Multipart解析和PrimeFaces+Commons FileUpload两种场景,分别提供临时文件加密的实现方案:


一、Undertow原生Multipart上传加密

Undertow通过MultiPartUploadHandler创建上传临时文件,可通过自定义FileFactory替换默认的临时文件创建逻辑,实现加密写入。

1. 自定义加密版FileFactory

实现Undertow的FileFactory接口,在创建临时文件输出流时,用加密流包装:

import io.undertow.server.handlers.form.FileFactory;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.security.SecureRandom;

public class EncryptedTempFileFactory implements FileFactory {
    // 建议从安全配置源读取密钥,而非硬编码
    private final byte[] encryptionKey = System.getenv("UPLOAD_ENCRYPT_KEY").getBytes();
    private final String cipherAlgorithm = "AES/CBC/PKCS5Padding";

    @Override
    public OutputStream createFile(File file) throws IOException {
        Files.createFile(file.toPath());
        FileOutputStream fos = new FileOutputStream(file);

        try {
            // 生成随机IV(AES-IV固定16字节)
            SecureRandom secureRandom = new SecureRandom();
            byte[] iv = new byte[16];
            secureRandom.nextBytes(iv);
            // 将IV写入文件开头,解密时需先读取
            fos.write(iv);

            // 初始化加密Cipher
            SecretKeySpec keySpec = new SecretKeySpec(encryptionKey, "AES");
            Cipher cipher = Cipher.getInstance(cipherAlgorithm);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));

            return new CipherOutputStream(fos, cipher);
        } catch (Exception e) {
            fos.close();
            Files.deleteIfExists(file.toPath());
            throw new IOException("Failed to initialize encrypted stream", e);
        }
    }

    @Override
    public File createTempFile(String prefix, String suffix, File directory) throws IOException {
        // 复用默认临时文件路径生成逻辑
        return File.createTempFile(prefix, suffix, directory);
    }
}

2. 配置Undertow使用自定义FileFactory

编程式配置(嵌入式/自定义部署)

在Undertow部署配置中替换默认的Multipart工厂:

import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.MultiPartConfigFactory;

// 构建部署信息时配置
DeploymentInfo deploymentInfo = new DeploymentInfo()
        .setContextPath("/your-app")
        .setDeploymentName("your-app.war")
        // 其他Servlet/过滤器配置...
        .setMultipartConfigFactory(new MultiPartConfigFactory()
                .setFileFactory(new EncryptedTempFileFactory()));

WildFly容器配置

若使用WildFly standalone服务器,需将自定义类打包为WildFly模块,在jboss-deployment-structure.xml中声明依赖,再通过CDI扩展或自定义Undertow Servlet容器配置替换FileFactory。


二、PrimeFaces + Commons FileUpload加密

PrimeFaces使用Commons FileUpload时,临时文件由DiskFileItemFactory创建,可通过继承该类并重写文件项创建逻辑实现加密。

1. 自定义加密版DiskFileItemFactory

import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.FileItem;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.SecureRandom;

public class EncryptedDiskFileItemFactory extends DiskFileItemFactory {
    private final byte[] encryptionKey = System.getenv("UPLOAD_ENCRYPT_KEY").getBytes();
    private final String cipherAlgorithm = "AES/CBC/PKCS5Padding";

    @Override
    public FileItem createItem(String fieldName, String contentType, boolean isFormField, String fileName) {
        DiskFileItem item = (DiskFileItem) super.createItem(fieldName, contentType, isFormField, fileName);

        try {
            FileOutputStream fos = new FileOutputStream(item.getStoreLocation());
            // 生成随机IV并写入文件开头
            SecureRandom secureRandom = new SecureRandom();
            byte[] iv = new byte[16];
            secureRandom.nextBytes(iv);
            fos.write(iv);

            // 初始化加密Cipher
            SecretKeySpec keySpec = new SecretKeySpec(encryptionKey, "AES");
            Cipher cipher = Cipher.getInstance(cipherAlgorithm);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));

            // 替换文件项的输出流为加密流
            item.setOutputStream(new CipherOutputStream(fos, cipher));
        } catch (Exception e) {
            item.delete();
            throw new RuntimeException("Failed to create encrypted temp file", e);
        }

        return item;
    }
}

2. 配置PrimeFaces使用自定义工厂

在faces-config.xml中配置FileUpload过滤器,指定自定义工厂类:

<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
    <init-param>
        <param-name>uploader</param-name>
        <param-value>commons</param-value>
    </init-param>
    <init-param>
        <param-name>factory</param-name>
        <param-value>com.your.package.EncryptedDiskFileItemFactory</param-value>
    </init-param>
</filter>

关键注意事项

  • 密钥管理:绝对禁止硬编码密钥,应使用WildFly安全Vault、环境变量或密钥管理服务(KMS)存储和读取密钥。
  • 解密逻辑:读取加密临时文件时,需先读取文件开头的IV,再初始化Cipher.DECRYPT_MODE,用CipherInputStream读取内容。
  • 性能考量:加密会增加CPU开销,需根据业务并发量测试性能,必要时调整加密算法或优化IO逻辑。
  • 临时文件清理:确保加密临时文件在使用后正常删除,避免磁盘空间泄漏。

内容的提问来源于stack exchange,提问作者László Tóth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 18:41:14