这是 perlsec 命令,可以使用我们的多个免费在线工作站之一在 OnWorks 免费托管服务提供商中运行,例如 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器
程序:
您的姓名
perlsec - Perl 安全性
商品描述
Perl 旨在使安全编程变得容易,即使在额外运行时
权限,如 setuid 或 setgid 程序。 与大多数命令行 shell 不同,它们是
基于脚本每一行的多次替换,Perl 使用了一个更
具有较少隐藏障碍的传统评估方案。 此外,由于
语言具有更多的内置功能,它可以更少地依赖外部(并且可能
不可信)程序来实现其目的。
保安 脆弱性 联系我们 相关信息
如果您认为您在 Perl 中发现了安全漏洞,请发送电子邮件至
[电子邮件保护] 与细节。 这指向一个封闭的订阅,
未归档的邮件列表。 请仅将此地址用于 Perl 中的安全问题
核心,不适用于独立分布在 CPAN 上的模块。
保安 机制 AND 疑虑
污点 模式
Perl 自动启用一组特殊的安全检查,称为 污点 模式,当它
检测其程序以不同的真实有效用户或组 ID 运行。 这
Unix 权限中的 setuid 位模式为 04000,setgid 位模式为 02000; 一个或两个
可以设置。 您还可以通过使用显式启用污点模式 -T 命令行标志。
这个标志是 非常 建议用于服务器程序和代表其运行的任何程序
其他人,例如 CGI 脚本。 一旦污点模式开启,它会在接下来的时间里开启
你的脚本。
在这种模式下,Perl 采取特殊的预防措施,称为 污点 检查 为了防止两者
明显而微妙的陷阱。 其中一些检查相当简单,例如验证
其他人无法写入路径目录; 细心的程序员一直使用
像这样的检查。 然而,其他检查最好由语言本身支持,并且
尤其是这些检查有助于使 set-id Perl 程序更安全
比相应的 C 程序。
您不得使用从程序外部派生的数据来影响外部的其他内容
你的程序——至少,不是偶然的。 所有命令行参数,环境
变量、区域设置信息(请参阅 perllocale)、某些系统调用的结果
("readdir()", "readlink()", "shmread()"的变量, 返回的消息
“msgrcv()”、“getpwxxx()”调用返回的密码、gcos 和 shell 字段),以及
所有文件输入都标记为“受污染”。 受污染的数据不得直接使用或
在任何调用子 shell 的命令中,或者在任何修改
文件、目录或进程, - 这些因素包括原料奶的可用性以及达到必要粉末质量水平所需的工艺。 以下 例外:
· "print" 和 "syswrite" 的参数是 而不去 检查污染。
· 符号方法
$obj->$method(@args);
和符号子引用
&{$foo}(@args);
$foo->(@args);
不检查污染。 这需要格外小心,除非你想要
外部数据来影响您的控制流。 除非你仔细限制这些
符号值是,人们可以调用函数 学校以外 你的 Perl 代码,比如
POSIX::system,在这种情况下,它们能够运行任意外部代码。
· 哈希键是 决不要 被污染了。
出于效率原因,Perl 对数据是否被污染采取保守的观点。 如果
表达式包含被污染的数据,任何子表达式都可能被认为是被污染的,即使
子表达式的值本身不受污染数据的影响。
因为污点与每个标量值相关联,所以数组的某些元素或
散列可以被污染,而其他人则不会。 散列的键是 决不要 被污染了。
例如:
$arg = 移位; # $arg 被污染
$hid = $arg 。 '酒吧'; # $hid 也被污染
$line = <>; # 污染
$行 = ; # 也被污染了
打开 FOO, "/home/me/bar" or die $!;
$行 = ; # 仍然被污染
$path = $ENV{'PATH'}; # 污染,但见下文
$data = 'abc'; # 没有污染
系统“回声$arg”; # 不安全
系统 ”/斌/回声", $arg; # 认为不安全
#(Perl 不知道 /斌/回声)
系统 "echo $hid"; # 不安全
系统“回声$数据”; # 不安全,直到 PATH 设置
$path = $ENV{'PATH'}; # $path 现在被污染了
$ENV{'PATH'} = '/箱:/ usr / bin';
删除@ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
$path = $ENV{'PATH'}; # $path 现在没有被污染
系统“回声$数据”; # 现在安全了!
打开(FOO,“< $arg”); # OK - 只读文件
打开(FOO, "> $arg"); # 不行 - 试着写
打开(FOO,“回声 $arg|”); # 不好
打开(FOO,“-|”)
或 exec 'echo', $arg; # 也不行
$shout = `echo $arg`; # 不安全,$shout 现在被污染了
取消链接 $data, $arg; # 不安全
umask $arg; # 不安全
执行“回声$arg”; # 不安全
执行“回声”,$arg; # 不安全
exec "sh", '-c', $arg; #非常没有安全感!
@files = <*.c>; # 不安全(使用 readdir() 或类似的)
@files = glob('*.c'); # 不安全(使用 readdir() 或类似的)
# 在任何一种情况下,glob 的结果都被污染了,因为列表
# 文件名来自程序外部。
$bad = ($arg, 23); # $bad 会被污染
$arg,`真`; # 不安全(虽然不是真的)
如果你尝试做一些不安全的事情,你会得到一个致命的错误,比如
“不安全的依赖”或“不安全的 $ENV{PATH}”。
“一个被污染的值污染整个表达式”原则的例外是
三元条件运算符“?:”。 由于带有三元条件的代码
$result = $tainted_value ? “未受污染”:“也未受污染”;
有效地
如果( $tainted_value ){
$result = "未受污染";
} {
$result = "也未受污染";
}
$result 被污染是没有意义的。
洗钱 和 检测 被污染 时间
测试一个变量是否包含被污染的数据,以及它的使用会因此触发一个
“不安全的依赖”消息,可以使用Scalar::Util的“tainted()”函数
模块,在您附近的 CPAN 镜像中可用,并包含在 Perl 中
发布 5.8.0。 或者您可以使用以下“is_tainted()”函数。
子 is_tainted {
本地$@; # 不要污染调用者的价值。
返回 ! eval { eval("#" .substr(join("", @_), 0, 0)); 1 };
}
这个函数利用了一个事实,即受污染的数据存在于一个
expression 使整个表达式被污染。 对每个人来说都是低效的
运算符来测试每个参数的污染性。 相反,稍微更高效和
使用保守的方法,如果在同一范围内访问了任何受污染的值
表达式,整个表达式被认为是被污染的。
但是对污点的测试只能让您到此为止。 有时你只需要清除你的
数据的污染。 通过将值用作散列中的键,值可能不会受到污染; 除此以外
绕过污染机制的唯一方法是引用常规的子模式
表达式匹配。 Perl 假定如果您在一个子字符串中使用 $1、$2 等引用
非污染模式,即您在编写该模式时就知道自己在做什么。 那
意味着使用一点思想——不要盲目地去污染任何东西,否则你会打败
整个机制。 最好验证变量是否只有好的字符(对于
“好”的某些值),而不是检查它是否有任何坏字符。 那是
因为很容易错过你从未想过的坏角色。
这是一个测试,以确保数据只包含“单词”字符
(字母、数字和下划线)、连字符、at 符号或点。
如果 ($data =~ /^([-\@\w.]+)$/) {
$数据 = $1; # $data 现在未受污染
} {
die "'$data' 中的错误数据"; # 在某处记录这个
}
这是相当安全的,因为 "/\w+/" 通常不匹配 shell 元字符,也不匹配
点、破折号或 at 对 shell 有特殊意义。 用于 ”/.+/" 会有
理论上是不安全的,因为它让一切都通过,但 Perl 不检查
那。 教训是,在清除污点时,您必须格外小心
模式。 使用正则表达式清洗数据是 仅由 去污机制
脏数据,除非您使用下面详述的策略来分叉较小的孩子
特权。
如果“使用语言环境”有效,该示例不会清除 $data,因为字符
由“\w”匹配的语言环境决定。 Perl 认为语言环境定义是
不可信,因为它们包含来自程序外部的数据。 如果你正在写一个
区域设置感知程序,并希望使用包含“\w”的正则表达式清洗数据,
将“no locale”放在同一块中的表达式之前。 参见 perllocale 中的“安全”
以供进一步讨论和示例。
交换机 On 这些因素包括原料奶的可用性以及达到必要粉末质量水平所需的工艺。 “#!” Line
当您使脚本可执行时,为了使其可用作命令,系统
将从脚本的 #! 线。 Perl 检查任何命令行
提供给 setuid(或 setgid)脚本的开关实际上与 #! 线。
一些 Unix 和类 Unix 环境对 #! 线,所以你可以
在这样的系统下,需要使用“-wU”之类的东西而不是“-w -U”。 (这个问题
应该只出现在支持 #! 和 setuid 或 setgid
脚本。)
污点 模式 和 @INC
当污点模式(“-T”)生效时,“.” 目录从@INC 中删除,并且
Perl 会忽略环境变量“PERL5LIB”和“PERLLIB”。 还是可以调整的
@INC 从程序外部使用“-I”命令行选项,如中所述
运行。 这两个环境变量被忽略,因为它们被遮挡了,一个用户
运行程序可能不知道它们已设置,而“-I”选项显然是
可见,因此被允许。
另一种在不修改程序的情况下修改@INC 的方法是使用“lib”编译指示,
例如:
perl -Mlib=/foo 程序
使用“-Mlib=/foo”而不是“-I/foo”的好处是前者会自动
删除任何重复的目录,而后者不会。
注意如果在@INC中加入了污染字符串,会报如下问题:
使用 -T 开关运行时 require 中的不安全依赖项
清洁 Up 您的 途径
对于“不安全的 $ENV{PATH}”消息,您需要将 $ENV{'PATH'} 设置为已知值,并且
路径中的每个目录都必须是绝对的,并且不能被其所有者以外的其他人写入,并且
团体。 即使您的可执行文件的路径名是
完全合格。 这是 而不去 生成是因为您没有提供完整的路径
程序; 相反,它是因为您从未设置 PATH 环境变量而生成的,或者
你没有将它设置为安全的东西。 因为 Perl 不能保证
有问题的可执行文件本身不会转身执行其他程序
这取决于您的 PATH,它确保您设置了 PATH。
PATH 不是唯一可能导致问题的环境变量。 因为有些
shell 可以使用变量 IFS、CDPATH、ENV 和 BASH_ENV,Perl 检查这些变量
启动子进程时为空或未受污染。 您可能希望添加类似
这到您的 setid 和污点检查脚本。
删除@ENV{qw(IFS CDPATH ENV BASH_ENV)}; # 使 %ENV 更安全
也有可能在其他不关心它们是否正常的操作中遇到麻烦
使用污染值。 在处理任何用户时明智地使用文件测试 -
提供的文件名。 如果可能,请打开等 after 正确丢弃任何特殊
用户(或组!)权限。 Perl 不会阻止您打开受污染的文件名
阅读,所以要小心你打印出来的东西。 污染机制旨在防止
愚蠢的错误,不是消除思考的需要。
当您传递“system”和“exec”时,Perl 不会调用 shell 来扩展通配符
显式参数列表而不是带有可能的 shell 通配符的字符串。
不幸的是,“open”、“glob”和反引号函数没有提供这样的替代
调用约定,因此需要更多的诡计。
Perl 提供了一种从 setuid 或 setgid 打开文件或管道的相当安全的方法
程序:只需创建一个特权降低的子进程,该子进程为其做肮脏的工作
你。 首先,使用连接父级和
管子旁的孩子。 现在子进程重置它的 ID 集和任何其他每个进程的属性,
像环境变量,umasks,当前工作目录,回到原来的或
已知的安全值。 然后是不再具有任何特殊权限的子进程,
执行“打开”或其他系统调用。 最后,孩子将它设法传递的数据传递给
访问回父。 因为文件或管道是在运行时在子进程中打开的
在比父母更少的特权下,它不容易被欺骗去做某事
不应该。
这是一种合理安全地进行反引号的方法。 注意“exec”是如何不被调用的
外壳可以展开的字符串。 这是迄今为止调用某些东西的最佳方式
可能会遇到 shell 转义:根本不要调用 shell。
使用英语;
死“不能分叉:$!” 除非已定义($pid = open(KID, "-|"));
if ($pid) { # 父级
尽管 ( ){
# 做点什么
}
关闭 KID;
} {
我的@temp = ($EUID, $EGID);
我的 $orig_uid = $UID;
我的 $orig_gid = $GID;
$EUID = $UID;
$EGID = $GID;
# 删除权限
$UID = $orig_uid;
$GID = $orig_gid;
# 确保 privs 真的消失了
($EUID, $EGID) = @temp;
死“不能放弃特权”
除非 $UID == $EUID && $GID eq $EGID;
$ENV{PATH} = "/箱:/ usr / bin"; # 最小路径。
# 考虑更多地对环境进行消毒。
exec 'myprog', 'arg1', 'arg2'
或者死“不能执行 myprog: $!”;
}
类似的策略适用于通过“glob”进行通配符扩展,尽管您可以使用
“readdir”代替。
尽管您相信自己没有编写过污点检查,但它最有用
计划赠送农场,你不一定相信那些最终不使用它的人
试图欺骗它做坏事。 这是一种安全检查
对 set-id 程序和代表其他人启动的程序很有用,比如 CGI
程式。
然而,这与甚至不相信代码的作者不去尝试是完全不同的
做坏事。 当有人给你一个程序时,这就是需要的信任
你以前从未见过,然后说,“来,运行这个。” 为了这种安全,你可能
想要查看包含在 Perl 发行版中的标准的 Safe 模块。 这个
模块允许程序员设置所有系统操作的特殊隔间
被困住,命名空间访问受到严格控制。 不应该考虑安全
但是防弹:它不会阻止外部代码设置无限循环,
分配 GB 内存,甚至滥用 perl 漏洞使主机解释器崩溃
或以不可预测的方式行事。 无论如何最好完全避免,如果你是
真的很担心安全。
安全性 错误
除了由于授予系统特权而产生的明显问题之外
像脚本一样灵活,在许多版本的 Unix 上,set-id 脚本本质上是不安全的
从一开始就对。 问题是内核中的竞争条件。 时间之间
内核打开文件以查看要运行的解释器以及(now-set-id)
解释器转身并重新打开文件以解释它,有问题的文件可能
已更改,尤其是当您的系统上有符号链接时。
幸运的是,有时可以禁用此内核“功能”。 不幸的是,有
禁用它的两种方法。 系统可以简单地取缔具有任何 set-id 位集的脚本,
这没有多大帮助。 或者,它可以简单地忽略脚本上的 set-id 位。
但是,如果内核 set-id 脚本功能没有被禁用,Perl 会大声抱怨
您的 set-id 脚本不安全。 您需要禁用内核设置 ID
脚本功能,或者在脚本周围放置一个 C 包装器。 AC 包装器只是一个编译
除了调用 Perl 程序之外什么都不做的程序。 编译好的程序不是
受到困扰 set-id 脚本的内核错误的影响。 这是一个简单的包装器,写成
在C中:
#define REAL_PATH "/path/to/script"
主要(交流,AV)
字符 **av;
{
execv(REAL_PATH, av);
}
将此包装器编译为二进制可执行文件,然后制作 it 而不是你的脚本
setuid 或 setgid。
近年来,供应商已经开始提供没有这种固有安全漏洞的系统。
在这样的系统上,当内核通过 set-id 脚本的名称打开到
解释器,而不是使用受干预的路径名,而是通过
/开发/fd/3. 这是一个已经在脚本上打开的特殊文件,因此不能有
恶意脚本利用的竞争条件。 在这些系统上,应该编译 Perl
使用“-DSETUID_SCRIPTS_ARE_SECURE_NOW”。 这 配置 构建 Perl 的程序试图
自己解决这个问题,所以你永远不必自己指定。 最多
SysVr4 和 BSD 4.4 的现代版本使用这种方法来避免内核竞争
状态。
提供保护 您的 计划部
有多种方法可以隐藏 Perl 程序的源代码,级别各不相同
的“安全”。
然而,首先,你 不能 取消读取权限,因为源代码必须
可读以便编译和解释。 (这并不意味着 CGI
不过,网络上的人可以阅读脚本的源代码。)所以你必须离开
社交友好 0755 级别的权限。 这让您本地系统上的人
只看到你的来源。
有些人错误地认为这是一个安全问题。 如果你的程序不安全
事情,并依赖于不知道如何利用这些不安全感的人,这不是
安全的。 人们通常可以确定不安全的事物并利用
他们不查看源。 默默无闻的安全,隐藏你的名字
错误而不是修复它们,确实没有什么安全性。
您可以尝试通过源过滤器使用加密(来自 CPAN 的 Filter::*,或
Filter::Util::Call 和 Filter::Simple 自 Perl 5.8 起)。 但饼干可能能够
解密它。 您可以尝试使用下面描述的字节码编译器和解释器,但是
破解者也许能够反编译它。 您可以尝试使用本机代码编译器
下面描述,但饼干可能能够拆卸它。 这些姿势不同程度
对于想要获取您的代码的人来说很困难,但没有人可以明确地隐藏它
(这适用于每种语言,而不仅仅是 Perl)。
如果您担心人们从您的代码中获利,那么底线是
只有限制性许可证才能为您提供法律保障。 许可您的软件和
用诸如“这是未发布的专有软件
XYZ 公司。您对它的访问并未授予您使用它的许可,等等。”
应该会见律师,以确保您的执照上的措辞在法庭上站得住脚。
统一
Unicode 是一种新的复杂技术,人们很容易忽视某些安全性
陷阱。 查看 perluniintro 的概述和 perlunicode 的详细信息,以及“安全
perlunicode 中 Unicode 的含义,特别是安全含义。
算法 复杂 攻击
Perl 实现中使用的某些内部算法可以通过选择攻击
仔细输入以消耗大量时间或空间或两者兼而有之。 这个可以
导致所谓的 拒绝 of 服务 (DoS) 攻击。
· 散列算法——众所周知,Perl 中使用的散列算法是
容易受到对其哈希函数的碰撞攻击。 此类攻击涉及
构造一组碰撞到同一个桶中的键产生低效
行为。 此类攻击通常依赖于发现所用哈希函数的种子
将键映射到存储桶。 然后使用该种子来暴力破解密钥集,该密钥集可以
用于发起拒绝服务攻击。 在 Perl 5.8.1 中引入了更改
强化 Perl 以应对此类攻击,后来在 Perl 5.18.0 中,这些功能被
添加了增强和额外的保护。
在撰写本文时,Perl 5.18.0 被认为是针对
对其哈希实现的算法复杂性攻击。 这主要归功于
以下措施可减轻攻击:
哈希种子随机化
为了让不知道是什么种子生成攻击密钥集
因为,这个种子在进程开始时随机初始化。 这可能会被覆盖
通过使用 PERL_HASH_SEED 环境变量,请参阅 perlrun 中的“PERL_HASH_SEED”。
此环境变量控制项目的实际存储方式,而不是它们的存储方式
通过“键”、“值”和“每个”呈现。
哈希遍历随机化
与散列函数中使用的种子无关,“键”、“值”和
“每个”以每个散列的随机顺序返回项目。 通过插入修改哈希
将更改该哈希的迭代顺序。 这种行为可以被覆盖
使用 Hash::Util 中的“hash_traversal_mask()”或使用 PERL_PERTURB_KEYS
环境变量,请参阅 perlrun 中的“PERL_PERTURB_KEYS”。 注意这个功能
控制键的“可见”顺序,而不是它们存储的实际顺序
英寸
桶序扰动
当项目碰撞到给定的哈希桶时,它们存储在链中的顺序
在 Perl 5.18 中不再可预测。 这是为了让它更难
观察碰撞。 此行为可以通过使用
PERL_PERTURB_KEYS 环境变量,参见 perlrun 中的“PERL_PERTURB_KEYS”。
新的默认哈希函数
默认哈希函数已被修改,目的是让它更难
推断哈希种子。
替代哈希函数
源代码包括多种哈希算法可供选择。 虽然我们
相信默认的 perl 哈希对攻击是健壮的,我们已经包含了哈希
将 Siphash 用作后备选项。 Perl 5.18.0 发布时
Siphash 被认为具有加密强度。 这不是默认值,因为
它比默认哈希慢得多。
如果不编译特殊的 Perl,就无法获得完全相同的行为
Perl 5.18.0 之前的任何版本。 最接近的是通过设置
PERL_PERTURB_KEYS 为 0 并将 PERL_HASH_SEED 设置为已知值。 我们不
由于上述安全考虑,建议将这些设置用于生产用途。
Perl的 具有 决不要 保证 任何 订购 of 这些因素包括原料奶的可用性以及达到必要粉末质量水平所需的工艺。 哈希 键,并且订单已经
在 Perl 5 的生命周期中多次更改。此外,散列键的顺序
一直并将继续受到插入顺序和历史记录的影响
在其生命周期内对哈希所做的更改。
还要注意,虽然散列元素的顺序可能是随机的,但这种“伪-
订购”应该 而不去 用于随机排列列表之类的应用程序(使用
"List::Util::shuffle()" 参见 List::Util,自 Perl 以来的标准核心模块
5.8.0; 或 CPAN 模块“Algorithm::Numerical::Shuffle”),或用于生成
排列(例如使用 CPAN 模块“Algorithm::Permute”或
"Algorithm::FastPermute"),或用于任何加密应用程序。
绑定哈希可能有自己的排序和算法复杂性攻击。
· 正则表达式 - Perl 的正则表达式引擎被称为 NFA (Non-
确定性有限自动机),这意味着它可以宁可
如果正则表达式可能会很容易消耗大量的时间和空间
以多种方式匹配。 仔细制作正则表达式可以帮助但相当
通常真的没有多少人可以做(“掌握正则表达式”一书是
要求阅读,见 perlfaq2)。 Perl 显示空间不足
内存不足。
· Sorting - Perls 5.8.0 之前使用的快速排序算法来实现 种类()
函数很容易被欺骗到行为不端,从而消耗大量时间。
从 Perl 5.8.0 开始,默认使用不同的排序算法合并排序。
Mergesort 不能对任何输入行为不当。
看到http://www.cs.rice.edu/~scrosby/hash/> 了解更多信息,以及任何计算机科学
算法复杂性的教科书。
使用 onworks.net 服务在线使用 perlsec