PHP安全配置_php基礎

來源:互聯網
上載者:User

一、CGI模式安裝安全

二、以Apache模組安裝安全

當 PHP 以 Apache 模組方式安裝時,它將繼承 Apache 使用者(通常為“nobody”)的許可權。這對安全和認證有一些影響。比如,如果用 PHP 來訪問資料庫,除非資料庫有自己的存取控制,否則就要使“nobody”使用者可以訪問資料庫。這意味著惡意的指令碼在不用提供使用者名稱和密碼時就可能訪問和修改資料庫。一個 web Spider 也完全有可能偶然探索資料庫的管理頁面,並且刪除所有的資料庫。可以通過 Apache 認證來避免此問題,或者用 LDAP、.htaccess 等技術來設計自己的防問模型,並把這些代碼作為 PHP 指令碼的一部份
一個常犯的對安全性不利的錯誤就是讓 Apache 擁有 root 許可權,或者通過其它途徑斌予 Apache 更強大的功能。
把 Apache 使用者的許可權提升為 root 是極度危險的做法,而且可能會危及到整個系統的安全。所以除非是安全專家,否則決不要考慮使用 su,chroot 或者以 root 許可權運行。
除此之外還有一些比較簡單的解決方案。比如說可以使用 open_basedir 來限制哪些目錄可以被 PHP 使用。也可以設定 Apache 的專屬地區,從而把所有的 web 活動都限制到非使用者和非系統檔案之中。

三、檔案系統安全

 PHP 遵從大多數伺服器系統中關於檔案和目錄許可權的安全機制。這就使管理員可以控制哪些檔案在檔案系統內是可讀的。必須特別注意的是全域的可讀檔案,並確保每一個有許可權的使用者對這些檔案的讀取動作都是安全的。
 PHP 被設計為以使用者層級來訪問檔案系統,所以完全有可能通過編寫一段 PHP 代碼來讀取系統檔案如 /etc/passwd,更改網路連接以及發送大量列印任務等等。因此必須確保 PHP 代碼讀取和寫入的是合適的檔案。

兩個重要措施來防止此類問題。

# 只給 PHP 的 web 使用者很有限的許可權。
# 檢查所有提交上來的變數。

$username = $_SERVER['REMOTE_USER']; // 使用認證機制$userfile   = $_POST['user_submitted_filename'];$homedir = "/home/$username";$filepath   = "$homedir/$userfile";if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {  die("Bad username/filename");}

* Null字元問題

由於 PHP 的檔案系統操作是基於 C 語言的函數的,所以它可能會以您意想不到的方式處理 Null 字元。 Null字元在 C 語言中用於標識字串結束,一個完整的字串是從其開頭到遇見 Null 字元為止。

# 會被 Null 字元問題攻擊的代碼:

$file = $_GET['file']; // "http://www.cnblogs.com/etc/passwd\0"if (file_exists('/home/wwwrun/'.$file.'.php')) {  // file_exists will return true as the file /home/wwwrun/http://www.cnblogs.com/etc/passwd exists  include '/home/wwwrun/'.$file.'.php';  // the file /etc/passwd will be included}

# 驗證輸入的正確做法

$file = $_GET['file']; // 對字串進行白名單檢查switch ($file) {  case 'main':  case 'foo':  case 'bar':    include '/home/wwwrun/include/'.$file.'.php';    break;  default:    include '/home/wwwrun/include/main.php';}

四、資料庫安全

* 設計資料庫

