■ 河南 許紅軍
編者按: 對于很多網站來說,都提供了文件上傳功能,允許用戶上傳圖片等文件,實現和其他人的互動。但是,這一功能也成了黑客等不法之徒覬覦的目標。黑客往往利用目標網站存在的各種漏洞來上傳各種非法文件,進而對網站進行滲透攻擊。在很多實際的案例中,都可以看到正是因為存在上傳漏洞,黑客才可以很輕松的發起攻擊,因此,對文件上傳進行嚴格的管控,對于提高網站的安全性是極為重要的。
和文件上傳相關的安全威脅包括以下類型,例如針對文件上傳的DoS攻擊,就是利用文件上傳功能,上傳大量的文件,來極大的占用服務器
的存儲和帶寬資源。黑客還會利用特殊方法,將非法文件(例如腳本等)傳輸上去,之后在服務器上運行惡意腳本。當然,黑客還可以將惡意文件上傳到服務器上,之后通過各種方法誘導用戶下載,當用戶下載后,黑客就可以利用跨站腳本攻擊等方法,來對網站進行滲透。
對于第一種攻擊類型來說,黑客會使用Web應用的上傳功能,連續發送體積巨大的文件,這就會導致目標網站負荷過載,從而形成拒絕服務。
應對這種攻擊方式,可以采用各種方式加以化解。例如對于PHP類型的網站來說,可以在“php.ini”文件中設置允許上傳的最大容量,執行“vim /etc/php.ini” 命令,在其中的“file_uploads=”的值設置為“Off”,就會取消上傳功能。
在“u p l o a d_m a x_filesize =”欄中設置單個文件的最大上傳容量(例如“100K”), 在“max_file_uploads =”欄中設置單次請求最大文件上傳數量,在“post_max_size =”欄中設置POST請求正文的最大限制,一般來說上傳文件使用的都是POST方法來實現的。在“memory_limit =”欄 中設置腳本所能申請到的最大內存值。
當 然,利 用Apache的“httpd.conf”文件,也可以限制請求正文的最大字節數,通過前期的檢查可以將不合法的請求拒絕掉,繼而可以有效提高防御DoS的能力。
執行“vim /etc/httpd/conf/https.conf” 命 令,在 對 應 的“” 欄中取消“LimitRequestBody 102400”行前面的“#”號,將該行配置激活,其中的“xxx”為具體的Web路徑。執行“systemcrl restart httpd”命令,重啟Apache。
這樣,在執行上傳操作時,文件大量就不能超過預設值(默認為100KB)。
對于非法上傳惡意腳本來說,其正是利用了服務器端配置上的某些漏洞來實現的。
因為對于有些文件上傳的處理方式來說,會將用戶上傳的文件保存到Web服務器的公開目錄中。如果應用中允許上傳的文件擴展名為php、asp、aspx、jsp等腳本文件,黑客就可以將上傳的文件作為腳本在服務器上運行。
這樣,黑客就可以執行瀏覽,修改和刪除Web服務器上的文件,甚至以此為跳板來攻擊其他的服務器。
應對的方法是禁止將上傳的文件保存到公開的目錄中,防止用戶直接查看到具體的訪問鏈接,而應該將其保存到比較隱藏的目錄中,當上傳之后,禁止顯示具體的鏈接地址,即必須通過特定的腳本才可以訪問上傳的文件,總之禁止在服務器上直接執行上傳的文件。
還可以將文件的擴展名設置為不可執行的腳本文件,即禁止上傳腳本類型的文件,當然這只是輔助性質的,因為限制文件擴展名是很可能存在疏漏的。
最關鍵的是不能將上傳文件保存在公開目錄中,因為在公開目錄中是可以執行腳本的。
例如在設計網站程序時,需要針對上傳的文件進行嚴格的檢測。例如在PHP網站中,可以定義一個名為專門的函數對此進行檢測,例如輸入諸如“define('UPLOADPATH', '/var/upload')”之類的語句,定義上傳路徑,注意其不能為公開目錄。
輸入:
“function check_upfile($scfile) {”
“$i n f o=p a t h i n f o($scfile);”
“?$ext= strtolower($info['extension'])”
“if ($exe != 'png'&&$exe != 'jpg' &&$exe !='bmp' ) {”
“die ('只能上傳指定格式的圖片文件!');”
“}”
“$count=0;”
“do {”
“$file=sprintf('%s/%08x.%s',UPLOADPATH,mt_rand(),$ext);”
“$fp-@fopen === FALSE&& ++$count < 10);”
“if ($fp === FALSE) {”
“die('無法生成文件!');”
“}”
“fclose($fp);”
“return $file;”,“}”等語句,創建所需的函數來檢測上傳的文件。這里的“$scfile”代表上傳的文件,首先分析和提取上傳文件的路徑信息,并獲取其規格化的擴展名,如果擴展名不符合要求(這里只能為圖片文件),則彈出警告信息。
之后通過一個循環,在指定的上傳路徑下創建名稱為隨機的文件,如果其可以順利打開的話,則說明創建成功,之后返回該文件名,該文件名中包含了絕對路徑信息。
之后執行:
“$scfile= check_upfile($realfile)”
“if(! move_uploaded_file($tmpfile,$scfile)){”
“die('文件不能上傳!');”
“}”等語句,將上傳的而原始文件寫入到上述文件中,“realfile”表示原始文件名。
這樣,就將其存儲到了非公開的路徑中。當用戶需要查看上傳的文件時,不能讓其直接獲取到實際的路徑,而必須通過特定的腳本來讀取,并將讀取的信息返回給用戶。
例 如 輸 入“$imgurl='g i v e t o u s e r f i l e.php?file=',basename($scfile);”語句,調用專用的腳本來讀取上傳的文件,并獲取對應的文件路徑信息。
其 中“givetouserfile.php”腳本就是用來獲取上傳文件信息的。
其內容為:
“
“define('UPLOADPATH','/var/upload');”
“$mimes=array('jpg'=>'image/jpeg','png'=>'image/png','bmp'=>'image/bmp');”
“$f i l e=$_G E T['file'];”
“$i n f o=p a t h i n f o($file);”
“$ext=strtolower($info['extension']);”
“$c o n t e n t_type=$mimes[$ext];”
“if (! $content_type){”
“die('上傳格式錯誤!');}”
“header('Content-Type: '. $content_type);”
“readfile(UPLOADPATH. '/ .basename($file));”
“?>”等行,其作用是將傳遞的文件名進行分析,來提取其擴展名,并找到擴展名對應的鍵值,如果找到的話,說明文件類型合規,然后就讀取其內容,并將其寫入到HTTP數據包中返回給用戶。
并 通 過“
但是,用戶無法了解其實際的路徑。這樣就從限制文件格式,存儲到非公開目錄,不顯示具體鏈接等方面保證了上傳文件的安全。即使用戶上傳了非法文件,也是無法訪問和執行的。
當然,這里只是使用了簡單的代碼進行示例性的說明。
對于黑客來說,為了實現對客戶機進行攻擊,往往會采取上傳包含有惡意代碼的圖片或者PDF文檔等方式,來誘使用戶進行下載,當用戶下載了看似正常的文件后,在進行瀏覽時就會激活其中隱藏的惡意代碼,從而可對Web服務器造成安全威脅。
對于這種狡猾的“迂回”攻擊策略,需要引起管理員的重視。
例如如果網站存在會話管理或者認證機制的話,當黑客實現了攻擊后,網站的SessionID和Cookie信息就會泄露出去,黑客就可借此進行認證,從而偽裝用戶身份進行非法操作。
當因為在用戶下載某些文件時,瀏覽器有時并不能正確識別文件的類型,例如黑客會上傳數據中包含HTML標簽的圖片文件,導致瀏覽器誤認為其是HTML文件,當在瀏覽器中進行查看時就會觸發其中的惡意JavaScript代碼。
為了防止這種攻擊行為,需要正確設置文件的Content-Type類型信息,這一點非常重要。對上傳的文件進行檢測,保證文件擴展名和內容保持一致。
例如對于JPG文件來說,必須確保其擴展名和文件頭信息匹配。為了避免在瀏覽器中直接執行文件,而僅僅是下載操作的話,需要在響應頭中指定“Content-Disposition:attachment”參數信息。
運行“regedit.exe”程序,在注冊表編輯器中打開“HKEY_CLASSES_ROOTMIMEDatabaseContent Type”分支,在其中顯示IE可以處理的所有Content-Type類型,例如對于擴展名為“.pdf”的文件來說,其Content-Type的 類 型 為“application/pdf”。
當IE接收到非圖片類型的文件時,就會在注冊表的上述位置查找與其對應的Content-Type信息,如果服務器端發送的Content-Type信息在本地找不到的話,IE就會根據具體URL地址中的擴展名進行判斷。而如果攻擊者在構建URL地址時惡意添加了某些特定的信息,最終IE就會根據這些信息認為是一個HTML文件而加以執行。
例如黑客會在特制的PDF文件中嵌入JavaScript代碼,之后利用網站設計上的漏洞(例如程序員使用了過時的Content-Type類型等),并以此構建惡意的訪問鏈接,導致用戶訪問該鏈接而進行跨站攻擊。
對于此類安全威脅,可以在上傳和下載兩個環節進行管控。
對于上傳來說,需要檢測文件擴展名是否在允許的范圍內,對于圖片文件需要確認其文件頭信息。
例如對于PHP來說,可以定義一個函數來進行執行檢測。
例如輸入:
“ function checktype($imgfile,$scfile){”
“$i n f o=p a t h i n f o($scfile);”
“$ext=strtolower($inf o['extension']);”
“if ($ext != 'png' &&$ext != 'jpg' && $ext !='gid'){”
“die('上傳的文件是非法的!')”
“$imginfo=getimagesiz e($imgfile);”
“$type=$imginfo[2];”
“if ($ext=='gif' &&$type==IMAGETYPE_GIF)return;”
“if ($ext=='jpg' &&$type==IMAGETYPE_JPEG)return;”
“if ($ext=='png' &&$type==IMAGETYPE_PNG)return;”
“die('圖片格式存在問題!')}”等語句。利用這些程序,可以對指定的文件進行檢測。如果其格式和類型存在問題,就顯示警告信息。
之后使用:
“c h e c k_i m a g e_t y o p e($t m p f i l e,$realfile);”
“$s c f i l e=c h e c k_upfile($realfile)”
“$scfile= check_upfile ($realfile)”
“if(! move_uploaded_file($tmpfile,$scfile)){”,“die(' 文 件 不 能 上傳!');}”等語句,來調用該函數,執行檢測上傳的圖片類型,文件格式以及存儲到非公開目錄等操作。
在下載文件時,需要正確設置Content-Type類型信息,針對圖片文件需要檢測文件頭,在有些時候,需要在響應頭中指定“Content-Disposition:attachment”參數信息。
如果在下載的時候,沒有經過預設的腳本進行處理,就直接可以在Web服務器上的公開目錄上出現的話,就說明服務器端配置存在一定的的問題。
例如對于Apache來說,和Content-Type信息相關的設置保存在名為“mime.types”的文件之中,需要對其進行檢測,來查看是否存在錯誤的Content-Type信息。
因為Apache是基于文件擴展名,來產生相應的Content-Type信息的。在下載圖片文件時,依然需要對其文件頭進行校驗,可以有效提高安全性。
為了避免在瀏覽器中直接執行文件,而僅僅將其下載到本地,可以在響應消息頭中執行“Content-Disposition:attachment”,或者將Content-Type設 置 為“application/octetstream”,就可以實現單純的下載操作。
例如對于PDF來說,可在網站程序中使用上述“givetouserfile.php” 腳本,所不同的是在其中將的“$mimes=array”行內容修改 為“$mimes=array('pdf'=>'application/octetstream')”。
并且在尾部添加:
“header('Content-Disposition: attachment;filename="'.basename($file).'" ');”
“readfile($path)”等語句,來設置只用于下載的文件信息。
這樣當瀏覽器處理時就直接進行下載了。