PHP安全-會話數(shù)據(jù)暴露(二)
當(dāng)你關(guān)注于防止源碼的暴露時,你的會話數(shù)據(jù)只同樣存在著風(fēng)險(xiǎn)。在默認(rèn)情況下,SESSION保存在/tmp目錄下。這樣做在很多情形下是很方便的,其中之一是所有用戶都有對/tmp的寫入權(quán)限,這樣Apache同樣也有權(quán)限進(jìn)行寫入。雖然其他用戶不能直接從shell環(huán)境讀取這些會話文件,但他們可以寫一個簡單的腳本來進(jìn)行讀取:
<?php
header(’Content-Type: text/plain’);
session_start();
$path = ini_get(’session.save_path’);
$handle = dir($path);
while ($filename = $handle->read())
{
if (substr($filename, 0, 5) == ’sess_’)
{
$data = file_get_contents('$path/$filename');
if (!empty($data))
{
session_decode($data);
$session = $_SESSION;
$_SESSION = array();
echo 'Session [' . substr($filename, 5) . ']n';
print_r($session);
echo 'n--nn';
}
}
}
?>
這個腳本在session.save_path所定義的會話文件保存目錄中搜索以sess_為前綴的文件。找到文件后,即對它的內(nèi)容進(jìn)行解析并用print_r()函數(shù)顯示它的內(nèi)容。這樣其它開發(fā)者就容易地取得了你的用戶的會話數(shù)據(jù)。
解決這個問題的最好方法是把你的會話數(shù)據(jù)存入用用戶名和密碼保護(hù)的數(shù)據(jù)庫中。由于數(shù)據(jù)庫的訪問是受控的,這樣就多了一層額外的保護(hù)。通過應(yīng)用前節(jié)中提及的技巧,數(shù)據(jù)庫可以為你的敏感數(shù)據(jù)提供一個安全的存放地,同時你應(yīng)該保持警惕,你的數(shù)據(jù)庫安全性正變得越來越重要。
為在數(shù)據(jù)庫中保存會話數(shù)據(jù),首先需要建立一個數(shù)據(jù)表:
CREATE TABLE sessions
(
id varchar(32) NOT NULL,
access int(10) unsigned,
data text,
PRIMARY KEY (id)
);
如果你使用的是MySQL,則表結(jié)構(gòu)描述如下:
mysql> DESCRIBE sessions;
+--------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id | varchar(32) | | PRI | | |
| access | int(10) unsigned | YES | | NULL | |
| data | text | YES | | NULL | |
+--------+------------------+------+-----+---------+-------+
如要使會話數(shù)據(jù)能保存在此表中,你需要使用session_set_save_handler( )函數(shù)來編輯PHP的內(nèi)建會話機(jī)制:
<?php
session_set_save_handler(’_open’,
’_close’,
’_read’,
’_write’,
’_destroy’,
’_clean’);
?>
Each of these six arguments is the name of a function that you must write. These functions handle the following tasks:
以上的六個參數(shù)每一個都代表著需要你編寫的函數(shù)的名稱,他們對下面的任務(wù)進(jìn)行處理:
l打開會話存儲
l關(guān)閉會話存儲
l讀取會話數(shù)據(jù)
l寫入會話數(shù)據(jù)
l消滅會話數(shù)據(jù)
l清除舊會話數(shù)據(jù)
我有意使用了有意義的名稱,這樣你可以一下看出它們的目的。命名是任意的,但你可能希望用下劃線開頭(如此處所示)或其它的命名約定來防止名稱沖突。下面是這些函數(shù)(使用MySQL)的示例:
<?php
function _open()
{
global $_sess_db;
$db_user = $_SERVER[’DB_USER’];
$db_pass = $_SERVER[’DB_PASS’];
$db_host = ’localhost’;
if ($_sess_db = mysql_connect($db_host, $db_user, $db_pass))
{
return mysql_select_db(’sessions’, $_sess_db);
}
return FALSE;
}
function _close()
{
global $_sess_db;
return mysql_close($_sess_db);
}
function _read($id)
{
global $_sess_db;
$id = mysql_real_escape_string($id);
$sql = 'SELECT data
FROM sessions
WHERE id = ’$id’';
if ($result = mysql_query($sql, $_sess_db))
{
if (mysql_num_rows($result))
{
$record = mysql_fetch_assoc($result);
return $record[’data’];
}
}
return ’’;
}
function _write($id, $data)
{
global $_sess_db;
$access = time();
$id = mysql_real_escape_string($id);
$access = mysql_real_escape_string($access);
$data = mysql_real_escape_string($data);
$sql = 'REPLACE
INTO sessions
VALUES (’$id’, ’$access’, ’$data’)';
return mysql_query($sql, $_sess_db);
}
function _destroy($id)
{
global $_sess_db;
$id = mysql_real_escape_string($id);
$sql = 'DELETE
FROM sessions
WHERE id = ’$id’';
return mysql_query($sql, $_sess_db);
}
function _clean($max)
{
global $_sess_db;
$old = time() - $max;
$old = mysql_real_escape_string($old);
$sql = 'DELETE
FROM sessions
WHERE access < ’$old’';
return mysql_query($sql, $_sess_db);
}
?>
你必須要在session_start( )之前調(diào)用session_set_save_handler( )函數(shù),但你可以在任何地方對這些函數(shù)本身進(jìn)行定義。
這個流程的漂亮之處在于你無須對代碼進(jìn)行編輯或變化使用會話的方式。$_SESSION依然存在,行為依舊,還是由PHP來產(chǎn)生與傳遞會識標(biāo)識,對有關(guān)會話的配置變更同樣還會生效。所有你需要做的只是調(diào)用這一個函數(shù)(同時建立由它指定的所有函數(shù)),PHP就會照顧余下的事情。
相關(guān)文章:
1. Python如何批量生成和調(diào)用變量2. windows服務(wù)器使用IIS時thinkphp搜索中文無效問題3. Python基于requests實(shí)現(xiàn)模擬上傳文件4. ASP.NET MVC實(shí)現(xiàn)橫向展示購物車5. 通過CSS數(shù)學(xué)函數(shù)實(shí)現(xiàn)動畫特效6. python利用opencv實(shí)現(xiàn)顏色檢測7. Python 中如何使用 virtualenv 管理虛擬環(huán)境8. ASP.Net Core(C#)創(chuàng)建Web站點(diǎn)的實(shí)現(xiàn)9. Python sorted排序方法如何實(shí)現(xiàn)10. Python獲取B站粉絲數(shù)的示例代碼
