Chinaunix

标题: 关于Perl的tainted模式 [打印本页]

作者: 兰花仙子    时间: 2005-11-16 21:57
标题: 关于Perl的tainted模式
前几天跟Apile谈起了cgi的安全问题,并谈到了tainted模式。回去后偶查了一些关于tainted的资料,并看到一个如何判断某个变量是否tainted的函数如下:

sub is_tainted{
   my $var=shift;
   my $blank=substr($var,0,0);
   return not eval {eval "1 || $blank" || 1};
}


这个函数让偶郁闷了半天,于是在mailing list上发贴求教。perlmonk的Jeff很热心的回答了偶的问题,引用如下:

If a variable is tainted, then any substring of that variable is also
tainted.  In addition, it is illegal to eval() any string that is tainted.
The inclusion of a tainted string inside another string makes that whole
string tainted.

Therefore:  if $var is tainted, the $blank will also be tainted (even
though it's a substring of zero characters).  If $blank is then tainted,
then the code

  eval { eval "1 || $blank" || 1 }

will return false (since the eval { ... } catches fatal errors, and the
eval "1 || $blank" raises a fatal error because $blank is tainted), and
therefore,

  return not eval { eval "1 || $blank" || 1 };

returns true, stating that $var is indeed tainted.  If $var wasn't
tainted, then

  eval "1 || $blank" || 1

returns 1, and

  return not eval { 1 }

returns false, stating that $var wasn't tainted.

*whew*

Frankly, I find the 'eval "1 || $blank" || 1' silly, since the whole
reason the '... || 1' is needed is since $blank is a blank string and the
code '1 || ' is invalid Perl.  Long story short, I'd have written:

  sub is_tainted {
    return not eval { eval 1 . substr($_[0], 0, 0) };
  }

It's much more concise.  If $_[0] isn't tainted, then

  not eval { eval 1 . substr($_[0], 0, 0) }
  ->
  not eval { eval 1 }
  ->
  not eval { 1 }
  ->
  not 1
  ->
  false

whereas if $_[1] is tainted, then the eval { ... } returns false since a
fatal error is raised because

  eval 1 . substr($_[0], 0, 0)

is illegal if $_[0] is tainted.



偶仍有所不明,于是再问Jeff:

1)eval "1 || $blank";
When $blank is tainted,the $blank is false,but "1 || $blank" should return
true,because "true || false" will return true always.Isn't it?

2)why to call eval 2 times here?


Jeff回答:

If $var is tainted, then even though $blank is an empty string, it's
tainted also.  That means the string "1 || $blank" (which is really just
"1 || " (which if it WERE eval'd would be a syntax error!)) is tainted by
association with $blank.  And eval($some_tainted_string) is a fatal error.
If we didn't have the eval { ... } around the eval($tainted_string), the
Perl application would die with the "Insecure dependecy..." error message.
The outer eval { ... } catches this error.

So, when $blank is tainted, the eval "1 || $blank" doesn't even get as far
as executing the code inside it.  It realizes it's ABOUT to eval() tainted
code, and dies; and that's what the outer eval { ... } is there for.


终于弄明朗了这个哈,大家也可看一下。
作者: apile    时间: 2005-11-17 08:45
谢谢仙子..
虽然大概知道tainted mode是怎麽回事...也知道他很复杂...
曾经我也在CGI里面打开-T..不过一堆fatal error..让我决定把他关了...

不过用这个subroutine倒不失为一个判断tainted variable..好方法..

好久没看perl的书了......
作者: 兰花仙子    时间: 2005-11-17 09:02
原帖由 apile 于 2005-11-17 08:45 发表
谢谢仙子..
虽然大概知道tainted mode是怎麽回事...也知道他很复杂...
曾经我也在CGI里面打开-T..不过一堆fatal error..让我决定把他关了...

不过用这个subroutine倒不失为一个判断tainted variable..好方法 ...


是哦,偶也是因为debug麻烦,一直不用-T的,以后为secure起见,也许该试着打开它,
作者: 怒剑狂啸    时间: 2005-11-17 09:43
Therefore:  if $var is tainted, the $blank will also be tainted (even
though it's a substring of zero characters).  If $blank is then tainted,
then the code


什么样的数据是被污染的?可否举例说明一下,
  1. substr($_[0], 0, 0)
复制代码

这个到底返回什么,以至于eval之后竟会有语法错误?
不解中……
作者: 兰花仙子    时间: 2005-11-17 09:54
原帖由 怒剑狂啸 于 2005-11-17 09:43 发表


什么样的数据是被污染的?可否举例说明一下,
  1. substr($_[0], 0, 0)
复制代码

这个到底返回什么,以至于eval之后竟会有语法错误?
不解中……


什么样的数据是被污染的?

任何从脚本外部接受过来的数据,都是tainted的。例如从STDIN,Socket,file handle接受的数据,都被称为tainted的。而且tainted属性是可传递的,也就是说,某个变量tainted了,那么由该变量计算或派生的其他变量也是tainted的。



substr($_[0], 0, 0)

什么也不返回哦,它是个0长度的string.这里返回什么没有意义,因为它是tainted变量的子串,所以它本质上也是tainted的。至于语法错误,是因为在-T模式下,eval接受到任何tainted变量,都会引起fatal error而引起die发生。
作者: apile    时间: 2005-11-17 11:04
原帖由 怒剑狂啸 于 2005-11-17 09:43 发表


什么样的数据是被污染的?可否举例说明一下,
  1. substr($_[0], 0, 0)
复制代码

这个到底返回什么,以至于eval之后竟会有语法错误?
不解中……

tainted mode下,数据要让他没被污染,要用
$untainted_variable = $var =~/(w+)/;
也可以
$untainted_variable = $var =~/(.*)/;
只是这样子就失去-T的本意了...

tainted 简单的说就是不是代码内给值的...
而是从其他地方透过I/O进来给值的都算tainted...
作者: 怒剑狂啸    时间: 2005-11-17 11:07
因为不怎么用perl写cgi,以前看到perl安全这一节就草草翻翻,一直觉得变量的污染模式就是指变量中含有不安全的代码,犯了一个常识性的错误,呵呵,谢谢仙子!
作者: 怒剑狂啸    时间: 2005-11-17 11:19

  1. $untainted_variable = $var =~/(.*)/;
复制代码

apile兄,这样做有什么作用么?难道是去除$var中的换行符以及换行符后的内容么?
作者: apile    时间: 2005-11-17 11:27
其实tainted就是强迫你检查所有的variable..只要不是自己产生的...
一定要透过regular expression去产生untainted variable..
上面.*其实只是在骗-T...我有用regular expression..其实一点更动也没有...
上面.*可以改成..例如叁数一定要是数字...\d+....
可以有效解决sql injection或system碰到 ; 的问题....
\n
作者: 怒剑狂啸    时间: 2005-11-17 12:02
哦,其实就是给programmer一个提示,要check一下,确保外部输入没有不安全的代码,改天再好好看看,谢谢apile兄!
作者: 兰花仙子    时间: 2005-11-17 12:18
两位大虾的讨论也让偶有所收获哦。

Apile的这句:
$untainted_variable = $var =~/(w+)/;
按照偶的理解,是否该这么写啊:
($untainted_variable) = $var =~/(w+)/; # 强迫"="赋值位于列表上下文
或者:
($untainted_variable = $var) =~/(w+)/; # 强迫先给$untainted_variable赋值,再匹配

Apile的原写法,应该是先匹配,再赋值给$untainted_variable,由于赋值的环境是标量上下文,结果应该是个数字,而不是匹配命中的结果哦。

从句子表面判断的,没test,大家看看对不对哈。
作者: apile    时间: 2005-11-17 12:46
不好意思..少写了()...仙子说得没错....

只是连从DB里面抓出来的variable..也是tainted...这就很麻烦了...

有时候几十个variable...一个一个检查....这样的程序写得会很累的....
作者: flw    时间: 2005-11-17 14:07
哈哈!支持讨论语法!
作者: flw    时间: 2005-11-17 14:14
下面这个是 perldoc perlsec 里的:
  1. sub is_tainted {
  2.     return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 };
  3. }
复制代码





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2