編寫PHP的安全性原則

來源:互聯網
上載者:User
安全|策略 PHP最初是被稱作Personal Home Page,後來隨著PHP成為一種非常流行的指令碼語言,名稱也隨之改變了,叫做Professional HyperText PreProcessor。以PHP4.2為例支援它的WEB伺服器有:Apache, Microsoft Internet information Sereve, Microsoft Personal web Server,AOLserver,Netscape Enterprise 等等。

PHP是一種功能強大的語言和解譯器,無論是作為模組方式包含到web伺服器裡安裝的還是作為單獨的CGI程式程式安裝的,都能訪問檔案、執行命令或者在伺服器上開啟連結。而這些特性都使得PHP運行時帶來安全問題。雖然PH P是特意設計成一種比用Perl或C語言所編寫的CGI程式要安全的語言,但正確使用編譯時間和運行中的一些配置選項以及恰當的應用編碼將會保證其啟動並執行安全性。

一、安全從開始編譯PHP開始。

在編譯PHP之前,首先確保作業系統的版本是最新的,必要的補丁程式必須安裝過。另外使用編譯的PHP也應當是最新的版本,關於PHP的安全性漏洞也常有發現,請使用最新版本,如果已經安裝過PHP請升級為最新版本:4.2.3

相關連結:http://security.e-matters.de/advisories/012002.html

安裝編譯PHP過程中要注意的3個問題:

1、只容許CGI檔案從特定的目錄下執行:首先把處理CGI指令碼的預設控制代碼刪除,然後在要執行CGI指令碼的目錄在http.conf 檔案中加入ScriptAlias指令。

#Addhadler cgi-script .cgi


ScriptAlias /cgi-bin/ "/usr/local/apache/cgi-bin/"

<Directory "/usr/local/apache/cgi-bin'>

AllowOverride None

Options None

Order allow,deny

Allow from all

</Directory>


<Directory "/home/*/public_html/cgi-bin">

AllowOverride None

Options ExecCGI

Order allow,deny

Allow from all

</Directory>




SriptAlias的第一個參數指明在Web中的可用相對路徑,第二個參數指明指令碼放在伺服器的目錄。應該對每個目錄

別名都用Directory,這樣可使得除系統管理員之外的人不知道Web伺服器上CGI指令碼的清單。

Directory允許使用者建立自己的CGI指令碼。也可用SriptAliasMatch,但Directory更容易使用。 允許使用者建立自己

CGI指令碼可能會導致安全問題,你可能不希望使用者建立自己的CGI。 Apache預設配置是注釋掉cgi?script的處理控制代碼,但有/cgi-bin目錄使用SriptAlias和Directory指令。 你也可禁止CGI執行,但仍允許執行PHP指令碼。

2.把PHP解析器放在web目錄外

把PHP解析器放在Web分類樹外是非常重要的做法。這樣可以防止web伺服器對PHP的解析器的濫用。特別是

不要把PHP解析器放在cgi-bin或允許執行CGI程式的目錄下。然而,使用Action解析指令碼是不可能的,因為用Action指令時,PHP解析器大多數要放在能夠執行CGI的目錄下只有當PHP指令碼作為CGI程式執行時,才能把PHP解析器放在Web分類樹之外。

如果希望PHP指令碼作為CGI程式執行(這們可以把PHP解析器放在Web分類樹之外),可以這樣:

( 1)所有的PHP指令碼必須位於能執行CGI程式的目錄裡。

( 2)指令碼必須是可執行檔(僅在UNIX/Linux機器裡)。

(3)指令碼必須在檔案頭包括PHP解析器的路徑。

你可用下面命令使PHP指令碼為可執行:

#chmod +x test.php4


這樣使在目前的目錄下的檔案名稱為test.PhP4的指令碼變為可執行。 下面是一個能作為CGI程式啟動並執行PHP腳的小例子。

#!/usr/local/bin/php

echo "This is a my small cgi program”


3. 按Apache模組方式安裝:

當將PHP作為Apache模組使用時,它將繼承Apche的使用者權限(一般情況下使用者為“nobody”)。這一點對於安全性和

驗證有不少影響。例如,使用PHP訪問資料庫,除非資料庫支援內建的存取控制,將不得不設定資料庫對於使用者“nobody”

的可存取權限。這將意味著惡意的指令碼在沒有訪問使用者名稱和密碼,也能訪問並修改資料庫。通過Apache驗證來保護資料不被暴露,或者也可使用LDAP、.htaccess檔案等設計自己的存取控制模型,並在PHP指令碼中將此代碼作為其中部分引入。 通常,一旦安全性建立,此處PHP使用者(此情形即Apache使用者)就風險大大降低了,會發現PHP護現在已被封鎖了將可能的染毒檔案寫入使用者目錄的能力。 此處最常犯的安全性錯誤是賦予Apache伺服器根(root)許可權。 將Apache使用者權限提升到根許可權是極端危險的。可能會危及整個系統,因此要小心使用sudo,chroot安全隱患大的命令等。除非你對安全有絕對的掌握,否則不要讓其以ROOT許可權運行。


二、讓PHP的使用更安全。

1、以安全模式運行PHP

以安全模式運行PHP是使PHP指令碼安全使用的好方法,特別是在允許使用者使用自己開發的PHP指令碼時。使用安全模式會使PHP在運行函數時檢查是否存在安全問題。 include、readfile、fopen、file、unlink、rmdir等等:被包含的檔案或者該檔案所在目錄的所有者必須是正在啟動並執行指令碼的所有者; Exec、System、Passthm等等:要執行的程式必須位於特定的目錄(預設為/usr/local/php/bin)。編譯PHP時可以用?with-exe-dir選項設定這個值。

Mysql?Connect:這個函數用可選的使用者名稱串連MySQL資料庫。在安全模式下,使用者名稱必須是當前被執行的指令碼的所有者,或運行httpd的使用者名稱(通常是nobody)。

HTTP Authentication:包含HTTP驗證代碼指令碼所有者的使用者ID(數字型)會自動加到驗證域。這樣可以防止有人通過抓取密碼的程式來欺騙同一個伺服器上的HTTP驗證指令碼。


2、使用 使用者識別和驗證

有時需要唯一地確認一個使用者。使用者通常由請求和響應系統確認。使用者名稱/口令組合就是這種系統的一個很好的例子,比如系統要求給出A1i的口令,響應的是Ali的口令。這樣驗證是因為只有Ali才知道這個口令。

(1)伺服器端使用者驗征

這是用於服務端上對PHP程式要求最小的驗證方法。只要讓Apache來管理對使用者的驗證就行了。

AuthName "Secret page" # The realm

AuthType Basic


# The password file has been placed outside the web tree

AuthUserFile /home/car2002/website.pw


<LIMIT GET POST>

require valid-user

</LIMIT>



你需要把上述檔案(檔案名稱為.htaccess)放在需要保護的地方。用Apache的htpasswd程式,可以建立包含使用者名稱和口令組合的檔案。把這個檔案放在Web分類樹之外,只讓該檔案的擁有者查看和修改這個檔案。當然,Web伺服器必須能夠讀取這個檔案。

如果想讀取被保護的目錄,Web伺服器要求瀏覽器提供使用者名稱和密碼。瀏覽器彈出對話方塊,使用者可以輸入他們的使用者名稱和密碼。如果使用者名稱和密碼與口令檔案中相符合,就允許使用者讀取被保護的頁面;反之,將得到錯誤頁面,告訴使用者沒有通過驗證。被保護的域會顯示出來以便使用者知道輸入那個使用者名稱和密碼。

(2)在PHP中進行使用者識別和驗證

和在Apache伺服器端進行使用者識別和驗證相比,在PHP進行使用者識別和驗證有以下優點:

A、可登出。

B、可失效。如使用者登入後40分鐘沒有瀏覽你的網站,你可強制他們重新通過驗證。

C、可定製。

D、可基於資料庫。你可以用儲存在各種各樣的資料庫裡的資料來驗證使用者,並且記錄訪問者訪問網站的詳細日誌。

E、可用於每個頁面。你可在每個頁面上決定是否需要驗證。

F、你也可以使瀏覽器彈出對話方塊。下面的例子顯示了怎樣從,MySQL資料庫中檢索用名和口令:讓使用者填人使用者名稱和口令。

<?

if(!isset($PHP_AUTH_USER)) {

Header("WWW-authenticate: basic realm="restricted area"");

Header( "HTTP/I.0 401 Unauthorized");

echo "You failed to provide the correct password... ";

exit;

} else {

mysql_select_db("users") ;

$user_id = strtolower($PHP^AUTH_USER);

$result = mysql_query("SELECT password FROM users " .

"WHERE username = '$username'") ;

$row = mysql_fetch_array($result) ;

if ($PHP_AUTH_PW != $row["password"]) {

Header( "WWW-authenticate: basic realm="restricted area"

Header( "HTTP/I.0 401 Unauthorized");

echo "You failed to provide the correct password... " ;

exit;

}

}

?>

Only users with a working username/password combination can see this




(3) 檢測IP地址

一般人們普遍認為一個IP地址唯一地確定一個訪問者。但實際上並不是這樣的。Proxy 伺服器可用相同的IP地址發送不同使用者的請求。另外IP地址的盜用也普遍存在。檢測 IP地址有它們的用處,但相當有限。例如你是一個論壇版主,你發現某個使用者粘貼一些不健康的、違法的內容。你可以找到他的IP地址,把從這個IP連進來的使用者逐出論壇。使用下面一行命令將會得到某個特定請求的源IP地址:

# ip = $REMOTE_ADDR


4、使用PHP加密技術

在PHP中,加密技術主要用來加密資訊、產生校正和和摘要。使用加密技術可大大地增強安全效能。 這裡只講述使用加密技術的一些概念。如果你想進一步瞭解,應參考一些好的加密技術資料。加密技術的標準是Bmce Schneier的應用加密技術,非常值得一讀。他的網站(www.counterpane.com/labs.html )是在互連網上尋找加密技術資料的好起點。資料加密是一個非常複雜的話題,這裡只簡單介紹一下。

PHP中大多數的加密函數由mcrypt庫和mhash庫提供。你需要在系統中裝上這兩個庫,在編譯時間加上--ith-mcrypt和--ith-hash選項。PHP從 3.013版本開始支援mcrypt庫。

5、使用具有SSL技術

SSI是英文Server Side Includes的縮寫。使用具有SSL(安全通訊端協議層)功能的web伺服器,可以不用改變一行代碼而提高網站的安全效能。SSI使用加密方法來保護web伺服器和瀏覽器之間的資訊流。SSL不僅用於加密在互連網上傳遞的資料流,而且還提供雙方身分識別驗證。這樣,你就可以安全地線上購物而不必擔心別人矢隨你的信用卡的資訊。這種特性使得SSL適用於那些交換重要訊息的地方,像電子商務和基於Web的郵件。

SSL使用公用祕密金鑰加密技術,伺服器在串連結束時給用戶端發送公用密鑰用來加密資訊,而加密的資訊只有伺服器用它自己持有的專用密鑰才能解開。用戶端用公用祕密金鑰加密資料,並且發送給服務端自己的密鑰,以唯一確定自己,防止在系統兩端之間有人冒充服務端或用戶端進行欺騙。

加密的HTTP串連用443連接埠號碼代替80連接埠號碼,以區別於普通的不加密的HTTP。用戶端使用加密HTTP串連時會自動使用443連接埠而不是80連接埠。這使得服務端更容易作出相應的響應。

在Apache伺服器下,可以通過直接編輯伺服器設定檔或者在需要使用SSI的目錄中建立.htaccess檔案來啟動SSI。登入到伺服器,找到設定檔的存放目錄,使用文字編輯器開啟檔案srm.conf,找到以下幾行:

# If you want to use server side includes, or CGI outside
# ScriptAliased directories, uncomment the following lines.
#AddType text/x-server-parsed-html .shtml
#AddType application/x-httpd-CGI .CGI


將以AddType開頭的兩行並且去掉每一行最前面的"#"符號即可。儲存所做的修改,然後再開啟檔案access.conf。

    <Directory /usr/local/etc/httpd/htdocs>
    # This may also be "None", "All", or any combination of "Indexes",
    # "Includes", or "FollowSymLinks"
    Options Indexes FollowSymLinks
    </Directory>

    將其中的Options Indexes FollowSymLinks改為:Options Indexes FollowSymLinks Includes 即可。



6、使用Apache的suEXEC機制

通常CGI程式或PHP指令碼只能以啟動web伺服器的使用者權限來運行(通常為www或nobody),這樣會出現的情況之一是可以讀寫和修改由另一個使用者的CGI和PHP指令碼產生的檔案(如指令碼和密碼檔案)。也可能使使用者可以串連到其他使用者的資料庫,但這與資料庫的配置有關。如MySQL的預設配置便是允許的,但可以通過強制資料庫進行口令驗證來彌補此不足。PHP的safe?mode減少了這些問題,但所有的指令碼仍然以相同的使用者標識運行。Apache可以解決這個問題。suEXEC(在執行前改變使用者標識)是一個小工具,允許以任意使用者標識運行CGI程式,當然也包括PHP指令碼,但根使用者除外。而且可以和UseDir和VirtualHost項一起使用。

所以suEXEC也叫CGI封裝。這意味著在指令碼運行之前它需要通過一系列規定的安全檢查。隨Apache2。0版發布的suEXEC有26個檢查點。suEXEC能解決一些安全問題,同時允許使用者開發和更安全地執行自己的指令碼。但是suEXEC會降低服務效能,因為suEXEC只能運行在CGI版本的PHP上,而CGI版本比模組版本運行速度慢。原因是模組版本使用了線程,而使用CGI版本的是進程。在不同線程之間的環境轉換和訪問公用的儲存地區顯然要比在不同的進程之間要快得多。使用suEXEC的另外一個問題是它增加了編寫和使用PHP指令碼的難度。你要確保指令碼能通過suEXEC的檢驗。否則,你的指令碼不會被執行。我們建議在你對安全效能要求比較高時使用suEXEC ,為此你還要以犧牲速度為代價。

7、建立安全的PHP指令碼

有很多編程技巧使PHP指令碼更安全地運行。其中最重要的一條是使用一些安全常識。運行PHP比運行CGI指令碼更安全,但它仍然有許多出現錯誤的地方。轉換到安全運行模式能夠限制出錯所產生的結果。如果你的PHP指令碼中有錯誤,可能會被人找到並且利用它來破壞網站甚至資料庫。所以經常備份也是必要的。


(1)安全設定軟體

基於Web的應用程式,如線上目錄,通常都在無人密切監視的情況下運行。如果發生錯誤時,你不可能立即採取行動。通常訪問者最先注意到所發生的問題,你應該使他們很容易地報告所發生的問題。更進一步,可以由構成這個網站的指令碼來跟蹤這些問題。例如,你的訪問者可能做一些你想不到的事情。也可能你對於重要函數所傳回值沒有檢查,指令碼可能會以不可預料的方式運行。

寫出更加安全的程式,就可以避免這些問題。例如你應該檢查資料庫函數的傳回值,如果資料庫崩潰,顯示給使用者的應該是出錯的資訊頁面而不是滿螢幕的錯誤。你甚至可以讓指令碼在發生嚴重問題,如資料庫崩潰、硬碟空間已滿的時候自動通知你。你也應該檢查從使用者傳來的所有資料。顯然後者更重要。 如果你的程式能夠應付各種錯誤,那麼你的程式不僅更加可靠,而且可以花更少的時間來維護。這些時間可大大彌補你開發程式時所花的額外時間。


(2)儲存和交換敏感資訊

顯然,你應盡量避免在互連網上以GET、POST、cookie或URL編碼的形式傳遞敏感資訊,這樣使資訊很容易被竊取。使用支援SSL的web伺服器能夠做到這一點,因為它加密網站和訪問者瀏覽器之間所有的資訊流。

如果你沒有支援SSL的Web伺服器,那麼你需要其他的辦法。比如沒有必要總是發送資料到瀏覽器;把資料儲存在資料庫中,只向瀏覽器發送關鍵字,這樣也很容易尋找到所需要的資料;並以加密的形式發送所有的資料等等。實現這種功能的最簡單的辦法是使用Session。 PHP4支援本地化的Session功能,PHP3則要使用PHPMB庫。

HTTP 協議是一種無狀態協議,它不負責為好串連的狀態資訊,因此無法跟蹤用戶端的各種資訊,Session的出現改變這一狀況。當使用者瀏覽一個支援Session功能的CGI指令碼時,在他離開這個網頁前可以將使用者資訊儲存在同意Session ID之下,也就是可以在不同的網頁之間偕同存取使用者資訊。

如果不使用PHP的安全模式或在suEXEC下以CGI方式運行PHP,那麼監視你的檔案的內容就不可能實現。此時唯一防止別人讀取資料的方法是儘快把資料儲存到資料庫中。


(3)檢查使用者輸入

Per1語言有個特性叫汙點檢測(taint checking)。當汙點檢測生效時,即使沒有發生重大錯誤,你也不能運行含有可疑變數的函數。一個變數,當它的值是使用者提供資料的一部分或全部時就變成可疑的了,因為這些資料被認為是不安全的。這樣可提高系統安性。 PHP沒有這個特性,但PHP有escapeshellcmd函數,可以達到同樣的效果。另一個不讓使用者濫用指令碼的方法是只允許使用經過嚴格檢查的輸入。


(4)使用最新的PHP版本 4.2.xx

在很長一段時間內,PHP作為伺服器端指令碼語言的最大賣點之一就是會為從表單提交的值自動建立一個全域變數。在PHP 4.1中,PHP的製作者們推薦了一個訪問提交資料的替代手段。在PHP 4.2中,他們取消了那種老的做法。在PHP 4.1中,添加了一組特殊資料以訪問外部資料。這些數組可以在任何範圍內調用,這使得外部資料的訪問更方便。在PHP 4.2中,register_globals被預設關閉以鼓勵使用這些數組以避免無經驗的開發人員編寫出不安全的PHP代碼。作出這樣的變化是出於安全性的考慮的。


三、總結

徹底安全的系統從理論上講不可能,因此我們所指安全性只是在代價與可用性間作平衡。若是使用者提交的每一個變數都要求有生物學驗證(如指紋評鑑),則將獲得極高水平的可靠性。但是也會造成使用者填寫一個表格就要幾十分鐘。這時使用者就會採取繞過安全驗證的方法。一個系統的可靠性只能由整個鏈條中最薄弱的環節來決定。在任何安全系統裡面,人是最脆弱的串連,單單技術本身不能讓系統安全。

PHP 還處在不斷髮展的過程中,你需要經常關注他的安全資訊。這裡筆者推薦你經常關注安全焦點(www.security-focus.com )和Packetstorm(www.packetstorm.com )。



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.