ホームページ  >  記事  >  バックエンド開発  >  PHP+SQL インジェクション攻撃の技術的な実装と防止方法_PHP チュートリアル

PHP+SQL インジェクション攻撃の技術的な実装と防止方法_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-21 15:32:40828ブラウズ

経験を要約します。私の考えでは、SQL インジェクション攻撃の主な原因は次の 2 つの理由です:
1. PHP 設定ファイル php.ini の magic_quotes_gpc オプションがオンになっておらず、オフに設定されている
2. 開発者がデータを設定していないtype 検査とエスケープ
しかし、実際には 2 番目の点が最も重要です。ユーザーが入力したデータ型をチェックし、正しいデータ型を MYSQL に送信することは、Web プログラマーの最も基本的な資質であるべきだと思います。しかし実際には、多くの初心者 Web 開発者はこれを忘れて、バックドアが大きく開いたままになっていることがよくあります。
なぜ2番目の点が最も重要なのでしょうか? 2 番目の保証がないと、magic_quotes_gpc オプションがオンかオフかに関係なく、SQL インジェクション攻撃を引き起こす可能性があるためです。技術的な実装を見てみましょう:
1. magic_quotes_gpc = Off の場合のインジェクション攻撃
magic_quotes_gpc = Off は、php の非常に安全でないオプションです。新しいバージョンの PHP では、デフォルト値が On に変更されました。しかし、オプションがオフになっているサーバーがまだかなりの数あります。結局のところ、サーバーがどんなに古いものであっても、まだそれを使用している人がいます。
magic_quotes_gpc = On の場合、送信された変数の前にあるすべての '(一重引用符)、"(二重記号)、(バックスラッシュ)、空白文字が自動的に追加されます。 以下は PHP 公式の説明です:

Copy code コードは次のとおりです:

magic_quotes_gpc boolean

magic_quotes がオンの場合、すべての ' (一重引用符)、" (二重引用符)、 (バックスラッシュ) と NUL はバックスラッシュで自動的にエスケープされます

エスケープがない場合、つまりオフの場合、攻撃者に機会を与えてしまいます。次のテスト スクリプトを例に挙げます:
コードをコピーします コードは次のとおりです:

if ( isset($_POST["f_login"] ) )
{
// Connectデータベースへ...
/ /...コードは省略されています...

// ユーザーが存在するかどうかを確認します
$t_strUname = $_POST["f_uname"];
$t_strPwd = $_POST["f_pwd" ];
$t_strSQL = "SELECT * FROM tbl_users WHERE ユーザー名='$t_strUname' AND パスワード = '$t_strPwd' LIMIT 0,1";

if ( $t_hRes = mysql_query($t_strSQL) )
{
// 処理中クエリが成功した後...
}
?>

サンプルテスト

ユーザー名:

パスワード: ;



通常のユーザー名とパスワード、想定される値はそれぞれ zhang3、abc123 です。送信された SQL ステートメントは次のとおりです:



コードをコピー

コードは次のとおりです:
SELECT * FROM tbl_users WHERE username= 'zhang3' AND パスワード = 'abc123' LIMIT 0,1
If 攻撃者がユーザー名フィールドに zhang3' OR 1=1 # を入力し、パスワード フィールドに abc123 を入力すると、送信される SQL ステートメントは次のようになります:



コードをコピー

コードは次のとおりです:
SELECT * FROM tbl_users WHERE username='zhang3' OR 1=1 #' AND Password = 'abc123' LIMIT 0,1
#はコメントなのでmysql の # 以降のステートメントは実行されません。この行のステートメントを実装するには、次のようになります。



コードをコピーします

コードは次のとおりです:
SELECT * FROM tbl_users WHERE username=' zhang3' OR 1=1
こうすることで攻撃者は認証を回避できます。攻撃者がデータベース構造を知っている場合、UNION SELECT を構築しますが、これはさらに危険です:

ユーザー名を入力するとします: zhang3 ' OR 1 =1 UNION select cola,colb,cold FROM tbl_b #

パスワードを入力: abc123,

送信された SQL ステートメントは次のようになります:



Copy code

コードは次のとおりです:
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) )
{
// クエリ成功後の処理省略しました...
}

}
サンプルテスト

ユーザー ID:


パスワード:




上記のスクリプトではユーザー ID を入力する必要があります。とログインするためのパスワード。通常のステートメントでは、ユーザーは 1001 と abc123 を入力し、送信された SQL ステートメントは次のとおりです:

SELECT * FROM tbl_users WHERE userid=1001 AND Password = 'abc123' LIMIT 0,1
攻撃者が 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

tru​​e

http://www.bkjia.com/PHPjc/322736.html

技術記事

経験を要約します。私の考えでは、SQL インジェクション攻撃の主な原因は次の 2 つの理由です: 1. PHP 設定ファイル php.ini の magic_quotes_gpc オプションがオンになっておらず、...





声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:PHP_PHP チュートリアルで Discuz フォーラムのログイン ユーザー名、ユーザー グループ、ユーザー ID、およびその他の情報を取得するための実装コード次の記事:PHP_PHP チュートリアルで Discuz フォーラムのログイン ユーザー名、ユーザー グループ、ユーザー ID、およびその他の情報を取得するための実装コード

関連記事

続きを見る