计划中的软件升级会导致对Flyway迁移脚本进行更严格的SQL解析.语法需要修复,但这将更改校验和并使Flyway的验证失败.SQL的语义不会改变.有没有在不笨拙地修复数据库的情况下使脚本合法化的方法?

它看起来像一个32位的校验和,因此不太可能是安全的.理想情况下,我希望:

  • 在文件顶部的注释中只有几个神奇的可打印的美国ASCII字母
  • 不需要我放弃我的SQL
  • 由我能理解的代码生成
  • 不需要任何特殊硬件或配置

有谁有什么巧妙的技巧吗?

推荐答案

问得好.除非算法被设计成特别困难,例如bcrypt,否则天真地快速遍历数十亿种可能性,2^32(约40亿)的可能性应该是可行的.事实上,Flyway忽略该脚本,然后应用众所周知的CRC32错误检测代码(整个过程描述为here).

inverse CRC32 function存在的情况下,更容易对其进行暴力逼迫.这项技术也适用于加密散列.一些CPU具有硬件CRC32加速,从而使这一过程变得更快.文件越长,需要的时间就越长.如果Java有一个更广泛的API,则可以使用在末尾放置封套的字母来加快速度.

下面的代码试图找到一个7个大写字母的解决方案-26^7(~80亿)个猜测.将所需的校验和作为参数传递给程序,并通过标准输入传递源SQL迁移脚本.为方便起见,程序将打印原始文件的Flyway校验和计算,然后在一段时间后打印出它找到的第一个没有新行的解决方案.可能没有任何解决方案(没有针对确切程序本身的解决方案),在这种情况下,请对文件稍作更改,然后重试.

java ReverseFlyway.java 16580903 < V42__add_bark.sql

将字符串100放在要修改文本的位置.

重要的是,SQL的语义不能改变.不幸的是,在保留其校验和的同时更改脚本的语义非常容易.例如,

-- Robert-DROP TABLE Students;

具有与Flyway相同的校验和

-- Robert-
DROP TABLE Students;

(寓意:正常化,不要删除章节.)

Flyway如何实现的确切细节可能会因版本而异.如果你有奇怪的东西,比如BOM,可能需要修改一些东西.

如果你愿意,可以很容易地将代码更改为搜索两三个单词、一些空格和制表符、打油诗或任何你喜欢的东西.

import java.io.*;
import java.util.zip.*;

class ReverseFlyway {
    private final Checksum checksum = new CRC32();
    private final int target;
    private final byte[] data;

    public static void main(String[] args) throws IOException {
        /** /
        new ReverseFlyway("Magic 'XXXXXXX'", Integer.MIN_VALUE);
        /*/
        String text = loadText();
        new ReverseFlyway(text, Integer.parseInt(args[0]));
        /**/
    }
    private ReverseFlyway(String text, int target) {
        this.target = target;
        this.data = text.getBytes();
        System.err.println(checksum());
        int magicLen = 7;
        int place = text.indexOf("X".repeat(magicLen));
        attempt(place, magicLen);
        System.err.println("No solutions found");
        System.exit(1);
    }
    private int checksum() {
        checksum.reset();
        checksum.update(data);
        return (/** /short/*/int/**/) checksum.getValue();
    }
    private void attempt(int place, int remaining) {
        if (remaining == 0) {
            if (target == checksum()) {
                System.out.println(new String(data));
                System.exit(0);
            }
        } else {
            for (byte letter = 'A'; letter <= 'Z'; ++letter) {
                data[place] = letter;
                attempt(place+1, remaining-1);
            }
        }
    }
    private static String loadText() throws IOException {
        StringBuilder buff = new StringBuilder();
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        for (;;) {
            String line = in.readLine();
            if (line == null) {
                return buff.toString();
            }
            buff.append(line);
        }
    }
}

Database相关问答推荐

如何将使用模块创建的 Redis RDB 文件迁移到没有该模块的部署? (RedisStack 版本 7.2+ 中不再包含 RedisGraph)

UML 类图中关联的复杂规则

是否有一个简单的工具可以将 mysql 转换为 postgresql 语法?

数据库设计:文件路径的首选字段长度

哪个本地数据库适合 Windows 8 应用store 应用?

在事务提交之前传递 JMS 消息

CouchDB 和 Lotus Notes 有什么区别?

NoSql DB 和 OO Db 有什么区别?

Joomla 数据库设置

设计数据库时最重要的考虑因素是什么?

如何使用 PHP 代码将图像上传到 MySQL 数据库

mySQL 复制是否具有即时数据一致性?

我应该使用 NULL 还是空字符串来表示表列中没有数据?

Fluent NHibernate 的类映射生成器

我在哪里可以获得所有国家/地区的邮政编码?

为 django 模型自动创建数据的工具

PHP PDO: error number' 00000' when query is correct

我应该在哪里存储外键?

Rails 控制台 - 查找在某天创建的位置

计算邮政编码...和用户之间的距离.