• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    Perl的安全性監測

    發布: 2007-7-04 20:04 | 作者: admin | 來源:  網友評論 | 查看: 11次 | 進入軟件測試論壇討論

    領測軟件測試網


    本月的專欄將介紹Perl的稱為“tainting”的內部安全機制,它可以讓Perl捕捉到任何可能導致安全性問題的系統調用。我強烈推薦在你的所有CGI程序中打開“tainting”機制。

    CGI使得互聯網上的任何人都可以在你的計算機上運行程序,這就使得CGI成為世界上最流行的安全漏洞。作為程序員,我們的責任是不讓壞人侵入我們的系統,對于我們所編制的程序來說,要做到沒有漏洞可鉆。

    例如,下面這個CGI程序,就是個壞程序:

    #!/usr/bin/perl -w

    # cgi-bad – 一個不好的cgi 腳本的例子

    ...

    $file = param("FILE")

    or die "Must fill out the FILE field\n";

    unlink("/usr/local/public/data/$file")

    or die "Can't delete $file : $!\n";

    該腳本所做的是讀出在表單中所輸入的文件名,并從目錄/usr/local/public/data/中刪除該名稱的文件。錯了!該腳本所做的實際上是讓任何用戶對在網絡服務器上usercode可以刪除的任何文件作刪除操作。請看:

    % setuid-bad ../../etc/apache/var/userdb

    天哪!那里是用戶數據庫!

    我們本來要做的是檢查程序的參數,以確定其是否為文件名。問題是你的程序外部所產生的數據用到了系統調用上,如nlink(), open(),和system()。而你并不打算讓在你的程序之外產生的數據影響到外部世界。

    Perl有個選項,打開后,可以強迫你檢查常數,環境,輸入,或其它有可能被不懷好意的人利用的漏洞。該選項稱為“tainting”

    打開Taint檢查選項
    要打開taint檢查選項,讓Perl帶一個 -T 選項:

    #!/usr/bin/perl -wT

    如果我們在上述程序運行時,帶有 –T選項,我們會看到如下信息:

    Insecure dependency in unlink while running with

    -T switch at setuid-bad line 5.

    Perl跟蹤$file中的值,它是在你的程序外部生成的,(它被稱為“tainted”)。 unlink() 被認為是個不安全的操作,因為它對外部世界有影響:文件。在不安全的操作下,企圖使用沒有信任度的(tainted)數據是危險的。正如我們已經看到的,數據可能有詐。

    這些漏洞可以由Perl的taint檢查選項在運行時捕捉到,并且使得程序停下來。

    Tainted數據

    Tainted 數據來源很多,包括:來源于你的環境散列表 (the %ENV) ,參數 (@ARGV),讀入的文件和目錄,來源于運行的程序中,以及一些系統調用的結果(用getpw讀出口令數據庫中的GECOS域)。任何對tainted值的操作(添加,合并,插入),其結果值也是tainted。這就好像是數據一旦被粘上了污點,那么無論數據傳播到哪里,污點就會被帶到哪里。

    僅有三種方式,可以得到“untainted”值:數據直接在程序中指明;數據來自于安全的函數(如localtime);或者使用正則表達式提取來自不安全函數的tainted 串的一部分。

    $a = 4; # untainted

    $file = $ARGV[0]; # tainted

    $file =~ m{^([^/]+)$}

    or die "$file is not a good filename.\n";

    $untainted = $1; # untainted

    通過正則表達式用括號括起來,創建了$1, $2, ... 變量。這些都是untainted數據。通過正則表達式,你可以確信它就是你所期望的值。如果匹配失敗,你會得到失敗信息。如果匹配成功,$1 ...變量包含了你可以使用的untainted 數據。

    如果我們已經打開tainting 選項,當我們試圖做unlink()操作時,Perl 解釋器會停下來,告訴你$file 中包含了tainted 數據。文件名是 tainted的,因為它來自于不信任源:使用你的程序的人。

    壞動作
    如果你所使用的數據是tainted的,你想要Perl程序所做的大多數事情會產生出錯信息。如果文件名或程序名是tainted的,那么運行程序,打開文件來寫入,以及刪除文件,這些操作都將被禁止進行。

    這一節將演示如何在這種場合下,解除tainted狀態。

    考慮:

    system("ls *.h");

    Perl 在你的串中看到了 *,并決定調用shell,這樣:

    sh -c "ls *.h"

    但是,的確有人可能用假的路徑環境變量來運行你的程序,從而導致調用了錯誤的sh或ls。所以,對于PATH變量以及SHELL中可以用來修改其行為的其他變量,應該進行 untaint操作。

    一般,運行其它程序時,你應采取三項步驟:

    明確你的環境變量,使得運行的是實際程序。

    關閉shell

    對程序的參數進行untaint操作。

    用如下的等簡單方式清除你的環境變量:

    delete @ENV{"IFS", "CDPATH", "ENV", "BASH_ENV"};

    $ENV{PATH} = "/bin:/usr/bin";

    第一行刪除掉可能會引起問題的環境變量,第二行給出一個確保安全的PATH。你可以添加其他的目錄到PATH中,但務必確保它們同該處一樣,是有確定值的。

    關閉shell也要把握好分寸。Perl 在涉及到有關shell的操作,如 open(), system(), backticks,和exec() 調用時,有自己的規則,這些規則不太容易掌握。最好的規則是:避免使用backticks 和pipe open() 調用,而是使用system() 和exec() ,并傳給它們參數表。

    大多數人習慣于看到如下的寫法:

    system("someprogram arg1 arg2 arg3");

    他們不知道還可這樣寫:

    system("someprogram", "arg1", "arg2", "arg3");

    這樣的寫法,可以精確地告訴Perl的各個參數是什么,Perl將不會調用shell。 exec() 也具有讀參數表和不調用shell的特點。而如果要使用piped open() 和backticks,就無法保證不會用到shell。

    如果你打算使用piped open 或 backticks,你得用如下的方法重新實現:

    $pid = open(COMMAND, "-|");

    die "Couldn't fork: $!" unless defined $pid;

    if ($pid) {

    @lines = <COMMAND>;

    close(COMMAND);

    } else {

    exec("some", "program", "with", "args") or die "execing: $!";

    }

    一般來說,即使你的PATH已經作了安全處理,給出所運行的程序的完整路徑是個好主意。這就會避免了錯誤地調用了/usr/bin/boom 而不是/home/user/bin/boom這種情況的發生,因為在PATH中 /usr/bin 位于/home/usr/bin/boom.之前。

     


     

    文件名
    對文件名進行操作時,使用unlink() 或 <*.h> ,或者用open()時,是有危險的。

    從目錄中讀入的文件名是tainted的。你可以打開一個tainted 文件名來讀入,但你不能打開它來寫入。從文件中讀數據,不管文件名是否 tainted,已經是tainted的。因為用到了shell,你不能用<*.h> 來得到文件清單。

    為了檢查文件名是否是好的,你得寫出一個正則表達式,并同合法的文件名進行匹配。在一些場合,可以用如下的簡單方法來檢查你的數據:

    $file = $ARGV[0];

    ($file =~ m{^([^/]+)$} && $file ne "." && $file ne "..")

    or die "Bad filename $file\n";

    $file = $1;

    根據任何不包含斜杠的串的正則表達式來檢查文件名,這就把子目錄排除在外,然后排除掉“.”(當前目錄)和“..”(當前目錄的父目錄)。如果這些測試都通過了,$1變量中存放的就是我們可以使用的文件名。

    為了得到匹配某種模式的文件名清單,你既可以從CPAN (File::KGlob 和File::BSD 是兩個有用的模塊)安裝有關模塊,也可以使用讀目錄操作和正則表達式:

    opendir(DH, "/path/to/directory") or die "opening directory: $!\n";

    while (defined ($thing = readdir(DH))) {

    next unless /^(.*\.h)$/;

    push(@files, $1);

    }

    closedir(DH);

    # @files is the list of untainted *.h filenames

    檢查 Taintedness

    如果你需要檢查 taintedness,你可以使用如下技巧:

    sub is_tainted {

    return ! eval {

    join('',@_), kill 0;

    1;

    };

    }

    你需要了解兩件事情:kill 0 除了返回“true”之外,什么也不做;如果表達式的部分使用了tainted數據,那么,該表達式是tainted。所以,如果is_tainted調用時使用了tainted數據,對@_ 進行kill,就足以使得Perl 程序die。

     


     

    Untainting過了頭也會有問題
    在不多的場合,盲目地untaint你的數據也產生安全漏洞。所以也此時需要Tainting的存在。如果象下面一樣,盲目地對任何數據都untaint:

    $var =~ /(.*)/s; # 愚蠢

    $var = $1;

    正則表達式中的 /s 符號使得句點可以匹配串中的任何換行符。

    通過用 .* 我們匹配了串中的一切符號,并用$1存放該數據的untainted的副本。

    正如注釋所說的,這樣做是愚蠢的。

    總結

    -T 打開tainting選項。來自你程序之外的數據是tainted,不能使用這些數據,以免影響外部世界。

    用正則表達式和$1, $2, ... 變量進行untaint。要運行其他程序,設置好path,不要使用shell,并對參數進行untaint。

    進一步的閱讀

    在perlsec manpage 中詳細闡述了tainting的機制,并給出了較多的例子。Chapter Perl Cookbook的第十六章談了進程管理,演示了non-shell 版的 piped opens和其他有趣的用法

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>