基于 Bash 中的任意用户数据的随机但可预测的 cronjob 计划

问题描述 投票:0回答:1

我正在尝试根据任意用户提供的数据为每月和每日的 cronjob 构建一个随机但可预测的 cronjob 计划。每日和每月的 cronjobs 应在不同的时间运行。

目标是,如果用户重复提供相同的输入,则 cronjobs 将始终在完全相同的时间运行。哪些数据产生什么样的时间表应该“感觉”是随机的,但不一定是密码随机的。但是,如果用户只是稍微更改输入,则 cronjobs 应该在完全不同(即不相似)的时间运行。如果用户随后将输入更改回原始时间,则 cronjobs 应在与之前完全相同的时间运行。

无法持久存储生成的 cronjob 计划,即它必须严格根据用户数据构建。用户数据是任意的,即我们不能期望它具有特定的形式或长度 - 它可以是空字符串,也可以是具有 1 GB 随机数据的字符串。

应该使用仅安装 Busybox 工具的 Bash 构建 cronjob 计划。


我的想法如下:

  1. 每月 cronjob 的时间表可以用代表该月第 n 分钟的整数来表示。因此,n=123 代表该月的第 123 分钟,或该月第一天的 2:03(cronjob 时间表

    3 2 1 * *
    )。相比之下,n=12345 表示该月的第 12,345 分钟,或该月的第 9 天的 13:45(cronjob 时间表
    45 13 9 * *
    )。由于 cronjob 不会在 2 月份运行,因此我们最多接受第 28 天的 23:59。因此我们需要一个 0 到 40319 之间的整数(= 28 天 * 24 小时 * 60 分钟 - 1)。

    为此,我们可以创建一个

    __crontab_monthly()
    函数,接受任意整数。由于输入的整数不一定在预期范围内,因此我们首先对 40320 进行模运算。然后进行模运算和除法运算,得到各自的日、小时和分钟。最后我们连接 cronjob 时间表。

    同样的原理也适用于日常 cronjob,只是限制为 0 到 1439 之间的整数(= 24 小时 * 60 分钟 - 1)。我们可以为此创建一个类似的

    __crontab_daily()
    函数。

    我还不知道如何确保每月和每日的 cronjobs 在不同的时间运行 - 除了通过一些神奇的值来抵消该值......有什么想法吗?

  2. 但是,要实现此目的,我们首先需要从用户数据中计算一个随机但持久的整数,以便将它们输入到我们的

    __crontab_{monthly,daily}()
    函数中。由于我们必须接受任意用户数据,所以我的想法是首先计算用户数据的 md5 哈希值。这确保了结果被认为是随机的(输入中的微小变化会产生完全不同的结果),但它是可预测的,并且对于相同的数据会产生一致的结果。

    md5 哈希可能是一个很好的起点,因为 md5 哈希只是 128 位数字的十六进制字符串表示形式。但是,我们无法在 Bash 中使用 128 位数字进行数学运算。因此,我产生了将两个唯一的 128 位哈希值统一合并为同一个 64 位整数的想法。我的方法是首先将哈希拆分为两个 64 位切片,执行 2^32 的模运算将每个切片压缩为 32 位,然后连接两个二进制数。这应该会产生一个 64 位有符号整数,然后可以将其输入到

    __crontab_{monthly,daily}()
    函数中。


到目前为止我想出了以下解决方案。用户输入存储在

$USER_DATA
变量中。我相当确定
__crontab_{monthly,daily}()
函数做了它们应该做的事情,但是
__crontab_reference()
函数更棘手......我只是不确定计算是否正确,二进制不是“我的事” ”。有人可以帮忙吗?

__crontab_reference() {
    local HASH="$(md5sum <<< "$1" | cut -d ' ' -f 1)"
    echo $(( 0x$(printf '%x\n' $(( 0x${HASH:0:16} % 2147483648 )))$(printf '%x\n' $(( 0x${HASH:16:16} % 2147483648 ))) ))
}

__crontab_daily() {
    local NUMBER=$(( "$1" % 1440 ))
    NUMBER=$(( NUMBER * ((NUMBER>0) - (NUMBER<0)) ))

    local HOUR=$(( NUMBER / 60 ))
    local MINUTE=$(( NUMBER % 60 ))
    echo "$MINUTE $HOUR * * *"
}

__crontab_monthly() {
    local NUMBER=$(( "$1" % 40320 ))
    NUMBER=$(( NUMBER * ((NUMBER>0) - (NUMBER<0)) ))

    local DAY=$(( NUMBER / 1440 + 1 ))
    local HOUR=$(( NUMBER % 1440 / 60 ))
    local MINUTE=$(( NUMBER % 1440 % 60 ))
    echo "$MINUTE $HOUR $DAY * *"
}

CRONTAB_REFERENCE="$(__crontab_reference "$USER_DATA")"
echo "Daily cronjob schedule: $(__crontab_daily "$CRONTAB_REFERENCE")"
echo "Monthly cronjob schedule: $(__crontab_monthly "$CRONTAB_REFERENCE")"

对于

USER_DATA=""
,得出:

Daily cronjob schedule: 36 1 * * *
Monthly cronjob schedule: 36 1 20 * *

最后但并非最不重要的一点是,有人对替代方法有想法(请包括 PoC 代码)吗?

bash random cron user-input prediction
1个回答
0
投票

bc
可以直接对十六进制进行操作。

使用评论中pmf的想法:

hash=$(md5sum <<<"$data")

read md mh mm dh dm <<<$( echo $(
    echo "
        ibase=16; s=${hash^^}0; ibase=A
        k=2^8
              md= s%28+1
        s/=k; mh= s%24
        s/=k; mm= s%60
        s/=k; dh= (mh+(s%23)+1)%24
        s/=k; dm= s%60

        md;mh;mm; dh;dm
    " | bc
))

为了确保 mh != dh,我们将其偏移一个非零量。

bc
想要大写的十六进制。如果所使用的 shell 没有
tr
参数扩展,则可以使用
${var^^}
进行转换。

© www.soinside.com 2019 - 2024. All rights reserved.