第一步一般都是建立資料庫,除非是使用第三方的資料庫服務。當建立一個資料庫的時候,會指定一個所有者來執行和建立語句。通常,只有所有者(或超級使用者)才有權對資料庫中的對象進行任意操作。如果想讓其他使用者使用,就必須賦予他們許可權。
應用程式永遠不要使用資料庫擁有者或超級使用者帳號來串連資料庫,因為這些帳號可以執行任意的操作,比如說修改資料庫結構(例如刪除一個表)或者清空整個資料庫的內容。
應該為程式的每個方面建立不同的資料庫帳號,並賦予對資料庫物件的極有限的許可權。僅分配給能完成其功能所需的許可權,避免同一個使用者可以完成另一個使用者的事情。這樣即使攻擊者利用程式漏洞取得了資料庫的存取權限,也最多隻能做到和該程式一樣的影響範圍。
鼓勵使用者不要把所有的事務邏輯都用 web 應用程式(即使用者的指令碼)來實現。最好用視圖(view)、觸發器(trigger)或者規則(rule)在資料庫層面完成。當系統升級的時候,需要為資料庫開闢新的介面,這時就必須重做所有的資料庫用戶端。除此之外,觸發器還可以透明和自動地處理欄位,並在偵錯工具和跟蹤事即時提供有用的資訊。
 
* 串連資料庫

把串連建立在 SSL 加密技術上可以增加用戶端和伺服器端通訊的安全性,或者 SSH 也可以用於加密用戶端和資料庫之間的串連。如果使用了這些技術的話,攻擊者要監視伺服器的通訊或者得到資料庫的資訊是很困難的。

 
* 加密儲存模型

SSL/SSH 能保護用戶端和伺服器端交換的資料,但 SSL/SSH 並不能保護資料庫中已有的資料。SSL 只是一個加密網路資料流的協議。
如果攻擊者取得了直接存取資料庫的許可(繞過 網頁伺服器),敏感性資料就可能暴露或者被濫用,除非資料庫自己保護了這些資訊。對資料庫內的資料加密是減少這類風險的有效途徑,但是只有很少的資料庫提供這些加密功能。
對於這個問題,有一個簡單的解決辦法,就是建立自己的加密機制,然後把它用在 PHP 程式內。PHP 有幾個擴充庫可以完成這個工作,比如說 Mcrypt 和 Mhash 等,它們包含多種加密運演算法則。指令碼在插入資料庫之前先把資料加密,以後提取出來時再解密。
對某些真正隱形資料,如果不需要以明文的形式存在(即不用顯示),可以考慮用散列演算法。使用散列演算法最常見的例子就是把密碼經過 MD5 加密後的散列存進資料庫來代替原來的純文字密碼。參見 crypt() 和 md5()。
 
* SQL注入

很多 web 開發人員沒有注意到 SQL 查詢是可以被篡改的,因而把 SQL 查詢當作可信任的命令。殊不知道,SQL 查詢可以繞開存取控制,從而繞過身分識別驗證和許可權檢查。更有甚者,有可能通過 SQL 查詢去運行主機作業系統級的命令。
直接 SQL 命令注入就是攻擊者常用的一種建立或修改已有 SQL 陳述式的技術,從而達到取得隱藏資料,或覆蓋關鍵的值,甚至執行資料庫主機作業系統命令的目的。這是通過應用程式取得使用者輸入並與靜態參數組合成 SQL 查詢來實現的。下面將會給出一些真實的例子。
由於在缺乏對輸入的資料進行驗證,並且使用了超級使用者或其它有權建立新使用者的資料庫帳號來串連,攻擊者可以在資料庫中建立一個超級使用者。

Example #1 一段實現資料分頁顯示的代碼……也可以被用作建立一個超級使用者(PostgreSQL系統)。

<?php$offset = $argv[0]; // 注意,沒有輸入驗證!$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";$result = pg_query($conn, $query);?>

一般的使用者會點擊 $offset已被斌值的“上一頁”、“下一頁”的連結。原本代碼只會認為 $offset是一個數值。然而,如果有人嘗試把以下語句先經過 urlencode()處理,然後加入URL中的話:

0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
    select 'crack', usesysid, 't','t','crack'
    from pg_shadow where usename='postgres';
--那麼他就可以建立一個超級使用者了。注意那個 0;只不過是為了提供一個正確的位移量以便補充完整原來的查詢,使它不要出錯而已。

 

Note:

-- 是 SQL 的注釋標記,一般可以使用來它告訴 SQL 解譯器忽略後面的語句。

