sql文件如何做完整性校验

在实际的业务场景,有时需要导出sql脚本文件,再导入执行sql脚本文件去同步数据,这里大多数数据量比较大,涉及的表和服务比较多,还可能不止一个数据库的场景。导入sql脚本文件直接执行而不去校验文件的完整性,会存在严重的安全隐患,必须要保证导入和导出的是同一个文件。

sql文件如何去做完整性校验呢?

导出sql文件时

  1. 将导出的数据写入到本地生成sql脚本文件中;
  2. 对生成sql脚本文件做MD5;
  3. 对得到的MD5值,使用AES算法加密;
  4. 使用AES加密后的值去重命名该sql文件;
  5. 导出该文件。

关键代码如下:

try {

    String path = System.getProperty("user.dir") + filePath + "export" + ".sql";

    export(sqlList, path);

    String md5Value = FileEncryptUtil.getFileMd5(path);
    log.info("md5Value: {}", md5Value);
    String aesValue = FileEncryptUtil.aesEncrypt(md5Value);
    String newPath = System.getProperty("user.dir") + filePath + aesValue + ".sql";

    File oldFile = new File(path);
    File newFile = new File(newPath);
    oldFile.renameTo(newFile);

    log.info("path: {}", newPath);
    return newPath;
} catch (IOException e) {
    log.error("导出sql文件异常,appId = {}", appId);
}
package com.angel.ocean.utils;

import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


@Slf4j
public class FileEncryptUtil {

    final static String key = "Y1yIwqT3bwEYoT1q";

    final static String iv = "gmbgzchNN9YFQAc0";

    /**
     * 加密
     *
     * @param content 需要加密的内容
     * @return
     */
    public static String aesEncrypt(String content) {
        AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, key.getBytes(), iv.getBytes());
        return aes.encryptBase64(content);
    }


    /**解密
     * @param content  待解密内容
     * @return
     */
    public static String aesDecrypt(String content) {
        AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, key.getBytes(), iv.getBytes());
        return aes.decryptStr(content);
    }

    /**
     * 求文件的MD5值
     * @param path
     * @return
     */
    public static String getFileMd5(String path) {

        File file = new File(path);

        try {
            MessageDigest md5Digest = MessageDigest.getInstance("MD5");
            return getFileChecksum(md5Digest, file);
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException, {}", e.getMessage(), e);
        } catch (IOException e) {
            log.error("IOException, {}", e.getMessage(), e);
        }

        return null;
    }

    public static String getFileChecksum(MessageDigest digest, File file) throws IOException {

        FileInputStream fis = new FileInputStream(file);

        byte[] byteArray = new byte[1024];
        int bytesCount;

        while ((bytesCount = fis.read(byteArray)) != -1) {
            digest.update(byteArray, 0, bytesCount);
        };

        fis.close();

        byte[] bytes = digest.digest();

        StringBuilder sb = new StringBuilder();
        for(int i=0; i< bytes.length; i++) {
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }

        return sb.toString();
    }
}

导入sql文件时

  1. 读取sql文件流,写入到本地;
  2. 获取文件名称,剔除.sql,就拿到AES加密后的值;
  3. 对该值进行AES解密,得到MD5值,假设为oldMd5;
  4. 对该文件进行MD5,即可得到该文件的MD5值,假设为newMd5;
  5. 校验oldMd5与newMD5的值是否相同,不一致则抛出文件完整性校验失败,导入sql失败;
  6. MD5值一致,则执行sql脚本文件。

关键代码如下:

@Override
public void importSqlFile(MultipartFile file) {

    String fileName = file.getOriginalFilename();

    if(!fileName.contains(".sql")) {
        throw new BusinessException("sql文件导入完整性校验失败");
    }

    String newFilePath = "";
    try {

        byte[] bytes = file.getBytes();

        newFilePath = System.getProperty("user.dir") + filePath + fileName;

        log.info("filePath:{}, fileName:{}", newFilePath, fileName);
        Path path = Paths.get(newFilePath);
        Files.write(path, bytes);

        String aesValue = fileName.replace(".sql", "");
        String md5Value = FileEncryptUtil.aesDecrypt(aesValue);
        log.info("md5Value:{}", md5Value);
        String newMd5 = FileEncryptUtil.getFileMd5(newFilePath);
        log.info("newMd5:{}", newMd5);

        if(md5Value.equals(newMd5)) {
            // 执行sql脚本
            executeSqlScript(newFilePath);
            log.info("sql文件导入成功");
        } else {
            log.info("sql文件导入完整性校验失败");
            throw new BusinessException("sql文件导入完整性校验失败");
        }

    } catch (IOException e) {
        log.error("文件上传失败, IOException:{}", e.getMessage());
    } finally {
        // deleteSqlFile(newFilePath);
    }
}
/**
 * 执行sql脚本
 * @throws SQLException
 */
private void executeSqlScript(String path) throws IOException {
    ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
    // resourceDatabasePopulator.addScript(new ClassPathResource(path));
    resourceDatabasePopulator.addScript(new FileSystemResource(path));
    resourceDatabasePopulator.execute(dataSource);
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果要下载一个百万级别的db.sql文件,可能需要考虑以下几个方面。 首先,考虑到文件大小较大,下载速度可能会受到影响。为了提高下载速度,可以选择一个稳定的网络连接,如使用有线网络而不是Wi-Fi连接。此外,也可以选择一个具有高带宽的互联网服务提供商,以确保能够获得更快的下载速度。 其次,为了确保下载的文件完整性和安全性,可以使用一些 checksum 工具进行校验。通过计算下载文件校验和,并与提供文件的网站或来源的校验和进行比对,可以验证文件完整性。这可以帮助避免下载损坏的文件,或在下载过程中出现错误。 另外,为了更好地管理下载过程,可以使用下载管理器软件。下载管理器可以提供暂停和恢复下载的功能,这对于下载大文件非常有帮助。下载管理器还可以分割下载文件为多个部分,并使用多线程下载,从而提高下载速度。 最后,对于百万级别的db.sql文件,可能需要一定的存储空间来保存文件。确保计算机或设备上的硬盘空间足够大以容纳下载的文件。 总之,为了成功下载一个百万级别的db.sql文件,需要选择稳定的网络连接、使用高带宽的互联网服务提供商、进行文件完整性校验、使用下载管理器来加快下载速度,并确保设备上有足够的存储空间。同时,也需要耐心等待下载完成,因为大文件的下载可能需要一些时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值