| 導購 | 订阅 | 在线投稿
分享
 
 
當前位置: 王朝網路 >> perl >> Perl語言安全
 

Perl語言安全

2008-05-19 06:26:00  編輯來源:互聯網  简体版  手機版  評論  字體: ||
 
 
  引言

  對一種編程語言而言,在設計這種語言的時候,一般是不會産生安全隱患的,事實上,這種隱患是由程序員引入的。幾乎每一種編程語言都有一定這樣的漏洞,這種漏洞將會在某種程度上導致不安全軟件的産生,但是一個如軟件整體的安全性仍然大部分依賴于這個軟件制造者的知識面、理解能力和他的安全意識。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」是含有」」標志的前綴,那麽它是爲輸出而打開的,並且在文件已經存在的時候覆蓋原文件;如果含有」」前綴,那麽是爲追加打開的;前綴」

  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給子進程。」or」語句用來決定我們是在父進程還是在子進程。如果我們在父進程(返回值爲非零),我們繼續執行print()語句。否則我們在子進程中,就執行txt2html程序,使用多于一個參數的exec()的安全版本來避免傳遞任何命令到shell層。所發生的是,子進程答應txt2html産生的STDOUT輸出,然後就默默的消亡了(記住:exec()從不返回),同時父進程從STDIN中讀取結果。象這樣的技術可以被用來通過管道將輸出輸到一個外部程序的技術:

  open (PROGRAM, "|-")

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

  print PROGRAM, "This is piped to /usr/bin/progname";

  在我們需要管道的時候,open()的以上這些形式應該總是比直接的管道open()命令優先采用,因爲它們不通過shell層。現在讓我們設想我們要將靜態文本轉化成格式化很好的HTML頁面,並且,基于方便考慮,要存放在顯示這些頁面的Perl腳本相同的目錄下。那麽我們的open語句看起來可能是如下形式:

  open (STATFILE, "

  當用戶通過表單中傳遞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」的話就會顯示這個文件,可能並沒有這個文件,即使有也不是很有用。但是如果用"statscript./pusername=statscript。p/%"來調用腳本,會發生什麽呢?如果腳本和我們的html文件在同一個目錄下的話,這樣我們可以用這

  
 
 
 
上一篇《養成良好的PerlOOP習慣》
下一篇《改良的Perl:程序員面向Linux的設置》
 
 
 
日版寵物情人插曲《Winding Road》歌詞

日版寵物情人2017的插曲,很帶節奏感,日語的,女生唱的。 最後聽見是在第8集的時候女主手割傷了,然後男主用嘴幫她吸了一下,插曲就出來了。 歌手:Def...

兄弟共妻,我成了他們夜裏的美食

老鍾家的兩個兒子很特別,就是跟其他的人不太一樣,魔一般的執著。兄弟倆都到了要結婚的年齡了,不管自家老爹怎麽磨破嘴皮子,兄弟倆說不娶就不娶,老父母爲兄弟兩操碎了心...

如何磨出破洞牛仔褲?牛仔褲怎麽剪破洞?

把牛仔褲磨出有線的破洞 1、具體工具就是磨腳石,下面墊一個硬物,然後用磨腳石一直磨一直磨,到把那塊磨薄了,用手撕開就好了。出來的洞啊很自然的。需要貓須的話調幾...

我就是掃描下圖得到了敬業福和愛國福

先來看下敬業福和愛國福 今年春節,支付寶再次推出了“五福紅包”活動,表示要“把欠大家的敬業福都還給大家”。 今天該活動正式啓動,和去年一樣,需要收集“五福”...

冰箱異味産生的原因和臭味去除的方法

有時候我們打開冰箱就會聞到一股異味,冰箱裏的這種異味是因爲一些物質發出的氣味的混合體,聞起來讓人惡心。 産生這些異味的主要原因有以下幾點。 1、很多人有這種習...

《極品家丁》1-31集大結局分集劇情介紹

簡介 《極品家丁》講述了現代白領林晚榮無意回到古代金陵,並追隨蕭二小姐化名“林三”進入蕭府,不料卻陰差陽錯上演了一出低級家丁拼搏上位的“林三升職記”。...

李溪芮《極品家丁》片尾曲《你就是我最愛的寶寶》歌詞

你就是我最愛的寶寶 - 李溪芮 (電視劇《極品家丁》片尾曲) 作詞:常馨內 作曲:常馨內 你的眉 又鬼馬的挑 你的嘴 又壞壞的笑 上一秒吵鬧 下...

烏梅的功效與作用以及烏梅的食用禁忌有哪些?

烏梅,又稱春梅,中醫認爲,烏梅味酸,性溫,無毒,具有安心、除熱、下氣、祛痰、止渴調中、殺蟲的功效,治肢體痛、肺痨病。烏梅泡水喝能治傷寒煩熱、止吐瀉,與幹姜一起制...

什麽是脂肪粒?如何消除臉部脂肪粒?

什麽是脂肪粒 在我們的臉上總會長一個個像脂肪的小顆粒,弄也弄不掉,而且顔色還是白白的。它既不是粉刺也不是其他的任何痘痘,它就是脂肪粒。 脂肪粒雖然也是由油脂...

網絡安全治理:國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰受害者

來源:中國青年報 新的攻擊方法不斷湧現,黑客幾乎永遠占據網絡攻擊的上風,我們不可能通過技術手段杜絕網絡攻擊。國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰...

 
 
 
  引言   對一種編程語言而言,在設計這種語言的時候,一般是不會産生安全隱患的,事實上,這種隱患是由程序員引入的。幾乎每一種編程語言都有一定這樣的漏洞,這種漏洞將會在某種程度上導致不安全軟件的産生,但是一個如軟件整體的安全性仍然大部分依賴于這個軟件制造者的知識面、理解能力和他的安全意識。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」是含有」」標志的前綴,那麽它是爲輸出而打開的,並且在文件已經存在的時候覆蓋原文件;如果含有」」前綴,那麽是爲追加打開的;前綴」   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給子進程。」or」語句用來決定我們是在父進程還是在子進程。如果我們在父進程(返回值爲非零),我們繼續執行print()語句。否則我們在子進程中,就執行txt2html程序,使用多于一個參數的exec()的安全版本來避免傳遞任何命令到shell層。所發生的是,子進程答應txt2html産生的STDOUT輸出,然後就默默的消亡了(記住:exec()從不返回),同時父進程從STDIN中讀取結果。象這樣的技術可以被用來通過管道將輸出輸到一個外部程序的技術:   open (PROGRAM, "|-")   or exec ("/usr/bin/progname", "$userinput");   print PROGRAM, "This is piped to /usr/bin/progname";   在我們需要管道的時候,open()的以上這些形式應該總是比直接的管道open()命令優先采用,因爲它們不通過shell層。現在讓我們設想我們要將靜態文本轉化成格式化很好的HTML頁面,並且,基于方便考慮,要存放在顯示這些頁面的Perl腳本相同的目錄下。那麽我們的open語句看起來可能是如下形式:   open (STATFILE, "   當用戶通過表單中傳遞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」的話就會顯示這個文件,可能並沒有這個文件,即使有也不是很有用。但是如果用"statscript./pusername=statscript。p/%"來調用腳本,會發生什麽呢?如果腳本和我們的html文件在同一個目錄下的話,這樣我們可以用這   
󰈣󰈤
 
 
 
  免責聲明:本文僅代表作者個人觀點,與王朝網路無關。王朝網路登載此文出於傳遞更多信息之目的,並不意味著贊同其觀點或證實其描述,其原創性以及文中陳述文字和內容未經本站證實,對本文以及其中全部或者部分內容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,並請自行核實相關內容。
 
 
夏末午後的美麗女生
天生麗質_唯美動人
清新素雅的靓麗女生
完美絕倫_秀色可餐
芙蓉古鎮(一)
就是不一樣的街燈&#;
百態
荷一組(三張)
 
>>返回首頁<<
 
 熱帖排行
 
 
 
 
© 2005- 王朝網路 版權所有