對顯示搜尋結果的頁面下手是一個能得到密碼的可行辦法。攻擊者所要做的只不過是找出哪些提交上去的變數是用於 SQL 陳述式並且處理不當的。而這類的變數通常都被用於 SELECT查詢中的條件陳述式,如 WHERE, ORDER BY, LIMIT 和 OFFSET。如果資料庫支援 UNION構造的話,攻擊者還可能會把一個完整的 SQL 查詢附加到原來的語句上以便從任意資料表中得到密碼。因此,對密碼欄位加密是很重要的。

Example #2 顯示文章……以及一些密碼(任何資料庫系統)

複製代碼 代碼如下:

<?php
$query = "SELECT id, name, inserted, size FROM products
WHERE 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中的任意一個變數的話,那麼就麻煩了。

SQL 中的 UPDATE 也會受到攻擊。這種查詢也可能像上面的例子那樣被插入或附加上另一個完整的請求。但是攻擊者更願意對 SET子句下手,這樣他們就可以更改資料表中的一些資料。這種情況下必須要知道資料庫的結構才能修改查詢成功進行。可以通過表單上的變數名對欄位進行猜測,或者進行暴力破解。對於存放使用者名稱和密碼的欄位,命名的方法並不多。

Example #3 從重設密碼……到獲得更多許可權(任何資料庫系統)

複製代碼 代碼如下:

<?php
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
?>

但是惡意的使用者會把 ' or uid like'%admin%'; --作為變數的值提交給 $uid 來改變 admin 的密碼,或者把 $pwd 的值提交為 "hehehe', admin='yes', trusted=100 "(後面有個空格)去獲得更多的許可權。這樣做的話,查詢語句實際上就變成了:

複製代碼 代碼如下:

<?php
// $uid == ' or uid like'%admin%'; --
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";

// $pwd == "hehehe', admin='yes', trusted=100 "
$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
...;";
?>

下面這個可怕的例子將會示範如何在某些資料庫上執行系統命令。

Example #4 攻擊資料庫所在主機的作業系統(MSSQL Server)

複製代碼 代碼如下:

<?php
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";
$result = mssql_query($query);
?>

如果攻擊提交 a%' exec master..xp_cmdshell 'net user test testpass /ADD' --作為變數 $prod的值,那麼 $query將會變成

複製代碼 代碼如下:

<?php
$query = "SELECT * FROM products
WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);
?>

MSSQL 伺服器會執行這條 SQL 陳述式,包括它後面那個用於向系統添加使用者的命令。如果這個程式是以 sa運行而 MSSQLSERVER 服務又有足夠的許可權的話,攻擊者就可以獲得一個系統帳號來訪問主機了。

Note:

雖然以上的例子是針對某一特定的資料庫系統的,但是這並不代表不能對其它資料庫系統實施類似的攻擊。使用不同的方法,各種資料庫都有可能遭殃。

預防措施

也許有人會自我安慰,說攻擊者要知道資料庫結構的資訊才能實施上面的攻擊。沒錯,確實如此。但沒人能保證攻擊者一定得不到這些資訊,一但他們得到了,資料庫有泄露的危險。如果你在用開放原始碼的軟體包來訪問資料庫,比如論壇程式,攻擊者就很容得到到相關的代碼。如果這些代碼設計不良的話,風險就更大了。
這些攻擊總是建立在發掘安全意識不強的代碼上的。所以,永遠不要信任外界輸入的資料,特別是來自於用戶端的,包括選擇框、表單隱藏欄位和 cookie。就如上面的第一個例子那樣,就算是正常的查詢也有可能造成災難。
•永遠不要使用超級使用者或所有者帳號去串連資料庫。要用許可權被嚴格限制的帳號。

•檢查輸入的資料是否具有所期望的資料格式。PHP 有很多可以用於檢查輸入的函數,從簡單的變數函數和字元類型函數(比如 is_numeric(),ctype_digit())到複雜的 Perl 相容Regex函數都可以完成這個工作。
•如果程式等待輸入一個數字,可以考慮使用 is_numeric()來檢查,或者直接使用 settype() 來轉換它的類型,也可以用 sprintf() 把它格式化為數字。

Example #5 一個實現分頁更安全的方法

複製代碼 代碼如下:

<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";

// 請注意格式字串中的 %d,如果用 %s 就毫無意義了
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",
$offset);
?>

•使用資料庫特定的敏感字元轉義函數(比如 mysql_escape_string() 和 sql_escape_string())把使用者提交上來的非數字資料進行轉義。如果資料庫沒有專門的敏感字元轉義功能的話 addslashes() 和 str_replace()可以代替完成這個工作。看看第一個例子,此例顯示僅在查詢的靜態部分加上引號是不夠的,查詢很容易被攻破。
•要不擇手段避免顯示出任何有關資料庫的信心,尤其是資料庫結構。參見錯誤報表和錯誤處理函數。
•也可以選擇使用資料庫的預存程序和預定義指標等特性來抽象數庫訪問,使使用者不能直接存取資料表和視圖。但這個辦法又有別的影響。
除此之外,在允許的情況下,使用代碼或資料庫系統儲存查詢日誌也是一個好辦法。顯然,日誌並不能防止任何攻擊,但利用它可以跟蹤到哪個程式曾經被嘗試攻擊過。日誌本身沒用,要查閱其中包含的資訊才行。畢竟,更多的資訊總比沒有要好。

五、錯誤報表

對於 PHP 的安全性來說錯誤報表是一把雙刃劍。一方面可以提高安全性,另一方面又有害。

攻擊系統時經常使用的手法就是輸入不正確的資料,然後查看錯誤提示的類型及上下文。這樣做有利於攻擊者收集伺服器的資訊以便尋找弱點。比如說,如果一個攻擊者知道了一個頁面所基於的表單資訊,那麼他就會嘗試修改變數:

Example #1 用自訂的 HTML 頁面攻擊變數

複製代碼 代碼如下:

<form method="post" action="attacktarget?username=badfoo&password=badfoo">
<input type="hidden" name="username" value="badfoo" />
<input type="hidden" name="password" value="badfoo" />
</form>

通常 PHP 所返回的錯誤提示都能協助開發人員偵錯工具,它會提出哪個檔案的哪些函數或代碼出錯,並指出錯誤發生的在檔案的第幾行,這些就是 PHP 本身所能給出的資訊。很多 PHP 開發人員會使用 show_source()、highlight_string()或者 highlight_file()函數來調試代碼,但是在正式啟動並執行網站中,這種做法可能會暴露出隱藏的變數、未檢查的文法和其它的可能危及系統安全的資訊。在運行一些具有內部調試處理的程式,或者使用通用調試技術是很危險的。如果讓攻擊者確定了程式是使用了哪種具體的調試技術,他們會嘗試發送變數來開啟調試功能:

Example #2 利用變數開啟調式功能

複製代碼 代碼如下:

<form method="post" action="attacktarget?errors=Y&showerrors=1&debug=1">
<input type="hidden" name="errors" value="Y" />
<input type="hidden" name="showerrors" value="1" />
<input type="hidden" name="debug" value="1" />
</form>

不管錯誤處理機制如何,可以探測系統錯誤的能力會給攻擊者提供更多資訊。

比如說,PHP 的專屬的錯誤提示風格可以說明系統在運行 PHP。如果攻擊者在尋找一個 .html 為頁面,想知道其背景技術(為了尋找系統弱點),他們就會把錯誤的資料提交上去,然後就有可以得知系統是基於 PHP 的了。
一個函數錯誤就可能暴露系統正在使用的資料庫,或者為攻擊者提供有關網頁、程式或設計方面的有用資訊。攻擊者往往會順藤摸瓜地找到開放的資料庫連接埠,以及頁面上某些 bug 或弱點等。比如說,攻擊者可以一些不正常的資料使程式出錯,來探測指令碼中認證的順序(通過錯誤提示的行號數字)以及指令碼中其它位置可能泄露的資訊。
一個檔案系統或者 PHP 的錯誤就會暴露 網頁伺服器具有什麼許可權,以及檔案在伺服器上的組織圖。開發人員自己寫的錯誤碼會加劇此問題,導致泄漏了原本隱藏的資訊。
有三個常用的辦法處理這些問題。第一個是徹底地檢查所有函數,並嘗試彌補大多數錯誤。第二個是對線上系統徹底關閉錯誤報表。第三個是使用 PHP 自訂的錯誤處理函數建立自己的錯誤處理機制。根據不同的安全性原則,三種方法可能都適用。
一個能提前阻止這個問題發生的方法就是利用 error_reporting() 來協助使代碼更安全並發現變數使用的危險之處。在發布程式之前,先開啟 E_ALL 測試代碼,可以幫你很快找到變數使用不當的地方。一旦準備正式發布,就應該把 error_reporting() 的參數設為 0 來徹底關閉錯誤報表或者把 php.ini中的 display_errors 設為 off 來關閉所有的錯誤顯示以將代碼隔絕於探測。當然,如果要遲一些再這樣做,就不要忘記開啟 ini 檔案內的 log_errors 選項,並通過 error_log 指定用於記錄錯誤資訊的檔案。

Example #3 用 E_ALL 來尋找危險的變數

複製代碼 代碼如下:

<?php
if ($username) { // Not initialized or checked before usage
$good_login = 1;
}
if ($good_login == 1) { // If above test fails, not initialized or checked before usage
readfile ("/highly/sensitive/data/index.html");
}
?>

六、使用Register Globals
 
可能 PHP 中最具爭議的變化就是從 PHP » 4.2.0版開始設定檔中 register_globals的預設值從 on 改為 off 了。對此選項的依賴是如此普遍以至於很多人根本不知道它的存在而以為 PHP 本來就是這麼工作的。本節會解釋用這個指令如何寫出不安全的代碼,但要知道這個指令本身沒有不安全的地方,誤用才會。

當 register_globals 開啟以後,各種變數都被注入代碼,例如來自 HTML 表單的請求變數。再加上 PHP 在使用變數之前是無需進行初始化的,這就使得更容易寫出不安全的代碼。這是個很艱難的抉擇,但 PHP 社區還是決定預設關閉此選項。當開啟時,人們使用變數時確實不知道變數是哪裡來的,只能想當然。但是 register_globals 的關閉改變了這種代碼內部變數和用戶端發送的變數混雜在一起的糟糕情況。下面舉一個錯誤使用 register_globals 的例子:

Example #1 錯誤使用 register_globals = on 的例子

複製代碼 代碼如下:

<?php
// 當使用者合法的時候,賦值 $authorized = true
if (authenticated_user()) {
$authorized = true;
}

// 由於並沒有事先把 $authorized 初始化為 false,
// 當 register_globals 開啟時,可能通過GET auth.php?authorized=1 來定義該變數值
// 所以任何人都可以繞過身分識別驗證
if ($authorized) {
include "/highly/sensitive/data.php";
}
?>
 

當 register_globals = on 的時候,上面的代碼就會有危險了。如果是 off,$authorized 就不能通過如 URL 請求等方式來改變,這樣就好多了,儘管初始設定變數是一個良好的編程習慣。比如說,如果在上面的代碼執行之前加入 $authorized = false 的話,無論 register_globals 是 on 還是 off 都可以,因為使用者狀態被初始化為未經認證。

另一個例子是關於會話的。當 register_globals = on 的時候,$username 也可以用在下面的代碼中,但要意識到 $username 也可能會從其它途徑進來,比如說通過 URL 的 GET。


Example #2 使用會話時同時相容 register_globals on 和 off 的例子

複製代碼 代碼如下:

<?php
// 我們不知道 $username 的來源,但很清楚 $_SESSION 是
// 來源於會話資料
if (isset($_SESSION['username'])) {

echo "Hello <b>{$_SESSION['username']}</b>";

} else {

echo "Hello <b>Guest</b><br />";
echo "Would you like to login?";

}
?>

採取相應的預防措施以便在偽造變數輸入的時候給予警告是完全有可能的。如果事先確切知道變數是哪裡來的,就可以檢查所提交的資料是否是從不正當的表單提交而來。不過這不能保證變數未被偽造,這需要攻擊者去猜測應該怎樣去偽造。如果不在乎請求資料來源的話,可以使用 $_REQUEST 數組,它包括了 GET、POST 和 COOKIE 的所有資料。詳情可參見本手冊的來自 PHP 之外的變數。

 

