PHP安全-文件名操縱
在很多情形下會使用動態(tài)包含,此時目錄名或文件名中的部分會保存在一個變量中。例如,你可以緩存你的部分動態(tài)頁來降低你的數(shù)據(jù)庫服務(wù)器的負(fù)擔(dān)。
<?php
include '/cache/{$_GET[’username’]}.html';
?>
為了讓這個漏洞更明顯,示例中使用了$_GET。如果你使用了受污染數(shù)據(jù)時,這個漏洞同樣存在。使用$_GET[’username’]是一個極端的例子,通過它可以把問題看得更清楚。
雖然上面的流程有其優(yōu)點(diǎn),但它同時為攻擊者提供了一個可以自由選擇緩存頁的良機(jī)。例如,一個用戶可以方便地通過編輯URL中的username的值來察看其他用戶的緩存文件。事實上,攻擊者可以通過簡單的更改username的值為相應(yīng)的文件名(不加擴(kuò)展名)來察看/cache目錄下的所有擴(kuò)展名為.html的文件。
http://example.org/index.php?username=filename
盡管該程序限制了攻擊者所操作的目錄和文件名,但變更文件名并不是唯一的手段。攻擊者可以創(chuàng)造性地達(dá)到在文件系統(tǒng)中進(jìn)行跨越的目的,而去察看其他目錄中的.html文件以發(fā)現(xiàn)敏感信息。這是因為可以在字串使用父目錄的方式進(jìn)行目錄跨越:
http://example.org/index.php?username=../admin/users
上面URL的運(yùn)行結(jié)果如下:
<?php
include '/cache/../admin/users.html';
?>
此時,..意味著/cache的父目錄,也就是根目錄。這樣上面的例子就等價于:
<?php
include '/admin/users.html';
?>
由于所有的文件都會在文件系統(tǒng)的根目錄下,該流程就允許了一個攻擊者能訪問你服務(wù)器上所有的.html文件。
在某些平臺上,攻擊者還可以使用一個NULL來終止字符串,例如:
http://example.org/index.php?username=../etc/passwd%00
這樣就成功地繞開了.html文件擴(kuò)展名的限制。
當(dāng)然,一味地去通過猜測攻擊者的所有惡意攻擊手段是不可能的,無論你在文件上加上多少控制,也不能排除風(fēng)險。重要的是在動態(tài)包含時永遠(yuǎn)不要使用被污染數(shù)據(jù)。攻擊手段不是一成不變的,但漏洞不會變化。只要通過過濾數(shù)據(jù)即可修復(fù)這個漏洞(見第一章):
<?php
$clean = array();
/* $_GET[’filename’] is filtered and stored in $clean[’filename’]. */
include '/path/to/{$clean[’filename’]}';
?>
如果你確認(rèn)參數(shù)中只有文件名部分而沒有路徑信息時,另一個有效的技巧是通過使用basename( )來進(jìn)行數(shù)據(jù)的過濾:
<?php
$clean = array();
if (basename($_GET[’filename’] == $_GET[’filename’])
{
$clean[’filename’] = $_GET[’filename’];
}
include '/path/to/{$clean[’filename’]}';
?>
如果你允許有路徑信息但想要在檢測前把它化簡,你可以使用realpath()函數(shù):
<?php
$filename = realpath('/path/to/{$_GET[’filename’]}');
?>
通過上面程序處理得到的結(jié)果($filename)可以被用來確認(rèn)是否位于/path/to目錄下:
<?php
$pathinfo = pathinfo($filename);
if ($pathinfo[’dirname’] == ’/path/to’)
{
/* $filename is within /path/to */.
}
?>
如果檢測不通過,你就應(yīng)該把這個請求記錄到攻擊日志以備后查。這個在你把這個流程作為深度防范措施時特別重要,因為你要確定其它的安全手段失效的原因。
相關(guān)文章:
