PHP安全《PHP Security》

來源:互聯網
上載者:User
安全 [  原書資訊 ]
《SAMS Teach Yourself PHP in 10 Minutes》
Author: Chris Newman   
Publisher : Sams Publishing
Pub Date : March 29, 2005
ISBN : 0-672-32762-7
Pages : 264

[  翻譯資訊 ]
翻譯人員:heiyeluren
翻譯時間:2006-3-15
翻譯章節:《Lesson 24. PHP Security》
中文名稱:PHP安全

PHP勿庸置疑是非常強大的伺服器端指令碼語言,但是強大的功能總是伴隨著重大的危險,在這章裡,你將學習到使用PHP的安全模式來阻止一些PHP潛在的危險因素。

【 安全模式 】

PHP的安全模式提供一個基本安全的共用環境,在一個有多個使用者帳戶存在的PHP開放的Web伺服器上。當一個Web伺服器上啟動並執行PHP開啟了安全模式,那麼一些函數將被完全的禁止,並且會限制一些可用的功能。

[  使用安全模式來強制限制 ]
在安全模式下,一些嘗試訪問檔案系統的函數功能將被限制。運行Web伺服器使用者ID,如果想要操作某個檔案,則必須擁有該檔案讀取或者寫入的存取權限,實現這個限制功能對於PHP來說是沒有問題的。

在安全模式開啟的時候,嘗試讀取或者寫入一個本地檔案的時候,PHP將檢查當前訪問使用者是否是該目標檔案的所有者。如果不是所有者,則該操作會被禁止。(寫入許可權:在較低層級的檔案存取權限下,可能會允許讀取或者寫入系統作業系統的檔案,通過PHP的安全模式實現了防止你操作另外一個使用者檔案的操作。當然,一個Web伺服器可能能夠訪問一個具有全域寫入許可權的任意檔案。)

當安全模式開啟的時候,以下函數列表的功能將會受到限制:

chdir , move_uploaded_file,  chgrp,  parse_ini_file,  chown,  rmdir,  copy,  rename,  fopen,  require,  highlight_file,  show_source,  include,  symlink,  link,  touch,  mkdir,  unlink
 
同樣的,一些PHP擴充中的函數也將會受到影響。(載入模組:在安全模式下dl函數將被禁止,如果要載入擴充的話,只能修改php.ini中的擴充選項,在PHP啟動的時候載入)

在PHP安全模式開啟的時候,需要執行作業系統程式的時候,必須是在safe_mode_exec_dir選項指定目錄的程式,否則執行將失敗。即使允許執行,那麼也會自動的傳遞給escapeshellcmd函數進行過濾。

以下執行命令的函數列表將會受到影響:
exec, shell_exec, passthru, system, popen

