污染模式
Perl中的一些特性可以幫助你寫出安全的程序。當然這些手段無法取代細致的思考和規(guī)劃,但是能幫助你避免一些微妙的錯誤。
所謂污染模式就是對所有來自程序之外數(shù)據(jù)附加上一個元數(shù)據(jù)以便來跟蹤它們。從被污染的數(shù)據(jù)(臟數(shù)據(jù))中生成出來的數(shù)據(jù)也是被污染的。你可以在程序中使用被污染的數(shù)據(jù),但是如果使用臟數(shù)據(jù)會影響程序之外的內容(不安全的使用方式),Perl就會拋出致命異常。
使用污染模式
perldoc perlsec介紹了污染模式的具體細節(jié)。
使用命令行參數(shù)-T就會啟動污染模式。如果-T寫在#!行當中,就必須直接運行程序,如果你忽略-T標志使用perl mytaintedappl.pl來啟動程序,Perl就會拋出異常并退出。
污染源
污染來自2個地方:文件輸入和程序環(huán)境。前者就是指你從文件讀到的或從網(wǎng)站、網(wǎng)絡用戶那收集到的內容。后者包括所有的命令行參數(shù)、環(huán)境變量和來自于系統(tǒng)調用的數(shù)據(jù),甚至從目錄句柄中讀取到的數(shù)據(jù)也是被污染的。
核心模塊Scalar::Util中的函數(shù)tainted()用于測試是否被污染,如果參數(shù)是被污染的就返回真:
die 'Oh no! Tainted data!' if Scalar::Util::tainted( $suspicious_value );
從數(shù)據(jù)中解除污染
要凈化數(shù)據(jù)你就必須精確地提取數(shù)據(jù)中好的部分。比如如使用正則表達式來捕獲,捕獲到的數(shù)據(jù)就是干凈數(shù)據(jù)。例如,如用戶輸入中包含電話號碼,你可以這樣解除污染:
die 'Number still tainted!' unless $number =~ /(\(/d{3}\) \d{3}-\d{4})/;
my $safe_number = $1;
匹配的模式越細致,你的程序就越安全。相反的做法是拒絕指定的項目或忽略風險而運行。當然你也可以捕獲整個值來解除污染,但是這樣就失去了使用污染模式的價值。
從環(huán)境中解除污染
全局變量%ENV里面有程序所在系統(tǒng)的環(huán)境變量。該變量是被污染的,原因是程序之外的力量可以操縱該值。環(huán)境變量控制著Perl或shell如何定位文件和目錄,這也是一個攻擊向量。一個安全敏感的程序應該刪除%ENV中的一些鍵,并且設置$ENV{PATH}到一個安全的路徑:
delete @ENV{ qw( IFS CDPATH ENV BASH_ENV ) };
$ENV{PATH} = '/path/to/app/binaries/';
如果$ENV{PATH}設置的不當就會收到報告其不安全的消息。如果環(huán)境變量包含了當前工作目錄,或者包含了相關目錄,或者指定的目錄是全局可寫的權限,那么聰明的攻擊者就可以劫持系統(tǒng)調用來進行惡意攻擊。
出于類似的原因,@INC在污染模式下并不包含當前工作目錄。Perl也會忽略PERL5LIB和PERLLIB環(huán)境變量。使用lib編譯指示或者使用-l標志來添加庫目錄到程序。
常見陷阱
污染模式只有打開和關閉2種狀態(tài),也就是要么全有要么全無。有時候需要部分解除污染的時候,就會有人過度放開(比如之前的全面捕獲),這時候污染模式就沒有起到應有的作用,所以要仔細審查污染解除的規(guī)則。
不幸的是,并不是所有模塊都會妥善處理被污染的數(shù)據(jù),CPAN作者應認真對待這個BUG。如果面對的是歷史遺留代碼,你可以考慮使用-t標志,這個標志會啟用污染模式但是會將違規(guī)的告警從異常降為警告(也就是不再退出),但這個并不是完整的污然模式。(在不能使用完整污染模式下的一種折中方案)