移至程式碼檢視的第二行,在連線的包含檔案之後,然後將 GetSQLValueString() 函數新增至程式碼的開頭,如下所示:
<?php if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") { $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue); switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } } ?>
問題
某些資料庫可讓您在單一查詢中傳送多個 SQL 陳述式。 因此,當您在查詢字串中將參數傳遞給動態生成的資料庫查詢時,會存在潛在的安全風險。駭客可能嘗試透過將惡意 SQL 陳述式附加至現有參數,來修改動態查詢中的 URL 或表單變數。這通常稱為 SQL 插入式攻擊。 部分由 Dreamweaver 建立的伺服器行為程式碼應經過修改以降低 SQL 插入式攻擊的風險。 如需 SQL 插入的相關詳細背景資訊,請參閱維基百科文章。 (參考 201713)
注意:本技術備註中所述的問題已在 Dreamweaver 8.0.2 Updater 中修正。
此技術備註涵蓋 Dreamweaver 的 PHP 伺服器行為。針對 ColdFusion、ASP VBScript、ASP JavaScript 和 JSP 伺服器行為,有個別的技術備註。ASP.NET 伺服器行為不受影響。
解決方法
當您讓查詢字串傳遞參數時,請確定只傳遞預期的資訊。 Adobe 已建立 Dreamweaver 8.0.2 Updater,可降低 SQL 插入攻擊的風險。這些修正將納入 Dreamweaver 的所有後續版本中。更新 Dreamweaver 8 後,您需要將伺服器行為重新套用至使用這些行為的頁面,並將這些頁面重新部署至您的伺服器。
此技術備註的其餘部分說明如何手動編輯 Dreamweaver MX 2004 程式碼,以防止 PHP 伺服器模型的 SQL 注入攻擊。容易遭受這些攻擊的伺服器行為如下所列,並附上修正方法:
含篩選器的資料錄集
未經篩選的資料錄集無須經過修改,但經過篩選的資料錄集則需要。 在下方範例中,名為「rs_byDate」的 Dreamweaver MX 2004 記錄集已透過從 URL 參數傳入的日期值進行篩選。下方反白顯示的程式碼是需要變更的部分:
<?php $colname_rs_byDate = "1"; if (isset($_GET['relDate'])) { $colname_rs_byDate = (get_magic_quotes_gpc()) ? $_GET['relDate'] : addslashes($_GET['relDate']); } mysql_select_db($database_dreamqa2, $dreamqa2); $query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = '%s'", $colname_rs_byDate); $rs_byDate = mysql_query($query_rs_byDate, $dreamqa2) or die(mysql_error()); $row_rs_byDate = mysql_fetch_assoc($rs_byDate); $totalRows_rs_byDate = mysql_num_rows($rs_byDate); ?>
若要防止記錄集遭受 SQL 插入攻擊,應在頁面頂端附近建立自訂 GetSQLValueString() 函數。此函數會驗證查詢參數的資料類型。建立函數後,請更新記錄集程式碼以使用 GetSQLValueString() 函數。
修改後的程式碼:
$colname_rs_byDate = $_GET['relDate'];
更新記錄集程式碼,使用上面建立的 GetSQLValueString() 函式來建立 SQL 字串。更新變數 $query_rs_byDate 的值:
原始程式碼:
$query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = '%s'", $colname_rs_byDate);
修改後的安全程式碼:
$query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = %s", GetSQLValueString($colname_rs_byDate, "date"));
「插入」、「更新」和「刪除記錄」伺服器行為與「記錄插入表單」精靈
「插入」、「更新」和「刪除記錄」伺服器行為與「記錄插入表單」精靈已使用 GetSQLValueString() 函式,因此需要調整以防止 SQL 注入攻擊。只需變更 GetSQLValueString() 函式即可。
以下是原始程式碼。需要變更的行以黃色標示:
if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") {$theValue = (!get_magic_quotes_gpc()) ? addslashes($theValue) : $theValue; switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } }
更新變數 $theValue 的定義:
原始代碼:
$theValue = (!get_magic_quotes_gpc()) ? addslashes($theValue) : $theValue;
修改後的安全代碼:
$theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue);
「登入使用者」伺服器行為
以下是修復「登入使用者」伺服器行為的步驟:
修改建構登入 SQL 查詢的代碼。
原始代碼:
$LoginRS__query=sprintf("SELECT username, password FROM login WHERE username='%s' AND password='%s'", get_magic_quotes_gpc() ? $loginUsername : addslashes($loginUsername), get_magic_quotes_gpc() ? $password : addslashes($password));
修改後的安全代碼:
$LoginRS__query=sprintf("SELECT username, password FROM login WHERE username=%s AND password=%s", GetSQLValueString($loginUsername, "text"), GetSQLValueString($password, "text"));
「檢查新使用者」伺服器行為
「檢查新使用者」伺服器行為需要您先將「插入記錄」伺服器行為新增至頁面。 GetSQLValuesString() 函數隨附於「插入記錄」伺服器行為中。 只需要更新 GetSQLValuesString() 以更妥善處理 SQL 注入,並更新「檢查新使用者」伺服器行為以在傳遞參數時使用此函數。
修改代碼以建構登入 SQL 查詢,從而使用 GetSQLValuesString() 傳入參數。 在頁面頂端附近,找出開頭為 // *** Redirect if username exists.
原始代碼:
$LoginRS__query = "SELECT username FROM login WHERE username='" . $loginUsername . "'"
修改後的安全代碼:
$LoginRS__query = sprintf("SELECT username FROM login WHERE username=%s", GetSQLValueString($loginUsername, "text"));
「主要詳細資料頁面集」
對於「主要詳細資料頁面集」應用程式物件,其主要變更在於 Dreamweaver 針對「詳細資料頁面」所建立的資料錄集。 如果您的「主要頁面」中沒有經過篩選的資料錄集,則無須針對「主要頁面」做任何變更。 如果您有已篩選的記錄集,請參閱具有篩選器的記錄集以更新記錄集代碼。
Dreamweaver 會在「詳細資料頁面」中建立已篩選的記錄集,因此需要更新該記錄集代碼以使用 GetSQLValueString() 函數傳入參數,並使用 sprintf() 建構 SQL 字串。
更新變數宣告代碼並使用 GetSQLValuesString() 函數建構 SQL 查詢。
原始代碼:
$recordID = $_GET['recordID']; $query_DetailRS1 = "SELECT * FROM albums WHERE ID = $recordID";
修改後的安全代碼:
$colname_DetailRS1 = "-1"; if (isset($_GET['recordID'])) { $colname_DetailRS1 = (get_magic_quotes_gpc()) ? $_GET['recordID'] : addslashes($_GET['recordID']); } $query_DetailRS1 = sprintf("SELECT * FROM albums WHERE ID = %s", GetSQLValueString($colname_DetailRS1, "int"));
「記錄更新表單」精靈
其他資訊
如需有關 SQL 注入攻擊的詳細資訊,請參閱下列文章:Wikipedia 上有關 SQL 注入攻擊的文章。
Adobe 資訊安全公告:APSB 06-07 Dreamweaver Server Behavior SQL 注入攻擊弱點。