コードビューの 2 行目、接続のインクルードファイルの直後に移動し、次のように 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; } } ?>
問題
一部のデータベースでは、1 つのクエリで複数の SQL ステートメントを送信できます。 そのため、クエリ文字列でパラメーターを動的に生成されたデータベースクエリに渡すときには、潜在的なセキュリティリスクがあります。ハッカーは既存のパラメーターに悪意のある SQL 文を追加することによって、動的クエリの URL またはフォーム変数を変更しようとする可能性があります。これが SQL インジェクション攻撃と呼ばれるものです。 Dreamweaver で作成されるサーバービヘイビアーコードの一部は、SQL インジェクション攻撃のリスクを軽減するために変更する必要があります。 SQL インジェクションのバックグラウンド情報の詳細は、こちらの Wikipedia の記事を参照してください。 (参照 201713)
注意:このテクニカルノートで説明されている問題は、Dreamweaver 8.0.2 Updater で修正されています。
このテクニカルノートでは、Dreamweaver の PHP サーバービヘイビアーについて説明します。ColdFusion、ASP VBScript、ASP JavaScript、JSP の各サーバービヘイビアーについては、別途テクニカルノートがあります。ASP.NET サーバービヘイビアーは影響を受けません。
解決策
クエリ文字列でパラメータを渡すときは、必ず、予期される情報のみを渡します。 アドビでは、SQL インジェクション攻撃のリスクを軽減する Dreamweaver 8.0.2 Updater を作成しました。これらの修正は、Dreamweaver の今後のすべてのリリースに組み込まれます。Dreamweaver 8 を更新した後、サーバービヘイビアーを使用するページに対してサーバービヘイビアーを再適用し、これらのページをサーバーに再デプロイする必要があります。
このテクニカルノートの残りの部分では、PHP サーバーモデルで SQL インジェクション攻撃を防ぐために Dreamweaver MX 2004 コードを手動で編集する方法について説明します。これらの攻撃に対して脆弱なサーバービヘイビアーと修正方法を以下に示します:
フィルター付きレコードセット
フィルター処理していないレコードセットは修正する必要はありませんが、フィルター処理したレコードセットは修正する必要があります。 以下の例では、「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"));
Insert、Update、およびDelete RecordサーバービヘイビアーとRecord Insertion Formウィザード
Insert、Update、およびDelete RecordサーバービヘイビアーとRecord Insertion Formウィザードは既に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() 関数は Insert Record サーバービヘイビアに含まれています。必要なのは、GetSQLValuesString()を更新してSQLインジェクションをより適切に処理し、Check New Userサーバービヘイビアを更新してパラメーターが渡されたときにこの関数を使用することだけです。
ログイン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()関数を使用し、SQL文字列を構築するためにsprintf()を使用するように更新する必要があります。
変数宣言コードを更新し、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インジェクションの詳細については、次の記事を参照してください:SQLインジェクションに関するWikipediaの記事。
アドビセキュリティ情報:APSB 06-07 Dreamweaver サーバービヘイビアー SQL インジェクションの脆弱性。