歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> PERL編程 >> perl腳本中的一些安全問題

perl腳本中的一些安全問題

日期:2017/2/27 9:27:07   编辑:PERL編程
  對一種編程語言而言,在設計這種語言的時候,一般是不會產生安全隱患的,事實上,這種隱患是由程序員引入的。幾乎每一種編程語言都有一定這樣的漏洞,這種漏洞將會在某種程度上導致不安全軟件的產生,但是一個如軟件整體的安全性仍然大部分依賴於這個軟件制造者的知識面、理解能力和他的安全意識。Perl也有它安全上令人擔憂的部分,然而大多數程序員完全沒有意識到這些方面。  在這篇文章裡,我們將會看一下Perl中一些最普遍被誤用和忽視的屬性。我們將會看到它們的誤用將會怎樣對運行它們的系統的安全以及它們的用戶造成威脅。我們將會演示怎樣把這些弱點挖掘出來以及如何去修改、避免它們。    用戶輸入上的弱點   Perl腳本中產生安全問題的一個很大的來源是沒有經過正確確認(或根本就沒有確認)的用戶的輸入。每次當你的程序要從一個不信任用戶那裡獲取輸入信息的時候,即使采用的是非直接的方式,你都應該小心。舉個例子來說吧,如果你在Perl中寫CGI腳本,你要預期到惡意的用戶將會發送給你假的輸入。 不正確的用戶輸入,如果沒有經過確認就被認可並使用了,將會導致許多方面出錯。最常見和明顯的錯誤是,沒有經過確認就去執行有用戶自定義參數的其他程序。    syetem()和exec()函數   Perl以能被用作一種“粘合”語言而著稱——它能夠通過如下方式完成一個出色的工作:在調用其他程序來為它工作的時候,通過采集一個程序的輸出,將它重新格式成一種特定的方式後傳遞到其他程序的輸入的方式仔細的協調它們的運行。這樣各個程序就能很好的運行了。  正如Perl發布標語告許我們的,我們有不止一種方法可以做同樣的事。一種執行一個外部程序和一個系統命令的方法事通過調用exec()函數。當Perl遇到一個exec()語句的時候,它審視exec()被調用處的參數,然後啟動一個新的進程來執行這條特定的命令。Perl從不會返回控制給調用exec()的原來的那個進程。    另一個相似的函數是sys_tem(去掉"_")()。sys_tem(去掉"_")()的運行方式非常象exec()。它們之間的唯一的大的區別是Perl會首先從父進程中分叉出一個子進程,子進程作為提供給sys_tem(去掉"_")()的一個參數。父進程等到子進程結束運行後再接著運行程序的其余部分。我們將會在下面更詳細的討論sys_tem(去掉"_")()調用,但這些討論大部分也適用於exec()。  傳遞給sys_tem(去掉"_")()的參數是一個列表——列表裡的第一個元素是要被執行的這個程序的程序名,其他元素是傳給這個程序的參數。然而,如果只有一個參數的的話,sys_tem(去掉"_")()的執行方式會發生差異。在那種情形下,Perl將會掃描這個參數看它是不是包含任何shell轉換字符。如果有的話,它就要把這些字符通過shell來解釋。所以產生一個shell命令行來工作。不然,Perl會降字符串拆成單詞然後調用效率更高的c庫函數execvp(),這個函數不能理解特殊的shell字符。    現在假設我們有一張CGI表單,它要詢問用戶名,然後顯示包含這個用戶統計信息的一個文件。我名可以如下使用sys_tem(去掉"_")()來調用"cat"實現那種要求:  sys_tem(去掉"_") ("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 /*"就可以了。  我們在前面提到sys_tem(去掉"_")()有一個參數表,並且將第一個元素看作命令來執行,而將其余的元素作為參數來傳遞。所以我們可以稍微改變一下我們的腳本,使只有我們想讓執行的程序能夠被執行:  sys_tem(去掉"_") ("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”是含有”>”標志的前綴,那麼它是為輸出而打開的,並且在文件已經存在的時候覆蓋原文件;如果含有”>>”前綴,那麼是為追加打開的;前綴”



Copyright © Linux教程網 All Rights Reserved