本文所討論的安全性環境是在Linux+Apache+Mysql+PHP。超出此範圍的安全性問題不在本文範疇之內。
一、apache server安全性設定
1、以Nobody使用者運行
一般情況下,Apache是由Root 來安裝和啟動並執行。如果Apache Server進程具有Root使用者特權,那麼它將給系統的安全構成很大的威脅,應確保Apache Server進程以最可能低的許可權使用者來運行。通過修改httpd.conf檔案中的下列選項,以Nobody使用者運行Apache 達到相對安全的目的。
User nobody
Group# -1
2、ServerRoot目錄的許可權
為了確保所有的配置是適當的和安全的,需要嚴格控制Apache 主目錄的存取權限,使非超級使用者不能修改該目錄中的內容。Apache 的主目錄對應於Apache Server設定檔httpd.conf的Server Root控制項中,應為:
Server Root /usr/local/apache
3、SSI的配置
在設定檔access.conf 或httpd.conf中的確Options指令處加入Includes NO EXEC選項,用以禁用Apache Server 中的執行功能。避免使用者直接執行Apache 伺服器中的執行程式,而造成伺服器系統的公開化。
Options Includes Noexec
4、阻止使用者修改系統設定
在Apache 伺服器的設定檔中進行以下的設定,阻止使用者建立、修改 .htaccess檔案,防止使用者超越能定義的系統安全特性。
AllowOveride None
Options None
Allow from all
然後再分別對特定的目錄進行適當的配置。
5、改變Apache 伺服器的預設訪問特性
Apache 的預設設定只能保障一定程度的安全,如果伺服器能夠通過正常的映射規則找到檔案,那麼用戶端便會擷取該檔案,如http://local host/~ root/ 將允許使用者訪問整個檔案系統。在伺服器檔案中加入如下內容:
order deny,ellow
Deny from all
將禁止對檔案系統的預設訪問。
6、CGI指令碼的安全考慮
CGI指令碼是一系列可以通過Web伺服器來啟動並執行程式。為了保證系統的安全性,應確保CGI的作者是可信的。對CGI而言,最好將其限制在一個特定的目 錄下,如cgi-bin之下,便於管理;另外應該保證CGI目錄下的檔案是不可寫的,避免一些詐騙程式駐留或混跡其中;如果能夠給使用者提供一個安全性 良好的CGI程式的模組作為參考,也許會減少許多不必要的麻煩和安全隱患;除去CGI目錄下的所有非業務應用的指令碼,以防異常的資訊洩漏。
7、SSL連結加密
以上這些常用的舉措可以給Apache Server 一個基本的安全運行環境,顯然在具體實施上還要做進一步的細化分解,制定出符合實際應用的安全配置方案。
二、PHP安全性設定
伺服器並不能阻止所有的安全問題,例如程式漏洞問題、使用者輸入表單問題、PHP檔案許可權問題等。
也可以通過一些手段來迷惑駭客或者別有用心者。
1、程式碼漏洞問題
很多 PHP 程式所存在的重大弱點並不是 PHP 語言本身的問題,而是編程者的安全意識不高而導致的。因此,必須時時注意每一段代碼可能存在的問題,去發現非正確資料提交時可能造成的影響。
?
123456 |
<?phpunlink ($evil_var);fwrite ($fp, $evil_var);system ($evil_var);exec ($evil_var);?> |
必須時常留意你的代碼,以確保每一個從用戶端提交的變數都經過適當的檢查,然後問自己以下一些問題:
- 此指令碼是否只能影響所預期的檔案?
- 非正常的資料被提交後能否產生作用?
- 此指令碼能用於計劃外的用途嗎?
- 此指令碼能否和其它指令碼結合起來做壞事?
- 是否所有的事務都被充分記錄了?
在寫代碼的時候問自己這些問題,否則以後可能要為了增加安全性而重寫代碼了。注意了這些問題的話,也許還不完全能保證系統的安全,但是至少可以提高安全性。
還可以考慮關閉 register_globals,magic_quotes 或者其它使編程更方便但會使某個變數的合法性,來源和其值被搞亂的設定。
2、使用者輸入表單問題
驗證使用者輸入的任何資料,保證PHP代碼的安全。
注意1:JS只是為了提高來訪使用者的體驗而產生的,而不是驗證的工具。因為任何一個來訪的使用者都可能會,也有可能無意間就禁用了用戶端指令碼的執行,從而跳過這層驗證。所以我們必須在PHP的伺服器端程式上檢驗這些資料。
注意2:不要使用$_SERVER['HTTP_REFERER']這個超級變數來檢查資料的來源地址,一個很小的菜鳥駭客都會利用工具來偽造這個變數的資料,儘可能利用Md5,或者rand等函數來產生一個令牌,驗證來源的時候,驗證這個令牌是否匹配。
3、PHP檔案許可權問題
PHP 被設計為以使用者層級來訪問檔案系統,所以完全有可能通過編寫一段 PHP 代碼來讀取系統檔案如 /etc/passwd,更改網路連接以及發送大量列印任務等等。因此必須確保 PHP 代碼讀取和寫入的是合適的檔案。 請看下面的代碼,使用者想要刪除自己主目錄中的一個檔案。假設此情形是通過 web 介面來管理檔案系統,因此 Apache 使用者有權刪除使用者目錄下的檔案。
?
1234567 |
<?php$username = $_POST['user_submitted_name'];$homedir = "/home/$username";$file_to_delete = "$userfile";unlink ("$homedir/$userfile");echo "$file_to_delete has been deleted!";?> |
既然 username 變數可以通過使用者表單來提交,那就可以提交別人的使用者名稱和檔案名稱,並刪除該檔案。這種情況下,就要考慮其它方式的認證:
- 只給 PHP 的 web 使用者很有限的許可權。
- 檢查所有提交上來的變數。
以下是更加安全的檔案名稱和變數的驗證和檢查:
?
12345678910 |
<?php$username = $_SERVER['REMOTE_USER'];$homedir = "/home/$username"; if (!ereg('^[^./][^/]*$', $userfile))die('bad filename'); if (!ereg('^[^./][^/]*$', $username))die('bad username');?> |
4、隱藏PHP副檔名
一般而言,通過隱藏的手段提高安全性被認為是作用不大的做法。但某些情況下,儘可能的多增加一份安全性都是值得的。
一些簡單的方法可以協助隱藏 PHP,這樣做可以提高攻擊者發現系統弱點的難度。在 php.ini 檔案裡設定 expose_php = off ,可以減少他們能獲得的有用資訊。
另一個策略就是讓 網頁伺服器用 PHP 解析不同副檔名。無論是通過 .htaccess 檔案還是 Apache 的設定檔,都可以設定能誤導攻擊者的副檔名:
# 使PHP看上去像其它的程式設計語言
AddType application/x-httpd-php .asp .py .pl
# 使 PHP 看上去像未知的檔案類型
AddType application/x-httpd-php .bop .foo .133t
# 使 PHP 代碼看上去像 HTML 頁面
AddType application/x-httpd-php .htm .html
要讓此方法生效,必須把 PHP 檔案的副檔名改為以上的副檔名。這樣就通過隱藏來提高了安全性,雖然防禦能力很低而且有些缺點。
三、Mysql資料庫安全性設定
PHP 本身並不能保護資料庫的安全。下面的章節只是講述怎樣用 PHP 指令碼對資料庫進行基本的訪問和操作。記住一條簡單的原則:深入防禦。保護資料庫的措施越多,攻擊者就越難獲得和使用資料庫內的資訊。正確地設計和應用程式資料庫可以減少被攻擊的擔憂。
1、資料庫設計問題
應用程式永遠不要使用資料庫擁有者或超級使用者帳號來串連資料庫,因為這些帳號可以執行任意的操作,比如說修改資料庫結構(例如刪除一個表)或者清空整個資料庫的內容。以下截圖的使用者佈建是危險的。
應該為程式的每個方面建立不同的資料庫帳號,並賦予對資料庫物件的極有限的許可權。僅分配給能完成其功能所需的許可權,避免同一個使用者可以完成另一個使用者的事情。這樣即使攻擊者利用程式漏洞取得了資料庫的存取權限,也最多隻能做到和該程式一樣的影響範圍。
2.資料庫連接問題
把串連建立在 SSL 加密技術上可以增加用戶端和伺服器端通訊的安全性,或者 SSH 也可以用於加密用戶端和資料庫之間的串連。如果使用了這些技術的話,攻擊者要監視伺服器的通訊或者得到資料庫的資訊是很困難的。
3.資料庫資料的加密
SSL/SSH 能保護用戶端和伺服器端交換的資料,但 SSL/SSH 並不能保護資料庫中已有的資料。SSL 只是一個加密網路資料流的協議。
如果攻擊者取得了直接存取資料庫的許可(繞過 網頁伺服器),敏感性資料就可能暴露或者被濫用,除非資料庫自己保護了這些資訊。對資料庫內的資料加密是減少這類風險的有效途徑,但是只有很少的資料庫提供這些加密功能。
對於這個問題,有一個簡單的解決辦法,就是建立自己的加密機制,然後把它用在 PHP 程式內,最常見的例子就是把密碼經過 MD5 加密後的散列存進資料庫來代替原來的純文字密碼。
?
123456789101112131415 |
<?php$query = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",addslashes($username), md5($password));$result = pg_query($connection, $query); $query = sprintf("SELECT 1 FROM users WHERE name='%s' AND pwd='%s';",addslashes($username), md5($password));$result = pg_query($connection, $query); if (pg_num_rows($result) > 0) {echo 'Welcome, $username!';} else {echo 'Authentication failed for $username.';}?> |
4、SQL注入問題
直接 SQL 命令注入就是攻擊者常用的一種建立或修改已有 SQL 陳述式的技術,從而達到取得隱藏資料,或覆蓋關鍵的值,甚至執行資料庫主機作業系統命令的目的。這是通過應用程式取得使用者輸入並與靜態參數組合成 SQL 查詢來實現的。下面將會給出一些真實的例子。
?
12345678 |
<?php $query = "SELECT id, name, inserted, size FROM productsWHERE size = '$size'ORDER BY $order LIMIT $limit, $offset;";$result = odbc_exec($conn, $query); ?> |
可以在原來的查詢的基礎上添加另一個 SELECT 查詢來獲得密碼:
union select '1', concat(uname'-'passwd) as name, '1971-01-01', '0' from usertable;
假如上述語句(使用 ' 和 --)被加入到 $query 中的任意一個變數的話,那麼就麻煩了。
這些攻擊總是建立在發掘安全意識不強的代碼上的。所以,永遠不要信任外界輸入的資料,特別是來自於用戶端的,包括選擇框、表單隱藏欄位和 cookie。就如上面的第一個例子那樣,就算是正常的查詢也有可能造成災難。
一個更安全的防止SQL注入的分頁顯示方法:
?
12345678 |
<?php settype($offset, 'integer');$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",$offset); ?> |