程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言基礎知識 >> Linux 和 Unix 安全編程:環境變量

Linux 和 Unix 安全編程:環境變量

編輯:C語言基礎知識

  環境變量
   缺省情況下,環境變量從進程的父進程繼續而來。但是,在程序執行另一個程序時,調用程序可以把環境變量設置為任意值。這對setuid/setgid程序而言很危險,因為其入侵者可以完全控制它們得到的環境變量。由於環境變量一般是繼續來的,同樣可以傳遞使用;安全程序可能調用某些其它程序,在沒有非凡措施的情況下,這會把有潛在危險的環境變量值傳遞給調用的程序。
  
   有些環境變量是危險的
   有些環境變量是危險的,因為很多庫和程序被環境變量以某些隱含、模糊或未公開的方式所控制。例如,sh和bash shell使用IFS變量來決定哪個字符被用來分隔命令行參數。由於shell是被若干底層調用(如C中的system(3)和popen(3),或Perl中的back-tick算符)執行的,把IFS設置為不平常的值就會攪亂那些看起來安全的調用。該行為在bash和sh裡有說明,但不引人注目;許多長時間的用戶知道IFS,只不過是因為了解IFS可用來破壞安全性,而不是因為有意經常使用的緣故。更糟的是,不是所有的環境變量都有文檔說明,而且即使有,其它的程序也可以改變和增加危險的環境變量。所以唯一的真正解決方案(下文有描述)是只選擇所需要的環境變量,不理會其余的環境變量。
  
   環境變量的存儲格式是危險的
   一般來說,程序應該使用標准的訪問例程來訪問環境變量。例如,在C裡應使用getenv(3)獲取環境變量的值,使用POSIX標准例程putenv(3)或BSD擴展setenv(3)來設置環境變量的值,使用unsetenv(3)來清除環境變量。需要說明的是,Linux下也實現了setenv(3)。但黑客不會這麼善良;黑客可以用execve(2)直接控制傳遞給程序的環境變量數據區。這就可能進行一些骯髒的攻擊,只有那些了解環境變量工作實質的人才能理解這些攻擊。在Linux下可以閱讀environ(5)來了解環境變量工作實質的概要。簡而言之,環境變量在內部作為一個指向字符的指針數組的指針來存儲;該數組按順序存儲並以NULL指針結尾(這樣就可以知道何時數組結束)。指向字符的指針每個都依次指向一個形式為“NAME=value”的以NIL結尾的字符串值。這包含若干意義,例如,環境變量名不能包含等號,而且name或value都不能含有NIL字符。但是,這種格式有一個很危險的含義,就是答應多個入口使用同一個變量名而值不同(如SHELL有多個值)。雖然典型的命令shell禁止這麼做,本地操作的黑客可以使用execve(2)制造出這樣的情況來。
  
   這種存儲格式(以及設置方式)的問題在於程序可能會檢查某個值(看看是否合法)而實際上使用的卻是另一個不同的值。在Linux下,GNU的glibc庫試圖保護程序免受此影響:在實現glibc 2.1的getenv時,總是獲取第一個匹配的入口,setenv和putenv總是設置第一個匹配的入口,而unsetenv實際上會清除所有匹配入口的設置(應該祝賀GNU的glibc實現者如此實現unsetenv!)。但是,有些程序直接訪問環境變量,重復遍歷所有環境變量;在這種情況下,它們可能會使用最後一個匹配的入口,而不是第一個。其結果就是假如檢查的是第一個匹配的入口,但實際使用的是最後一個匹配的入口,黑客就可以以此來繞過保護例程。
  
   解決方案 -- 提取和清除
   對於安全的setuid/setgid程序,應該小心提取需要作為輸入(假如需要的話)的簡短的環境變量列表。然後應該清除整個環境,再重新設置一小組必需的環境變量作為安全的值。假如調用了下一級的程序,這實際上並不是什麼更好的辦法;因為沒有可行的辦法來列出“所有的危險值”。即使對直接或間接調用的每一個程序的源碼都進行了仔細檢閱,還是有人可以在你編寫完代碼後加入新的未公開的環境變量,其中就可能有一個可利用的環境變量。
  
   清除環境的簡單方式是把全局變量environ設置為NULL。全局變量environ在中定義,C/C++用戶需要#include該頭文件。在產生線程前需要處理該值,但這幾乎不成問題,因為在程序執行的開始階段就需要進行這些處理。另一個清除環境的方式是使用未公開的函數clearenv()。clearenv()有個希奇的歷史;有人建議在POSIX.1中定義它,但不知什麼原因它沒有進入標准。盡管如此,POSIX.9(綁定POSIX的Fortran 77)中定義了clearenv(),所以它具有了半官方的地位。clearenv()定義在,但在使用#include包含它之前,必須確定__USE_MISC已經#defined。
  
   一個幾乎可以確定會不斷添加的值是PATH,一個查找程序的目錄列表;PATH應該不包括當前目錄,一般應該像“/bin:/usr/bin”那樣簡單。一般還會設置IFS(其缺省值為“ ”)和TZ(時區)。假如不提供IFS或TZ,Linux也不會死機,但沒有TZ值時有些基於System V的系統會出問題,而且據傳言某些shell需要IFS值被設置。在Linux下,參見environ(5)以了解可能需要設置的通用環境變量列表。
  
   假如確實需要用戶提供的值,首先要檢查這些值(以保證這些值與合法值的模式相匹配,而且在某些合理的最大長度之內)。理想情況是在/etc下有些標准的可信賴文件,包含“標准的安全環境變量值”的信息,但是現在沒有為此目的定義的標准文件。與此相似,可能需要在那些具有PAM模塊的系統裡檢查PAM模塊的pam_env。
  
  
   假如采用不答應直接重新設置環境的語言編寫setuid/setgid程序,一個方法是建立一個“包裹”程序。包裹程序把環境程序設置為安全值,然後調用其它程序。注重:確定包裹程序會實際執行預期的程序;假如它是個解釋程序,要確定不會出現可能的競爭狀態,使得解釋器能夠載入另一個與授予了非凡的setuid/setgid權限的程序不同的程序。
  
   全文:www.linux.org.tw
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved