返回 Perl 哈希随机化的旧行为

Tza*_*ren 6 perl

我正在尝试将 Perl 从版本 5.16 升级到 5.26,现在哈希值的随机化方式有所不同。有没有办法恢复到 5.16 的旧行为?我对新行为有疑问,因为现有代码和测试依赖于旧的可预测哈希顺序。

zdi*_*dim 12

哈希值的实现在 5.18 中进行了重大修改,请参阅perl5180delta

(问题的原始形式)中没有说明大规模检修的哪一部分是问题所在,但 PERL_PERTURB_KEYS环境变量似乎可以提供帮助

环境PERL_PERTURB_KEYS变量允许控制应用于 和 朋友的随机化级别keys

PERL_PERTURB_KEYS为 0 时,perl 根本不会随机化键顺序。由于插入而发生变化的机会keys与之前的 perls 中相同,基本上仅当存储桶大小发生变化时。
...

更全面的讨论可以在 perlrun 中找到,例如PERL_HASH_SEED

...
如果提供了该选项,但未PERL_PERTURB_KEYS设置,则值“0”意味着PERL_PERTURB_KEYS=0/ PERL_PERTURB_KEYS=NO,任何其他值意味着PERL_PERTURB_KEYS=2/ PERL_PERTURB_KEYS=DETERMINISTICPERL_PERTURB_KEYS有关该模式的重要注意事项,请参阅文档DETERMINISTIC
...

以及紧随其后的PERL_PERTURB_KEYS(我的重点)

...
(自 Perl 5.18.0 起)设置为“ 0”或“ NO”,则对于相同的运行,遍历键将可以在运行之间重复PERL_HASH_SEED。插入散列不会改变顺序,除非在散列中提供更多空间。 与设置结合使用时,PERL_HASH_SEED此模式尽可能接近 5.18 之前的行为。
...

因此,请设置这些环境变量,或者设置PERL_HASH_SEED并相应地设置另一个环境变量,以便重复运行程序以具有相同的顺序等。(请注意,如果将键添加到哈希中,则它可能会在 5.18 之前的代码中随机化同样,在这种情况下,在 5.18+ 中设置这些变量也无济于事。更安全的方法是始终对键进行排序。)

我理解恢复旧行为的论点,但我必须建议阅读完整的文档并考虑安全影响。

另请参阅perlsec 中的算法复杂性攻击


为此需要在 shell 中设置环境变量,例如在 bash 中设置为

export PERL_HASH_SEED=0
Run Code Online (Sandbox Code Playgroud)

这可以在运行程序的终端中完成,也可以在其中完成,这样.bashrc您就不必每次打开终端时都执行此操作。(但是它会影响从该 shell 运行的所有脚本。)或者,可以在启动程序的同一命令行上执行此操作

$ PERL_HASH_SEED=0 program.pl arguments
Run Code Online (Sandbox Code Playgroud)

如果程序是由另一个程序启动的(不是直接在 shell 中),那么您也可以通过父进程中的%ENV哈希来设置它,因为环境是由子进程继承的。然后,组织所有这些的一种独立方法是添加一个简短的包装脚本,其中

$ENV{PERL_HASH_SEED} = 0;

my @cmd = ...

system( @cmd ) == 0 or ...
Run Code Online (Sandbox Code Playgroud)

当然,除了system之外,还有很多方法可以从 Perl 程序中运行命令,从内置qx(“反引号”的运算符形式)和pipeline-open (也可以在 perlipc 中查看)开始,它们允许对命令的输出。或者,更好的是,使用像IPC::System::Simple, Capture::Tiny, IPC::Run(从更简单到更强大)这样的库。

  • @TzachOren 添加了一个建议,也许可以在最后编写一个包装器。还添加了另一条评论——即使在 5.18 之前的 perls 中添加密钥,哈希也可能会随机化 (2认同)

pmq*_*mqs 7

哈希随机化更改的文档位于此处

以下设置将使您获得一致的订单

设置 PERL_HASH_SEED=0(恰好是一个 0)意味着 PERL_PERTURB_KEYS=0(禁用哈希密钥随机化)

您可以按照一致的顺序返回钥匙,我怀疑这不足以满足您的目的。

无论如何,我们用一个小脚本来测试一下

# create a hash
my %hash = map { $_ => $_ } 'a' .. 'e';

printHashKeys(\%hash);
printHashKeys(\%hash);
printHashKeys(\%hash);
printHashKeys(\%hash);


sub printHashKeys
{
    my $h = shift ;
    my %hash = %$h;

    for my $key (keys %hash)
    {
        print "$key  " ;
    }
    print "\n";
}
Run Code Online (Sandbox Code Playgroud)

使用 Perl 5.30.2 运行,我得到这个 - 键顺序每次都不同。

$ perl try.pl 
c  a  e  b  d  
a  c  e  b  d  
d  b  e  a  c  
a  c  e  b  d  
Run Code Online (Sandbox Code Playgroud)

现在PERL_HASH_SEED设置为 0。这次它们的密钥以一致的顺序出现

$ PERL_HASH_SEED=0 perl try.pl 
b  c  d  e  a  
b  c  d  e  a  
b  c  d  e  a  
b  c  d  e  a  
Run Code Online (Sandbox Code Playgroud)