Provided by: manpages-zh_1.5-1_all bug

NAME

       perlsec - Perl 安全

DESCRIPTIONyz
       Perl可以輕鬆寫出安全的程式,即使運行時有特殊權-
       ,比如setuid或setgid程式。許多稿本的命令行裏有多項替換語句,Perl卻不是這樣,它使用更多傳統方法而少有艱深。而且,由於perl語言有更多內在功能,它可以更少的依賴於其他(可能不可信的)程式來完成根本目的。

        當Perl檢測到程式中真實的使用者或組ID與有效使用者或組ID不同時,它自動地開啟一種叫做「污染模式」特殊的安全性檢測。setuid的unix的權-
       位是04000,setgid 的UNIX權位是02000;它-
       抭ㄕ野i能被設置。你也可以用命令行標識 -T
       明確地開啟「污染模式」。強烈建議伺服器程式或者在以其他人-
       份運行的程式(比如CGI稿本)使用此標識符。一旦污染模式被打開,它在稿本的餘下內容中一直開啟。

       在「污染模式」中,Perl使用叫做「污染檢測」的特殊預防方法來防止明顯的和不易被察覺的陷阱。一些檢測相當簡單,如檢查路徑目錄以確定它-
       拊翵銗L人是不可寫的;小心的程式-
       一向做此類檢測。其他的檢測已經得到Perl本-
       最好的支持,這些檢測尤其使寫一茳et-id的Perl程式比相應的C程式更安全。

       你不可以使用來自程式之外的數據來影響程式之外的事情──至少不是偶然的。所有命令行參數,環境變量,本地信息(參見perllocale),特定系統調用的結果(readdir(),readlink(),shmread()的變量,msgrcv()的返回信息,getpwxxx()調用返回的密碼、gcos和shell域)和所有檔案輸入都被標記成「污染的」。「污染的」數據既不可以直接或間接在任何調用一-
       茪lshell命令中使用,也不能在任何-
       蚹奰仵蛂B目錄或進程的命令中使用,但有以下例外:

       o   print和syswrite的參數不被檢查是否被污染。

       o   符號方法

               $obj->$method(@args);

           以及符號的子引用

               &{$foo}(@args);
               $foo->(@args);

           不會被檢查是否被污染。這-
           n求額外的小心,除非你希望外部數據影響你的控制流。除非你小心地-
           制這些符號O什麼,人怚i以從 Perl 代碼外部調用函數,類似
           POSIX::system,來運行任意外部代碼。

       為了效率鴞],Perl 對數據是否已被污染持保守的看法。如果一-
       茠竁F式包含污染的數據,任何子表達式都被認為污染的,即使自表達式的-
       P污染的數據無關

       由於污染與每蚍迠q袺騿A一-
       蚍晥帤畢C的元素可以只有一部分被污染。散列的鍵永遠不會被污染。

       例如:

           $arg = shift;               # $arg 是污染的
           $hid = $arg, 'bar';         # $hid 也是污染的
           $line = <>;                 # 污染的
           $line = <STDIN>;            # 仍舊是污染的
           open FOO, "/home/me/bar" or die $!;
           $line = <FOO>;              # 還是污染的
           $path = $ENV{'PATH'};       # 污染的, 但是請看下
           $data = 'abc';              # 非污染的

           system "echo $arg";         # 不安全的
           system "/bin/echo", $arg;   # 認為不安全
                                       # (Perl 不知道 /bin/echo)
           system "echo $hid";         # 不安全的
           system "echo $data";        # 如果PATH被設定,那麼才是安全的

           $path = $ENV{'PATH'};       # $path 現在是污染的

           $ENV{'PATH'} = '/bin:/usr/bin';
           delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

           $path = $ENV{'PATH'};       # $path 現在不是污染的
           system "echo $data";        # 現在是安全的!

           open(FOO, "< $arg");        # OK - 只讀檔案
           open(FOO, "> $arg");        # Not OK - 試圖去寫

           open(FOO,"echo $arg|");     # Not OK
           open(FOO,"-|")
               or exec 'echo', $arg;   # 同樣 not OK

           $shout = `echo $arg`;       # 不安全的, $shout 現在是污染的

           unlink $data, $arg;         # 不安全的
           umask $arg;                 # 不安全的

           exec "echo $arg";           # 不安全的
           exec "echo", $arg;          # 不安全的
           exec "sh", '-c', $arg;      # 非常不安全!

           @files = <*.c>;             # 不安全的 (使用 readdir() 或其他)
           @files = glob('*.c');       # 不安全的 (使用 readdir() 或其他)

           # In Perl releases older than 5.6.0 the <*.c> and glob('*.c') would
           # have used an external program to do the filename expansion; but in
           # either case the result is tainted since the list of filenames comes
           # from outside of the program.

           $bad = ($arg, 23);          # $bad will be tainted
           $arg, `true`;               # Insecure (although it isn't really)

       如果你試圖做一些不安全的事情,你會得到類似"Insecure
       dependency"或"Insecure $ENV{PATH}"的P命錯誤。

       Laundering and Detecting Tainted DataM~MV據

       測試一蚥僆q是否含有污染的數據,誰的用法會引發一條"Insecure
       dependency"信息,在你附近的CPAN鏡像查找Taint.pm模塊,它應該在1997年左右就可以得到
       。或者你可以用is_tainted()函數。

           sub is_tainted {
               return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 };
           }

       此函數利用了「表達式中任何一部分存在的污染數據P使整-
       茠竁F式都被污染」。操作測試每-
       荌捊O否被污染會使效率低下。相反,稍稍高效且矇w的方法是,只n一-
       茠竁F式中任何一部分存取一茬Q污染的A那麼這茠竁F式被認為是被污染的。

       但是僅僅測試數據是否被污染還不夠。有時你必須清除數據的污染。唯一的通過污染機制的方法是引用正則表達式中的一-
       茪l模式。Perl假定如果你用$1, $2等等引用一-
       茪l串,那麼你就知道你在做什麼。也就是說你必須思考而不是盲目的解除污染,或者違抗整-
       蚞魖謘C校驗變量是否只含有好的字符(已知的好的字符)比檢查它是否含有壞的字符-
       n好。是因為很可能就把意料之外的壞字符漏掉。

       下悸漕狺l是一-
       蚗邠d數據中是否只含有單詞(字母、數字、下劃線)、連字符、'@'符號或者是'.'。

           if ($data =~ /^([-\@\w.]+)$/) {
               $data = $1;                     # $data now untainted
           } else {
               die "Bad data in '$data'";      # log this somewhere
           }

       這完全沒有問題,因為/1920/從理論上講會不安全,因為它匹配任何字符,而Perl將不再檢查它-
       怴C我-
       怐爾g驗是當你解除污染時,必須對匹配模式極其的小心。使用正則表達式清洗數據是解除污染的唯一機制,除非你使用下-
       惜~詳細敘z的派生一荅S權被飢C的字進程的方法。

       如果程式中使用了use locale,那麼上-
       悸漕狺l將不會解除$data的污染,因為1176ㄔi信的,因為它怚]含程式之外
       的數據。如果你在寫一-
       胵ocale-
       aware的程式,並且想使用包含120竁F式清洗數據,那麼請在同一塊內的表達式之前加上no
       locale。參見perllocale/SECURITY以獲 得更多的信息。

       當你使稿本程式可執行,就是可以像命令一樣讓它-
       怳u作時,系統會把"#!"行的開關傳遞給Perl。Perl檢查setuid(或setgid)程式的任何和"#!"行開關匹配的命令行開關。一些Unix或Unix-like系統環境強制在"#!"行使用一-
       荈}關,所以你也許必須用類似-wU的開關而不是-w -U。(這-
       荌暋D只出現在支持#!、setuid、setgid稿本的Unix或Unix-like系統環境中)

       Taint mode and @INC

       When the taint mode ("-T") is in effect, the "." directory is removed
       from @INC, and the environment variables "PERL5LIB" and "PERLLIB" are
       ignored by Perl. You can still adjust @INC from outside the program by
       using the "-I" command line option as explained in perlrun. The two
       environment variables are ignored because they are obscured, and a user
       running a program could be unaware that they are set, whereas the "-I"
       option is clearly visible and therefore permitted.

       Another way to modify @INC without modifying the program, is to use the
       "lib" pragma, e.g.:

         perl -Mlib=/foo program

       The benefit of using "-Mlib=/foo" over "-I/foo", is that the former
       will automagically remove any duplicated directories, while the later
       will not.

       Cleaning Up Your PathMz|

       對於"Insecure
       $ENV{PATH}"這樣的信息,你必須把$ENV{PATH}設置為已知的,並且路徑中的任何目錄都對於非本使用者或非本組成-
       不可寫。你也許會在即使路徑名是完全合法的情況下收到那條信息表示非常驚訝。當你沒有提供程式一-
       荍嗾膋爾纁|時,它不會被引起;相反,-
       Y你從未設置PATH環境變量,或者你沒有把它設置安全,它就會被引起。因為Perl不能保証可疑的可執行程式是不是它本-
       將執行其他的依賴於PATH的程式,它確定是你設定的PATH。

       PATH不是唯一可能導-
       P問題的變量。因為一些shell會使用IFS,CDPATH,ENV和BASH_ENV,Perl在開始子進程時檢查它-
       怓O否也為空或者未污染。你也許會在你的set-
       id和污染檢測模式下的稿本程式中加入這些東西:

           delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};   # 使 %ENV 更安全

       當然,無論是否使用污染變量都有可能出現麻煩。在處理任何由使用者提供的檔名的檔案時,-
       n做周密的測試。必須時,可以在去掉使用者(或組!)的特權之後再進行類似open的操作。Perl不阻止你打開污染的檔名並讀取內容,所以-
       n小心對待列印出的內容。污染機制的目的是防止愚蠢的錯誤,不是使人懶惰不去思考。

       當你傳遞給system和exec明確的參數列表而非含有通配符的字符串時,Perl不會調用shell去擴展通配符。不幸的是,open,glob,backtick(譯注:backtick為反引號)函數並不提供這樣的特性,所以當使用它-
       怐漁尕必須非常仔細。

       Perl為從一茳etuid或setgid程式打開檔案或管道提供了一茼w全的方法:創建一-
       荋謅秸v的子進程來為你完成那些「骯臟」的工作。-
       漸,用特殊的OPEN語法創建一茪l進程,使其和父進程通過一-
       蚨瑐D相連。現在子進程把它的ID和其他諸如環境變量,umask,當前工作目錄的性質-
       奐s設置回-
       鴝l的或安全的變量。然後讓該不具有任何特權的子進程來完成OPEN和其他的系統調用。最終,子進程把它成功存取的數據傳遞給父進程。因為檔案或管道是由運行於比父進程權-
       低的子進程打開的,所以它不容易被欺騙去做它不該做的事情。

       這裏有一-
       茼w全使用backtick的方法。注意當shell可能擴展時,exec是如何不被調用的。這是目前來調用可能被shell轉義的東西最好的方法:從不調用shell。

               use English '-no_match_vars';
               die "Can't fork: $!" unless defined($pid = open(KID, "-|"));
               if ($pid) {           # parent
                   while (<KID>) {
                       # do something
                   }
                   close KID;
               } else {
                   my @temp     = ($EUID, $EGID);
                   my $orig_uid = $UID;
                   my $orig_gid = $GID;
                   $EUID = $UID;
                   $EGID = $GID;
                   # Drop privileges
                   $UID  = $orig_uid;
                   $GID  = $orig_gid;
                   # Make sure privs are really gone
                   ($EUID, $EGID) = @temp;
                   die "Can't drop privileges"
                       unless $UID == $EUID  && $GID eq $EGID;
                   $ENV{PATH} = "/bin:/usr/bin"; # Minimal PATH.
                   # Consider sanitizing the environment even more.
                   exec 'myprog', 'arg1', 'arg2'
                       or die "can't exec myprog: $!";
               }

        使用類似的策略可以讓glob使用通配符擴展,雖然也可以用readdir。

       當你雖然相信自己並沒有寫有問題的程式,但並不信任程式的最終使用者不會企圖讓它做壞事時,污染檢測最為有用。此類安全檢查對set-id和以其他使用者-
       份運行的程式(如CGI)非常有用。

       Y連程式的作者都不可信的話,情況就不同了。當某人給你一段程式並和你說,「給,試試看。」對於此類安全問題,使用包含在Perl發行版中的Safe模塊。這-
       蚍珔穭像\程式-
       建立特殊的隔間,在其中所有的系統調用都被截獲,並且名字空間入口被嚴格控制。

       Security BugswD

       除了源於賦予像稿本一樣靈活的系統特權這類明顯的問題,在許多Unix版本中,set-id稿本從一開始就是天生不安全的。問題出在核心的條件競爭。在核心打開檔案來查看應該運行-
       虒挭擰鼎M當(現在已set-id)解釋器回過頭來奐s打開檔案並解釋它的這兩-
       茖韝孜﹛A可疑的檔案也許已經改變了,特別是當系統中有符號連接時。

       幸運的是,這荇痐萿滿u特性」有時可以被關閉。不幸的是,有兩-
       茪隤k來關閉它。系統可以簡單的宣布任何含有set-id位的稿本都是不合法的,這-
       蚥蒫M用處不大。另一-
       茯O忽略稿本中的set-
       id位。如果後者被設置為真,那麼當Perl注意到其它稿本中無效的setuid/gid位時,它可以模仿
       setuid和setgid的機制。這是通過一-
       茈s做suidperl的特殊程式來實現的,它在需n時自動被調用。

       但是,如果核心的set-id稿本特性沒有被關閉,Perl就會大聲抱怨你的set-id程式是不安全的。你-
       n麼需n關閉核心的set-id稿本特性,n麼為稿本製作一笏 Wrapper。一笏
       Wrapper就是一-
       荌ㄓF調用你的Perl程式其他什麼都不幹的已編譯程式。已編譯程式不受此核心問題的影響去找set-id稿本的麻煩。這裏有一-
       蚋眾瑼慢 Wrapper:

           #define REAL_PATH "/path/to/script"
           main(ac, av)
               char **av;
           {
               execv(REAL_PATH, av);
           }

       把此C Wrapper編譯成可執行二進制檔案,對它setuid或setgid而不是你的稿本。

       近幾年,軟體商開始提供沒有此安全問題的系統。在它怳丑A當核心把將-
       n被打開的set-id稿本的名字傳遞給解釋器時,它將不會傳遞可能出現問題的路徑名而是傳遞/dev/fd/3。這是一-
       茪w經在稿本上打開的特殊檔案,所以將不會出現條件競爭問題。在這些系統中,Perl需-
       n在編譯時帶上-DSETUID_SCRIPTS_ARE_SECURE_NOW參數。Configure程式將自己完成這-
       茈羺A所以你永遠不必-
       n自己指出此點。現在SVR4和BSD4.4都採用此種方法來避免核心條件競爭。

       在Perl 5.6.1 發行之前,suidperl的代碼問題可能導P安全漏洞。

       Protecting Your ProgramsO@A{式

       有很多種方法可以隱藏你的Perl程式鴝l碼,它怢膃酗ㄕP等級的「安全性」。

       漸,你不能去掉「讀」權,因為-
       鴝l碼必須在被讀取之後才能編譯和解釋。(這並不意味著CGI稿本的-
       鴝l碼在網上是可被讀取的)所以你必須把權-
       設置為對外界友好的0755。這使在你本地系統上的人只能查看鴝l碼。

       一些人錯誤的認為這是一茼w全問題。如果你的程式不安全,而你依賴人-
       怳ㄙ器D如何利用這些漏洞,這是不安全的。通常某些人在沒有看-
       鴝l碼的情況下就可以利用這些漏洞。以隱藏來實現所謂的「安全」而不是-
       袨_漏洞,是非常不安全的。

       你可以試著通過-
       鴝l碼過濾器(CPAN上的Filter::*)來實現加密。但是駭客有可能把它解密。你可以試著使用下-
       探y-
       z的字節碼編譯器和解釋器,但是駭客有可能把它反編譯。這些對想看你代碼的人造成不同難度的困難。但是沒有一種可以完全的避免(不光是Perl,所有語言都一樣)。

       如果你擔心有人會通過你的程式得利,那麼你可以在最低行寫一-
       制性的許可証來尋求法律保護。當然如果你用類似「這是某某公司的私人程式,你無權使用它」的聲明來授權你的軟體並發佈它的話,那會是非常危險的。你應該找一-
       茷蒏v確定你的許可証的措辭可以在法庭上站得住腳。

       Unicode

       Unicode is a new and complex technology and one may easily overlook
       certain security pitfalls.  See perluniintro for an overview and
       perlunicode for details, and "Security Implications of Unicode" in
       perlunicode for security implications in particular.

       Algorithmic Complexity Attacks

       Certain internal algorithms used in the implementation of Perl can be
       attacked by choosing the input carefully to consume large amounts of
       either time or space or both.  This can lead into the so-called Denial
       of Service (DoS) attacks.

       o   Hash Function - the algorithm used to "order" hash elements has
           been changed several times during the development of Perl, mainly
           to be reasonably fast.  In Perl 5.8.1 also the security aspect was
           taken into account.

           In Perls before 5.8.1 one could rather easily generate data that as
           hash keys would cause Perl to consume large amounts of time because
           internal structure of hashes would badly degenerate.  In Perl 5.8.1
           the hash function is randomly perturbed by a pseudorandom seed
           which makes generating such naughty hash keys harder.  See
           "PERL_HASH_SEED" in perlrun for more information.

           The random perturbation is done by default but if one wants for
           some reason emulate the old behaviour one can set the environment
           variable PERL_HASH_SEED to zero (or any other integer).  One
           possible reason for wanting to emulate the old behaviour is that in
           the new behaviour consecutive runs of Perl will order hash keys
           differently, which may confuse some applications (like
           Data::Dumper: the outputs of two different runs are no more
           identical).

           Perl has never guaranteed any ordering of the hash keys, and the
           ordering has already changed several times during the lifetime of
           Perl 5.  Also, the ordering of hash keys has always been, and
           continues to be, affected by the insertion order.

           Also note that while the order of the hash elements might be
           randomised, this "pseudoordering" should not be used for
           applications like shuffling a list randomly (use
           List::Util::shuffle() for that, see List::Util, a standard core
           module since Perl 5.8.0; or the CPAN module
           Algorithm::Numerical::Shuffle), or for generating permutations (use
           e.g. the CPAN modules Algorithm::Permute or
           Algorithm::FastPermute), or for any cryptographic applications.

       o   Regular expressions - Perl's regular expression engine is so called
           NFA (Non-Finite Automaton), which among other things means that it
           can rather easily consume large amounts of both time and space if
           the regular expression may match in several ways.  Careful crafting
           of the regular expressions can help but quite often there really
           isn't much one can do (the book "Mastering Regular Expressions" is
           required reading, see perlfaq2).  Running out of space manifests
           itself by Perl running out of memory.

       o   Sorting - the quicksort algorithm used in Perls before 5.8.0 to
           implement the sort() function is very easy to trick into
           misbehaving so that it consumes a lot of time.  Nothing more is
           required than resorting a list already sorted.  Starting from Perl
           5.8.0 a different sorting algorithm, mergesort, is used.  Mergesort
           is insensitive to its input data, so it cannot be similarly fooled.

       See <http://www.cs.rice.edu/~scrosby/hash/> for more information, and
       any computer science text book on the algorithmic complexity.

SEE ALSO見
       perlrun中關於清理環境變量的描z

@H
       nan1nan1 <nan1nan1@hotmail.com>

ss
       20011223http://cmpp.linuxforum.net