• <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-06-11來源:作者:點擊數: 標簽:
    引言 對一種編程語言而言,在設計這種語言的時候,一般是不會產生 安全 隱患的,事實上,這種隱患是由 程序員 引入的。幾乎每一種編程語言都有一定這樣的漏洞,這種漏洞將會在某種程度上導致不安全軟件的產生,但是一個如軟件整體的安全性仍然大部分依賴于這
    引言
    對一種編程語言而言,在設計這種語言的時候,一般是不會產生安全隱患的,事實上,這種隱患是由程序員引入的。幾乎每一種編程語言都有一定這樣的漏洞,這種漏洞將會在某種程度上導致不安全軟件的產生,但是一個如軟件整體的安全性仍然大部分依賴于這個軟件制造者的知識面、理解能力和他的安全意識。Perl也有它安全上令人擔憂的部分,然而大多數程序員完全沒有意識到這些方面。
    在這篇文章里,我們將會看一下Perl中一些最普遍被誤用和忽視的屬性。我們將會看到它們的誤用將會怎樣對運行它們的系統的安全以及它們的用戶造成威脅。我們將會演示怎樣把這些弱點挖掘出來以及如何去修改、避免它們。


    用戶輸入上的弱點
    Perl腳本中產生安全問題的一個很大的來源是沒有經過正確確認(或根本就沒有確認)的用戶的輸入。每次當你的程序要從一個不信任用戶那里獲取輸入信息的時候,即使采用的是非直接的方式,你都應該小心。舉個例子來說吧,如果你在Perl中寫CGI腳本,你要預期到惡意的用戶將會發送給你假的輸入。 不正確的用戶輸入,如果沒有經過確認就被認可并使用了,將會導致許多方面出錯。最常見和明顯的錯誤是,沒有經過確認就去執行有用戶自定義參數的其他程序。


    syetem()和exec()函數
    Perl以能被用作一種“粘合”語言而著稱--它能夠通過如下方式完成一個出色的工作:在調用其他程序來為它工作的時候,通過采集一個程序的輸出,將它重新格式成一種特定的方式后傳遞到其他程序的輸入的方式仔細的協調它們的運行。這樣各個程序就能很好的運行了。
    正如Perl發布標語告許我們的,我們有不止一種方法可以做同樣的事。
    一種執行一個外部程序和一個系統命令的方法是通過調用exec()函數。當Perl遇到一個exec()語句的時候,它審視exec()被調用處的參數,然后啟動一個新的進程來執行這條特定的命令。Perl從不會返回控制給調用exec()的原來的那個進程。
    另一個相似的函數是system()。system()的運行方式非常象exec()。它們之間的唯一的大的區別是Perl會首先從父進程中分叉出一個子進程,子進程作為提供給system()的一個參數。父進程等到子進程結束運行后再接著運行程序的其余部分。我們將會在下面更詳細的討論system()調用,但這些討論大部分也適用于exec()。
    傳遞給system()的參數是一個列表--列表里的第一個元素是要被執行的這個程序的程序名,其他元素是傳給這個程序的參數。然而,如果只有一個參數的的話,system()的執行方式會發生差異。在那種情形下,Perl將會掃描這個參數看它是不是包含任何shell轉換字符。如果有的話,它就要把這些字符通過shell來解釋。所以產生一個shell命令行來工作。不然,Perl會降字符串拆成單詞然后調用效率更高的c庫函數execvp(),這個函數不能理解特殊的shell字符。
    現在假設我們有一張CGI表單,它要詢問用戶名,然后顯示包含這個用戶統計信息的一個文件。我名可以如下使用system()來調用’cat’實現那種要求:
    system ("cat /usr/stats/$username";
    用戶名來自這樣的一個表單:
    $username = param ("username";
    . 舉個例子,當用戶在表單里添上username = jdimov,然后提交后。Perl在字符串``cat /usr/stats/jdimov''中沒有找到任何轉換字符創,所以它就調用execvp()函數運行”cat”后返回到我們的腳本中。這個腳本也許看起來沒有害處可言,但是它容易被一個惡意的攻擊者所利用。
    問題是這樣的,通過在表單的”username”域內使用特殊的字符,一個攻擊者可以通過 shell來執行任何命令。舉個例子,我們可以這樣說,如果攻擊者傳遞這樣的字符串"jdimov; cat /etc/passwd",Perl會把分號當作一個轉換字符,然后把它傳遞到shell中:
    cat /usr/stats/jdimov; cat /etc/passwd
    攻擊者既可以獲得亞元文件,又可以獲得密碼文件。如果攻擊者想要搞破壞的話,他只要發送"; rm rf /*"就可以了。
    我們在前面提到system()有一個參數表,并且將第一個元素看作命令來執行,而將其余的元素作為參數來傳遞。所以我們可以稍微改變一下我們的腳本,使只有我們想讓執行的程序能夠被執行:
    system ("cat", "/usr/stats/$username";
    既然我們分開來指定程序的參數,那么shell就永遠也不會被調用了。所以發送";rm -rf /*"也就不會起作用了,因為攻擊字符串將只會被解釋成一個文件名而已。
    這種方法比單個參數的版本要好多了,因為它避免了使用shell命令,但是仍然有潛在的缺陷。特別的,我們要考慮到$username的值會不會被利用產生程序中能被執行的弱點。舉例來說,一個攻擊者仍然可以利用我們重寫的代碼版本,通過把$username設置成字符串"../../etc/passwd"來獲得系統的密碼文件。
    使用那樣的程序的時候很多地方會出錯,舉例來說,一些應用程序將特殊的字符序列解釋成執行一條shell命令的請求。一個普遍的問題是有些版本的Unix郵件工具當它們在一定的上下文背景下看到有”~!…”等字符序列的時候將會執行一個shell命令。所以在一個消息體中的空白行中包含"~!rm -rf *"的用戶輸入將會在某種情形下產生問題。
    只要是談及安全的,上面論及system()函數的任何內容也適用于exec().


    Open()函數
    在Perl中open()函數被用來打開文件。在最為常見的形式中,它是這樣使用的:

    open (FILEHANDLE, "filename";
    這樣使用的時候,’filename”是以只讀方式打開的。如果”filename”是含有”>”標志的前綴,那么它是為輸出而打開的,并且在文件已經存在的時候覆蓋原文件;如果含有”>>”前綴,那么是為追加打開的;前綴”<”打開文件來進行輸入*作,但這也是不含前綴的時候的默認方式。用未經確認的用戶輸入作為文件名的一部分所產生的一些問題應該總是比較明顯的。舉例來說,向后回溯瀏覽目錄的騙招在這里仍然能用。還有其他值得擔憂的問題?,F在我們使用open()替換”cat”來修改我們的腳本文件。我們象這樣的命令:
    open (STATFILE, "/usr/stats/$username";
    然后我們從文件中讀取代碼并顯示它。Perl文檔告許我們:如果文件名是以”|”開始的,文件名將會被解釋成一個輸出管道命令;反之,如果文件名以”|”結束的話,文件名將會被解釋成將讓我們進行輸出的管道。
    于是,只要加上一個”|”前綴,用戶就可以在/usr/stats目錄下運行任何命令了。向后回溯目錄的*作能夠讓用戶在這個系統里執行任何程序。
    一種解決這個問題打方法是:對于你想要打開并向其中輸入的文件總是要求通過加”<”標識顯式的指明.
    有時我們確實要調用一個外部的程序,比如,我們想要改表我們的腳本文件以讓他能夠讀取舊的純文本文件/usr/stats/username,但是在顯示給用戶之前要先通過一個HTML過濾器。我們有一個馬上就可以使用的便利的方法來實現這個意圖。一種方法可以這樣做:
    open (HTML, "/usr/bin/txt2html /usr/stats/$username|";

    print while ;
    不幸的是,這依然要通過shell層。然而我們可以采用open()調用的另一個形式來避免牽涉到shell:
    open (HTML, "-|"

    or exec ("/usr/bin/txt2html", "/usr/stats/$username";

    print while ;
    當我們打開一個管道命令,或者是為了讀(“-|”),或者是為了寫(”|-“)的時候,Perl在當前進程中產生分支,并且返回子進程的PID給父進程,返回0給子進程?!眔r”語句用來決定我們是在父進程還是在子進程。如果我們在父進程(返回值為非零),我們繼續執行print()語句。否則我們在子進程中,就執行txt2html程序,使用多于一個參數的exec()的安全版本來避免傳遞任何命令到shell層。所發生的是,子進程答應txt2html產生的STDOUT輸出,然后就默默的消亡了(記?。篹xec()從不返回),同時父進程從STDIN中讀取結果。象這樣的技術可以被用來通過管道將輸出輸到一個外部程序的技術:
    open (PROGRAM, "|-"

    or exec ("/usr/bin/progname", "$userinput";

    print PROGRAM, "This is piped to /usr/bin/progname";
    在我們需要管道的時候,open()的以上這些形式應該總是比直接的管道open()命令優先采用,因為它們不通過shell層?,F在讓我們設想我們要將靜態文本轉化成格式化很好的HTML頁面,并且,基于方便考慮,要存放在顯示這些頁面的Perl腳本相同的目錄下。那么我們的open語句看起來可能是如下形式:
    open (STATFILE, "<$username.html";
    當用戶通過表單中傳遞username=jdimo的時候,腳本顯示jdimov.html。這里仍然有被攻擊的可能。不同于c++和c ,perl不用空字節來結束字符串,這樣的話字符串jdimov/”jdimov/lo/bah在絕大數c庫調用中解釋為”jdimo”,但是在Perl中卻是”jdimov\0blah”。當perl傳遞一個含空字符的字符串給用c寫的程序的時候,這個問題就突出了。UNIX內核以及絕大多數UNIX 和shell 都 是純c 語言的。Perl自身也主要是且c編寫,當用戶如下調用我們的腳本:
    statscrit.plusername=jdimov/%00
    會發生什么呢?我們的程序傳遞字符串”jdimov/%。html”到對應的系統調用里以打開它,但是因為那些系統調用是用c編寫,接受的是空字節的字符串方式。結果怎樣呢?如果有文件”jdimov”的話就會顯示這個文件,可能并沒有這個文件,即使有也不是很有用。但是如果用"stats cript./pusername=stats cript。p/%"來調用腳本,會發生什么呢?如果腳本和我們的html文件在同一個目錄下的話,這樣我們可以用這個輸入來期騙腳本,來顯示給我們所有的內容。在這種情況下或許不是什么大的安全危險,但是它肯定能被其它的程序使用,因為它允許攻擊者分析其他可利用的缺陷的來源。


    單引號
    在perl中,另一種讀取外部程序的輸出的方法是把命令放在單引號里。所以如果我們想在分等級的$stats的文件中保存我們stats文件的內容的話,我們可以這樣做:
    $stats=’cat/user/stats/$username’;
    這確實要通過shell層來實現。任何把用戶輸入包含在一對單引號內的腳本都有發生前面討論的所有的安全問題的危險。有很多方法可試圖使shell不要誤解一席可能的轉換字符。但是最安全的事就是不要用但引號。取而代之的是,打開一個通到STDIN的管道,然后分叉執行外部程序,就像我們在前一節open()所做的一樣。


    Eval()和/e 修飾符
    函數eval()可以在運行時間執行一個Perl代碼塊,并返回上一次經評估語句的值。這種函數功能經常用于諸如配置文件,它可以寫成perl代碼,除非你絕對相信輸進eval()的源代碼,否則不要做諸如eval/$userinput,之類的事,這也適用于一個常規表述中的/e 修飾符,用來使perl在執行之前解釋該表述。


    過濾用戶輸入
    用于本節我們所討論的所有問題的過濾用戶輸入的一個通常方法(FU In OCA )就是過濾任何不需要的轉換字符和有問題的數據。例如我們可以在任何時段過濾來避免向后的目錄查看。類似的,我們一旦看見非法的字符,就讓程序運行失敗,這種策略被稱為”黑名單”這種哲學就是如果某東西沒有明確禁止,那它肯定是好的。一個更好的策略就”白名單”,它指如果某東西沒有被明確認可,那么它必須禁止。黑明單的最重要的問題是它非常難保持完整性并得到更。你也許會忘掉過濾某一特定字符,或者你的程序或許不得不隨不同的轉換字符集合轉到一個不同shell中。不過濾掉不需要的轉換字符和其他危險輸入,相反,只過濾進合法的輸入。下面的片段就是一個例子,它會停止執行一個安全性有問題的*作,如果有戶輸入中包含了除字母,數字,點和@符號外任何東西(@經常用于用戶的電子郵件地址)
    unless($useradress=~/^[-@/w。]+)$/)

    {print”secrity error。/n”exit(1);

    }
    基本的思想是不去編譯一個特定值的列表來保護,而是產生一個安全列表來接受可接受的輸入值的列表??山邮艿妮斎胼斎胫档倪x擇當然會隨著不同的應用程序而變化??山邮艿闹祽摬捎媚撤N能將破壞的可能性降到最小的方式來選擇。


    避免shell
    當然,你也必須盡可能的避免shell,然而這種技術可被廣泛地應用。如果你調用一個有特定序列的編輯器。你必須確認這些特定序列是不被允許使用的。一般,通過使用現存perl模塊,你能避免使用外部程序來執行一個外部函數,CPAN是一個能完成幾乎所有標準UNIX工具集能做的任何事的經測試的函數的模塊來源,然而它或許會費點勁來包含一個模塊,并且調用它,而不是調用一個外部程序,模塊方法一般來說更安全和靈活,為解釋清楚這一點,使用Net::SMTP,而不用exec()’ing sendmail/--T會幫你少一些使用shell的麻煩,并能防止你的用戶在sendmail代理中尋求已知的弱點。


    其它安全問題的來源(不安全環鏡變量)
    用戶輸入實際上是perl程序的主要安全問題的來源,但是還有其它因素是在寫安全的perl源代碼時所必須考濾的,經常 在shell下運行的腳本的易受攻擊的弱點或者通過網絡服務器是不安全的環鏡變量,最通常的是PATH /變量。當你從你代碼內部中使用一個外部應用程序或功能,而僅僅指明了一條相對路徑的時候,你就使 你這個程序和運行它的系統處于危險中。如果你有如下一個system()調用:
    system(“txt2html”,”user/stats/jdiov”);
    對于這種調用,你假設txt2htm文件是包含在PATH變量某處的目錄下,但是假如發生這種情況,一個攻擊者改變你的路徑指向含有相同的名字的其他帶惡意的程序中,你的系統的安全性就得不到保證。為了避免例似的事情發生,每個需要含有遠程安全意識的程序都應該這樣開始寫:
    #!/usr/bin/perl -wT

    require 5.001;

    use strict;

    $ENV{PATH} = join ':' => split (" ", << '__EOPATH__');

    /usr/bin

    /bin

    /maybe/something/else

    __EOPATH__
    如果程序依賴于其他環境變量,它們也要在它們使用前明確的定義出來。
    另一個危險變量(這個更是針對perl的)是@INC距陣變量,它非常像PATH,只不過它 指明Perl到哪里去找要包含在程序中的模塊。有關@INCR 的問題和PATH是非常相似的。有人可能會把你的perl指向一個具有相同的名字模塊,而且如你所料的做同樣的事,但是它也背地里做一些壞事,因此@INC同PATH都不值的信任。在包括任何外部模塊之前都 必須完全重新定義。


    Setuid腳本
    通常一個Perl程序是以執行它的用戶的權限來運行的。通過產生一個setuid腳本,它的有效用戶的ID可以設定成更高的權限,這個權限使這個用戶可以訪問他實際沒有訪問權限的資源,比如passwd程序使用setuid來獲取對系統password文件的寫的權限,這樣允許用戶來更改自已的密碼,因為執行程序是通過CGI界而來執行的,該界面是在使用網絡服務器的用戶權限下運行的,CGI程序員經常 試圖使用setuid技巧來讓他們的腳本執行一些惡作劇。這有可能用,但也可能十分危險,對一個事情,如果一個攻擊者發現一各方法可以利用腳本的弱點他們不僅是獲得訪誤問系統的權限,但是他們會用有效的UID的特權來獲得存在著另外幾種類似的種族狀況,在一個程序當中,這類缺陷是比較容易監控的,尤其是對有經驗的程序員來說,目前相關方面的工作正在積極的探索著。關于這個問題,目前還沒有一個既容易又完全有效的解決方法,常常在種族狀況存在的可能情況下,用到的最好的方法是使用原子*作方式來進行,這就意味著僅僅使用一種系統來同時檢查和生存檔案。而不必使用處理器,在二者之間進行切換。當然,這不可能是常有的。
    另外我們所作的一種標準模式是使用SYSOPEN來確定一種只讀模式,不必再設定刪減標志。

    通過這種方法,即使我們的文件名確實已經形成,當我們打開文件進行寫*作的時候 ,我們也不會破壞文件。注意:Fcnt1??毂仨毎M來,以便讓sysopen()函數起作用,因為這個模塊是如下常數,O_RDONLY, O_WRONLY, O_CREAT,等被定義的地方。


    緩沖區溢出和perl
    一般來說,perl腳本是不容易發生緩沖區溢出的,因為perl能在需要的時候動態的擴展它的數據結構。Perl跟蹤為每個字符串分配的大小。在一個字符串每次被賦值之前,perl保證有足夠的空間可以利用,如果需要的話,也可以為那個字符串分配更多的空間。
    然而在一些較老的perl實現方法中有幾種熟為人知的緩沖區溢出情形。一個明顯的例子是5。003版本會因為緩沖區溢出而崩潰。所有的suidperl版本(一種設計用來工作在為某些內核)都是在早于5。004版本的perl的不同分類的基礎上建立起來的。


    結論:
    在我們以后的文章中,我們將會化一定的時間來熟悉perl提供給我們的安全特性,尤其是perl的”taint 模式“,并且,我們將會證明,如果我們不小心的話,即使在如此堅固的安全機制下,依然可能會出現的一些問題。在學習perl的這些方面以及一些典型的例子的時候。我們的目標是為了培養我們的一種直覺,這種直覺能幫助我們在看perl腳本的第一眼時就能夠意識到其中的安全問題,以避免在我們的程序中犯類似的錯誤。


    原文轉自:http://www.kjueaiud.com

    ...
    老湿亚洲永久精品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>