另外,背部標記操作符(`)也將被關閉。

當運行在安全模式下,雖然不會引起錯誤,但是 putenv 函數將無效。同樣的,其他一些嘗試改變PHP環境變數的函數set_time_limit, set_include_path 也將被忽略。

[  開啟安全模式 ]
開啟或者關閉PHP的安全模式是利用php.ini中的safe_mode選項。如果要啟用安全模式給當前所有共用Web伺服器的使用者,只要設定配置選項為:

safe_mode = On

當函數在訪問檔案系統的時候將進行檔案所有者的檢查。預設情況下,會檢查該檔案所有者的使用者ID,當你能夠修改檔案所有者的組ID(GID)為 safe_mode_gid 選項所指定的。

如果你有一個共用庫檔案在你的系統上,當你碰到需要include或require的時候,那麼你可以使用 safe_mode_include_dir 選項來設定你的路徑,保證你的代碼正常工作。(包含路徑: 如果你想要使用 safe_mode_include_dir 選項包含更多的包含路徑,那麼你可以象 include_path 選項一樣,在Unix/Linux系統下使用冒號進行分割,在Windows下使用分號進行分割)

比如你想要在安全模式下包含 /usr/local/include/php 下的檔案,那麼你可以設定選項為:

safe_mode_include_dir = /usr/local/include/php

如果你的包含的檔案是需要執行的,那麼你可以設定 safe_mode_exec_dir 選項。比如你需要 /usr/local/php-bin 路徑下的檔案是可以執行的,那麼可以設定選項為:

safe_mode_exec_dir = /usr/local/php-bin

(可執行:如果你執行的程式在 /usr/bin 目錄下,那麼你可以把這些的二進位檔案,串連到你指定選項下能夠執行的路徑)

如果你想設定某些環境變數,那麼可以使用 safe_mode_allowed_env_vars 選項。這個選項的值是一個環境變數的首碼,預設是允許 PHP_ 開頭的環境變數,如果你想要改變,可以設定該選項的值,多個環境變數首碼之間使用逗號進行分割。

比如下面允許時區的環境變數 TZ ,那麼修改該選項的值為:

safe_mode_allowed_env_vars = PHP_,TZ

【 其他的安全特徵 】
 
除了安全模式以外,PHP還提供了許多其他許多特徵來保證PHP的安全。


[  隱藏PHP ]
你能夠在php.ini裡使用 expose_php 選項來防止Web伺服器泄露PHP的報告資訊。如下:

expose_php = On

利用整個設定,你能夠阻礙一些來自自動指令碼針對Web伺服器的攻擊。通常情況下,HTTP的頭資訊裡麵包含了如下資訊:

Server: Apache/1.3.33 (Unix) PHP/5.0.3 mod_ssl/2.8.16
OpenSSL/0.9.7c

在 expose_php 選項開啟以後,PHP的版本資訊將不包含在上面的頭資訊裡。

當然,使用者訪問網站的時候同樣能夠看到 .php 的副檔名。如果你想整個的使用不同的副檔名,你需要在 httpd.conf 中找到如下這行:

AddType application/x-httpd .php

你就可以修改 .php 為任何你喜歡的副檔名。你能夠指定任意多個的副檔名,中間使用空格進行分割。如果你想在伺服器端使用PHP來解析 .html 和 .htm 檔案的時候,那麼你設定選項如下:

AddType application/x-httpd .html .htm

(解析HTML:配置你的Web伺服器使用PHP去解析所有的HTML檔案,但是如果非伺服器端代碼也需要PHP去解析,會影響伺服器的效能。靜態頁面你可以使用不同的副檔名,這樣能夠消除對PHP指令碼引擎的依賴,增強效能。)

[  檔案系統安全 ]

安全模式限制了指令碼所有者只能訪問屬於自己的檔案,但是你可以使用 open_basedir 選現來指定一個你必須訪問的目錄。如果你指定了一個目錄,PHP將拒絕訪問除了該目錄和該目錄子目錄的其他目錄。open_basedir 選項能夠工作在安全模式之外。

限制檔案系統只能訪問 /tmp 目錄,那麼設定選項為:

open_basedir = /tmp

[  函數存取控制 ]

你能夠在 disable_functions 選項中使用逗號分割來設定函數名,那麼這些函數將在PHP指令碼中被關閉。這個設定能夠工作在安全模式之外。

disable_functions = dl

當然,同樣的你能夠使用 disable_classes 選項來關閉對一些類的訪問。

[  資料庫安全 ]

假設你的PHP指令碼中包含一個基於表單值來執行的Mysql查詢:

$sql = "UPDATE mytable SET col1 = " . $_POST["value"] . "
        WHERE col2 = 'somevalue'";
$res = mysql_query($sql, $db);

你希望 $_POST["value"] 包含一個整數值來更新你的列 col1。可是,一個惡意使用者能夠輸入一個分號在表單欄位裡,接著,是一段他/她想被任意執行的SQL語句。

舉例,假設下面是 $_POST["value"] 提交的值:

0; INSERT INTO admin_users (username, password)
VALUES ('me', 'mypassword');

那麼當這個查詢發送給Mysql查詢的時候,那麼就變成了下面這條SQL:

UPDATE mytable SET col1 = 0;
INSERT INTO admin_users (username, password)
VALUES ('me', 'mypassword');
WHERE col2 = 'somevalue';

這明顯是一個有害的查詢!首先這個查詢會在 mytable 表裡更新 col1。這個並沒有什麼麻煩的,但是第二個運算式,它將執行 INSERT 運算式來插入一個能登陸的新管理員。第三個運算式就廢棄了,但同時SQL解析器將拋出一個錯誤,這個有害的查詢才完成。這個攻擊就是大家常說的 SQL injection(註:SQL注入)。

當然,SQL injection 存在一個問題,對方必須瞭解你的資料庫結構。在這個例子中,攻擊者是知道你有一個表 admin_users,並且知道包含 username 和 password欄位,同時,儲存的密碼是沒有加密的。

除了你自己,一般的網站訪問者是不知道這些關於資料庫的資訊。可是,如果你使用了一個開發原始碼的線上電子商務程式,或者使用一個自由的討論版程式,這些資料表的定義都是已知的,或者有一些使用者能夠訪問到你的資料庫。

此外,你的指令碼輸出會提示一個查詢錯誤,這些資訊裡包含了很多關於資料庫結構的重要訊息。在一個正常工作的網站上,你應該考慮設定 display_errors 選項為 off,並且使用 log_errors 來代替 display_errors ,把警告和錯誤資訊插入到檔案中。

(資料庫許可權:它是一個非常重要的東西,你只有正確的許可權,才能通過指令碼正確的串連資料庫。你應該不要在指令碼中使用管理員去串連資料庫。如果你這麼做,那麼一個攻擊者將可能擷取全部的資料庫許可權,並且包括其他相同伺服器的許可權。攻擊者將可能運行 GRANT 或 CREATE USER 命令來擷取更多的存取權限。 )

如果你要防止 SQL injection 攻擊,你必須保證使用者表單裡提交的內容不是一個能夠執行的SQL運算式。

前一個例子中,我們使用一個整型值來進行更新。如果在單引號後面跟上一個字串,這個攻擊者在分號之前必須提交一個閉合的引用在整個SQL運算式中。可是,當 magic_quotes_gpc 選項是開啟的時候,在Web表單中提交的引號將自動被轉義。

為了防止被惡意的攻擊者進行 SQL injection攻擊,你應該總是確認提交的資料是合法的。如果你需要的是一個整數值,那麼你可以使用 is_numeric 函數來測試這個表達值,或者使用 settype 函數來轉換為一個數字,清除任何一個傻傻的SQL語句。

如果你開發的程式需要幾個提交的值在一個SQL運算式裡,你能夠使用 sprintf 函數來構建一個SQL字串,使用格式化字元來指示資料類型的每個值。看下面的例子:

$sql = sprintf("UPDATE mytable SET col1 = %d
                 WHERE col2 = '%s'",
                 $_POST["number"],
                 mysql_escape_string($_POST["string"]));

在上一個例子中,整個Mysql的資料已經被使用,所以這個字串已經通過 mysql_escape_string 函數進行過濾。對於其他資料庫,你可以使用 addslashes 函數進行轉義,或者使用其他方法。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.