Example #3 探測有害變數

複製代碼 代碼如下:

<?php
if (isset($_COOKIE['MAGIC_COOKIE'])) {

// MAGIC_COOKIE 來自 cookie
// 這樣做是確保是來自 cookie 的資料

} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {

mail("admin@example.com", "Possible breakin attempt", $_SERVER['REMOTE_ADDR']);
echo "Security violation, admin has been alerted.";
exit;

} else {

// 這一次請求中並沒有設定 MAGIC_COOKIE 變數
}
?>
 

當然,單純地關閉 register_globals 並不代表所有的代碼都安全了。對於每一段提交上來的資料,都要對其進行具體的檢查。永遠要驗證使用者資料和對變數進行初始化!把 error_reporting() 設為 E_NOTICE 層級可以檢查未初始化的變數。

更多關於類比 register_globals 為 on 或 off 的資訊,請見此 FAQ。

Note: Superglobal 可用性說明:

自 PHP 4.1.0 起可以使用 Superglobal 數組,例如 $_GET,$_POST,和$_SERVER,等等。更多資訊請閱讀手冊中的 superglobals 章節。

七、使用者提交的資料

很多 PHP 程式所存在的重大弱點並不是 PHP 語言本身的問題,而是編程者的安全意識不高而導致的。因此,必須時時注意每一段代碼可能存在的問題,去發現非正確資料提交時可能造成的影響。

Example #1 危險的變數用法

複製代碼 代碼如下:

<?php
// 從使用者目錄中刪除一個檔案,或者……能刪除更多的東西?
unlink ($evil_var);

// 記錄使用者的登陸,或者……能否在 /etc/passwd 添加資料?
fwrite ($fp, $evil_var);

// 執行一些普通的命令,或者……可以執行 rm -rf * ?
system ($evil_var);
exec ($evil_var);
?>

必須時常留意你的代碼,以確保每一個從用戶端提交的變數都經過適當的檢查,然後問自己以下一些問題:

•此指令碼是否只能影響所預期的檔案?
•非正常的資料被提交後能否產生作用?
•此指令碼能用於計劃外的用途嗎?
•此指令碼能否和其它指令碼結合起來做壞事?
•是否所有的事務都被充分記錄了?
在寫代碼的時候問自己這些問題,否則以後可能要為了增加安全性而重寫代碼了。注意了這些問題的話,也許還不完全能保證系統的安全,但是至少可以提高安全性。

還可以考慮關閉 register_globals,magic_quotes 或者其它使編程更方便但會使某個變數的合法性,來源和其值被搞亂的設定。在開發時,可以使用 error_reporting(E_ALL) 模式協助檢查變數使用前是否有被檢查或被初始化,這樣就可以防止某些非正常的資料的撓亂了。

八、魔術引號

* 魔術引號

當開啟時,所有的 '(單引號),"(雙引號),\(反斜線)和 NULL 字元都會被自動加上一個反斜線進行轉義。這和 addslashes() 作用完全相同。

一共有三個魔術引號指令:
■magic_quotes_gpc  影響到 HTTP 要求資料(GET,POST 和 COOKIE)。不能在運行時改變。在 PHP 中預設值為 on。 參見 get_magic_quotes_gpc()。
■magic_quotes_runtime  如果開啟的話,大部份從外部來源取得資料並返回的函數,包括從資料庫和文字檔,所返回的資料都會被反斜線轉義。該選項可在啟動並執行時改變,在 PHP 中的預設值為 off。 參見 set_magic_quotes_runtime() 和 get_magic_quotes_runtime()。
■magic_quotes_sybase  如果開啟的話,將會使用單引號對單引號進行轉義而非反斜線。此選項會完全覆蓋 magic_quotes_gpc。如果同時開啟兩個選項的話,單引號將會被轉義成 ''。而雙引號、反斜線 和 NULL 字元將不會進行轉義。 如何取得其值參見 ini_get()。


