If 攻撃者がユーザー名フィールドに zhang3' OR 1=1 # を入力し、パスワード フィールドに abc123 を入力すると、送信される SQL ステートメントは次のようになります:
SELECT * FROM tbl_users WHERE username='zhang3 ' OR 1 =1 UNION select cola,colb,cold FROM tbl_b #' AND password = 'abc123' LIMIT 0,1
これはかなり危険です。 agic_quotes_gpc オプションがオンで引用符がエスケープされている場合、上記の攻撃者が作成した攻撃ステートメントは次のようになり、その目的を達成できません:
コードをコピーします コードは次のとおりです:
SELECT * FROM tbl_users
WHERE username='zhang3' OR 1=1 #'
AND password = 'abc123'
LIMIT 0,1
SELECT * FROM tbl_users
WHERE username='zhang3 ' OR 1 =1 UNION コーラを選択、 Colb,cold FROM tbl_b #'
AND パスワード = 'abc123' LIMIT 0,1
2. magic_quotes_gpc = On の場合のインジェクション攻撃
magic_quotes_gpc = On の場合、攻撃者は文字フィールドに対して SQL インジェクションを実行できません。だからといって安全というわけではありません。現時点では、SQL インジェクションは数値フィールドを通じて実行できます。
最新バージョンのMYSQL 5.xでは、データ型の入力が厳格化され、自動型変換がデフォルトでオフになっています。数値フィールドを引用符でマークされた文字タイプにすることはできません。つまり、以前の mysql バージョンでは、uid が数値であると仮定すると、このようなステートメントは正当です:
コードをコピー コードは次のとおりです:
INSERT INTO tbl_user SET uid="1";
SELECT * FROM tbl_user WHERE uid="1";
最新の MYSQL 5.x では、上記のステートメントは次のように記述する必要があります:
コードをコピー コードは次のとおりです:
INSERT INTO tbl_user SET uid=1;
SELECT * FROM tbl_user WHERE uid=1;
これは正しいと思います。開発者として、ルールに準拠した正しいデータ型をデータベースに送信することが最も基本的な要件だからです。
では、magic_quotes_gpc = Onの場合、攻撃者はどのように攻撃するのでしょうか?非常に簡単で、数値フィールドに対して SQL インジェクションを実行するだけです。次の php スクリプトを例に挙げます:
コードをコピーします コードは次のとおりです:
if ( isset($_POST["f_login"] ) )
{
// Connectデータベースへ...
// ...コードは省略されています...
// ユーザーが存在するかどうかを確認します
$t_strUid = $_POST["f_uid"];
$t_strPwd = $_POST["f_pwd" ];
$t_strSQL = "SELECT * FROM tbl_users WHERE uid=$t_strUid AND パスワード = '$t_strPwd' LIMIT 0,1";
if ( $t_hRes = mysql_query($t_strSQL) )
{
// クエリ成功後の処理省略しました...
}
}
サンプルテスト
攻撃者が userid にいる場合は、次のように入力します。 1001 OR 1 =1 #、挿入された SQL ステートメントは次のとおりです:
SELECT * FROM tbl_users WHERE userid=1001 OR 1 =1 # AND パスワード = 'abc123' LIMIT 0,1
攻撃者は目的を達成しました。
3. PHP SQLインジェクション攻撃を防ぐ方法
PHP SQLインジェクション攻撃を防ぐにはどうすればよいでしょうか?最も重要な点は、データ型をチェックしてエスケープすることだと思います。要約されたルールは次のとおりです。
php.ini の display_errors オプションは、display_errors = off に設定する必要があります。これにより、php スクリプトでエラーが発生した後は、Web ページにエラーが出力されなくなり、攻撃者による有用な情報の分析が防止されます。
mysql_query などの mysql 関数を呼び出すときは、mysql エラーが出力されないように、先頭に @ を追加する必要があります。つまり @mysql_query(...) です。攻撃者が有益な情報を分析できないようにする場合も同様です。さらに、一部のプログラマーは、開発時に mysql_query エラーが発生したときにエラーと SQL ステートメントを出力することに慣れています。たとえば、次のようになります。 . ";
if ( mysql_query($t_strSQL) )
{
// 正しい処理
}
else
{
echo "エラー! SQL ステートメント: $t_strSQL rnError メッセージ".mysql_query();
exit; } このやり方はかなり危険で愚かです。これを行う必要がある場合は、Web サイト設定ファイルでグローバル変数を設定するかマクロを定義してデバッグ フラグを設定することをお勧めします:
グローバル設定ファイル内:
コードをコピー コードは次のとおりです。以下:
define("DEBUG_MODE",0); // 1: DEBUG MODE; 0: RELEASE MODE
// 呼び出しスクリプト:
$t_strSQL = "SELECT a from b...."; ( mysql_query($t_strSQL ) )
{
// 正しい処理
}
else
{
if (DEBUG_MODE)
echo "エラー! SQL ステートメント: $t_strSQL rn エラー メッセージ".mysql_query()
;
Submit SQL ステートメントはエスケープされ、型がチェックされます。
IV. 私が作成した安全なパラメータ取得関数
ユーザーが誤ったデータや php + mysql インジェクションを防ぐために、安全なパラメータ値を取得する関数 PAPI_GetSafeParam() を作成しました:
コードをコピー
コードは次のとおりです。 define("XH_PARAM_INT",0);
define("XH_PARAM_TXT",1);
function PAPI_GetSafeParam($pi_strName, $pi_Def = "", $pi_iType = XH_PARAM_TXT)
{
if ( isset($ _GET[ $pi_strName]) )
$t_Val = trim($_GET[$pi_strName]);
else if ( isset($_POST[$pi_strName]))
Else
Return $ PI_DEF;
// int
If (xh_param_int == $ Pi_itype) {
IF (is_numeric ($ t_val))
erturn $ t_val; // string
$t_Val = str_replace("&", "&",$t_Val);
$t_Val = str_replace("<", "<",$t_Val); ( get_magic_quotes_gpc() )
{
$t_Val = str_replace("\"", """,$t_Val);
$t_Val = str_replace("\''", "' ",$t_Val);
{
$t_Val = str_replace(""", """,$t_Val);
$t_Val = str_replace("'", "'",$t_Val);この関数には 3 つのパラメータがあります:
$pi_strName: 変数名
$pi_Def: デフォルト値
$pi_iType: データ型。値は XH_PARAM_INT と XH_PARAM_TXT で、それぞれ数値型とテキスト型を表します。
リクエストが数値の場合は、is_numeric()を呼び出して、それが数値であるかどうかを判断します。そうでない場合は、プログラム指定のデフォルト値が返されます。
簡単にするために、テキスト文字列については、ユーザーが入力したすべての危険な文字 (HTML コードを含む) をエスケープします。 PHPの関数addlashes()に脆弱性があるため、str_replace()に直接置き換えました。 get_magic_quotes_gpc() 関数は PHP 関数であり、magic_quotes_gpc オプションがオンになっているかどうかを判断するために使用されます。
2番目のセクションの例ですが、コードは次のように呼び出すことができます:
コードをコピー
コードは次のとおりです:
<
if ( isset($_POST["f_login? "] ) )
{
/ / データベースに接続します...
// ...コードは省略されています...
// ユーザーが存在するかどうかを確認します
$t_strUid = PAPI_GetSafeParam("f_uid", 0, XH_PARAM_INT);
$t_strPwd = PAPI_GetSafeParam("f_pwd", "", クエリ成功後の処理。簡単に言うと...
}
}
?>
この場合、すでにかなり安全です。 PAPI_GetSafeParam のコードは少し長いですが、セキュリティを確保するためにこの効率を犠牲にする価値はあります。皆さんももっと私を批判し、修正していただければ幸いです。 :)
http://www.bkjia.com/PHPjc/322736.html
www.bkjia.com
true
http://www.bkjia.com/PHPjc/322736.html
技術記事
経験を要約します。私の考えでは、SQL インジェクション攻撃の主な原因は次の 2 つの理由です: 1. PHP 設定ファイル php.ini の magic_quotes_gpc オプションがオンになっておらず、...