* 魔術引號的作用

優點:

■ 對初學者很有用 魔術引號在 PHP 中用來實現避免初學者的代碼更危險。儘管 SQL 注入在魔術引號開啟的情況下仍然有可能實現,但起碼系統的風險減少很多了。
■ 方便使用 當向資料庫中插入資料時,魔術引號所做的就是自動對所有的 GET、POST、COOKIE 資料運用 addslashes() 函數

缺點:

■可移植性 編程時認為其開啟或並閉都會影響到移植性。可以用 get_magic_quotes_gpc() 來檢查是否開啟,並據此編程。
■ 效能 由於並不是每一段被轉義的資料都要插入資料庫的,如果所有進入 PHP 的資料都被轉義的話,那麼會對程式的執行效率產生一定的影響。在運行時調用轉義函數(如 addslashes())更有效率。 儘管 php.ini-dist 預設開啟了這個選項,但是 php.ini-recommended 預設卻關閉了它,主要是出於效能的考慮。
■ 不便 由於不是所有資料都需要轉義,在不需要轉義的地方看到轉義的資料就很煩。比如說通過表單發送郵件,結果看到一大堆的 \'。針對這個問題,可以使用 stripslashes() 函數處理

 

* 關閉魔術引號

magic_quotes_gpc指令只能在系統級關閉,不能在運行時。也就是說不能用 ini_set()。

 
Example #1 在伺服器端關閉魔術引號

下面是一個通過 php.ini 檔案把這些選項設為 Off的範例。更多資訊請參見本手冊的怎樣修改配置設定。

; Magic quotes
;

; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = Off

; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off

; Use Sybase-style magic quotes (escape ' with '' instead of \').
magic_quotes_sybase = Off
如果不能修改伺服器端的設定檔,使用 .htaccess 也可以。範例如下:

php_flag magic_quotes_gpc Off
 

為了能寫出移植性較強的代碼(可以運行於任何環境),例如不能修改伺服器配置的情況,下面的例子可以在運行時關閉 magic_quotes_gpc。但是這樣做比較低效,適當的修改配置才是更好的辦法。

Example #2 在運行時關閉魔術引號

複製代碼 代碼如下:

<?php
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value)
{
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);

return $value;
}

$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}
?>

九、隱藏PHP

一般而言,通過隱藏的手段提高安全性被認為是作用不大的做法。但某些情況下,儘可能的多增加一份安全性都是值得的。

一些簡單的方法可以協助隱藏 PHP,這樣做可以提高攻擊者發現系統弱點的難度。在 php.ini 檔案裡設定 expose_php = off ,可以減少他們能獲得的有用資訊。

另一個策略就是讓 網頁伺服器用 PHP 解析不同副檔名。無論是通過 .htaccess 檔案還是 Apache 的設定檔,都可以設定能誤導攻擊者的副檔名:

Example #1 把 PHP 隱藏為另一種語言

# 使PHP看上去像其它的程式設計語言
AddType application/x-httpd-php .asp .py .pl或者乾脆徹底隱藏它:

Example #2 使用未知的副檔名作為 PHP 的副檔名

# 使 PHP 看上去像未知的檔案類型
AddType application/x-httpd-php .bop .foo .133t或者把它隱藏為 HTML 頁面,這樣所有的 HTML 檔案都會通過 PHP 引擎,會為伺服器增加一些負擔:

Example #3 用 HTML 做 PHP 的檔案尾碼

# 使 PHP 代碼看上去像 HTML 頁面
AddType application/x-httpd-php .htm .html要讓此方法生效,必須把 PHP 檔案的副檔名改為以上的副檔名。這樣就通過隱藏來提高了安全性,雖然防禦能力很低而且有些缺點。

十、保持更新

PHP 和其它的大型系統一樣,在持續的研究和改進中。每一個版本都會有或多或少的改進來增強安全性和修複任何缺陷,配置問題以及任何會影響到整個系統安全與效能的問題。

和其它系統級的指令碼語言一樣,最好的途徑是經常更新,並時刻留意最新版本及其改變

聯繫我們

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