PHP SQLインジェクション攻撃の防御方法とインジェクション分析_PHPチュートリアル

WBOY
リリース: 2016-07-13 17:09:49
オリジナル
854 人が閲覧しました

1. PHP チュートリアル設定ファイル php.ini の magic_quotes_gpc オプションがオンになっておらず、オフに設定されています。 2. 開発者はデータ型をチェックしてエスケープしませんでした

しかし、実際には 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 公式の説明です:

ソースプリントを表示しますか?

magic_quotes_gpc ブール値

gpc (get/post/cookie) 操作の magic_quotes 状態を設定します。magic_quotes がオンの場合、すべての ' (一重引用符)、" (二重引用符)、(バックスラッシュ)、および null はバックスラッシュで自動的にエスケープされます。

逃げ場がない場合、つまりオフの場合、攻撃者に付け入る機会を与えてしまいます。次のテスト スクリプトを例として取り上げます:

1

2if ( isset($_post["f_login"] ) )
3{
4 // データベースへの接続に関するチュートリアル...
5 // ...コードは省略されています...
6
7 // ユーザーが存在するかどうかを確認します
8 $t_struname = $_post["f_uname"];
9 $t_strpwd = $_post["f_pwd"];
10 $t_strsql = "select * from tbl_users where username='$t_struname'、password = '$t_strpwd' 制限 0,1";
11
12 if ( $t_hres = mysql_query($t_strsql) )
13
14 // クエリが成功した後の処理。少し...
15 }
16}
17?>
18
19サンプルテスト
20
21


22 ユーザー名:

23 パスワード:

24
25
26

27

このスクリプトでは、ユーザーが通常のユーザー名とパスワードを入力すると、値がそれぞれ zhang3 と abc123 であると仮定すると、送信される SQL ステートメントは次のようになります。

tbl_users から * を 1 つ選択

2 ユーザー名 = 'zhang3' およびパスワード = 'abc123' 制限 0,1

攻撃者がユーザー名フィールドに zhang3' または 1=1 # を入力し、パスワード フィールドに abc123 を入力すると、送信される SQL ステートメントは次のようになります:

tbl_users から * を 1 つ選択

2 ここで、ユーザー名 = 'zhang3' または 1=1 #' およびパスワード = 'abc123' 制限 0,1

# は mysql のコメント文字であるため、# の後のステートメントは実行されません。この行のステートメントを実装するには、次のようになります。
tbl_users から * を 1 つ選択

2 ユーザー名='zhang3' または 1=1


これにより、攻撃者は認証をバイパスできます。攻撃者がデータベース構造を知っている場合、ユニオン選択を構築しますが、これはさらに危険です:


ユーザー名に zhang3 ' または 1 =1 Union select cola,colb,cold from tbl_b #

と入力するとします。

パスワードを入力してください: abc123,

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

tbl_users から * を 1 つ選択

2 ユーザー名 = 'zhang3 '

3 または 1 =1 ユニオンは tbl_b #' から cola、colb、cold を選択し、パスワード = 'abc123' 制限 0,1

これはかなり危険です。 agic_quotes_gpc オプションがオンで引用符がエスケープされている場合、上記の攻撃者が作成した攻撃ステートメントは次のようになり、その目的を達成できません:


tbl_users から * を 1 つ選択

2 ここで、ユーザー名='zhang3' または 1=1 #'

3 とパスワード = 'abc123'
4 リミット 0,1
5
6 tbl_users から * を選択します
7 where username='zhang3 ' または 1 =1 Union select cola、colb、cold from tbl_b #'
8 およびパスワード = 'abc123' 制限 0,1

2. magic_quotes_gpc = on の場合のインジェクション攻撃

magic_quotes_gpc = on の場合、攻撃者は文字フィールドに対して SQL インジェクションを実行できません。だからといって安全というわけではありません。現時点では、数値フィールドを通じて SQL インジェクションを実行できます。

最新バージョンの mysql 5.x では、データ型の入力が制限され、自動型変換がデフォルトでオフになっています。数値フィールドを引用符でマークされた文字タイプにすることはできません。言い換えれば、uid が数値であると仮定すると、以前の mysql バージョンでは、このようなステートメントは正当です:

1 tbl_user set uid="1" に挿入します;
2 select * from tbl_user where uid="1";


最新の mysql 5.x では、上記のステートメントは合法ではないため、次のように記述する必要があります:

1 tbl_user set uid=1 に挿入;
2 select * from tbl_user where uid=1;


これは正しいと思います。開発者として、ルールに準拠した正しいデータ型をデータベースに送信することが最も基本的な要件だからです。

では、magic_quotes_gpc = on の場合、攻撃者はどのように攻撃するのでしょうか?非常に簡単で、数値フィールドに対して SQL インジェクションを実行するだけです。次の php スクリプトを例として取り上げます:

1
2 if ( isset($_post["f_login"] ) )
3{
4 // データベースに接続します...
5 // ...コードは省略されています...
6
7 // ユーザーが存在するかどうかを確認します
8 $t_struid = $_post["f_uid"];
9 $t_strpwd = $_post["f_pwd"];
10 $t_strsql = "select * from tbl_users where uid=$t_struid、password = '$t_strpwd' 制限 0,1";
11 if ( $t_hres = mysql_query($t_strsql) )
12{
13 // クエリが成功した後の処理中です...
14 }
15
16}
17 ?>
18 サンプルテスト
19
20


21 ユーザー ID:

22
23 パスワード:

24
25

26 体>


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

select * from tbl_users where userid = 1001、password = 'abc123' 制限 0,1

攻撃者が userid に「1001 or 1 =1 #」と入力した場合、挿入される SQL ステートメントは次のようになります。

select * from tbl_users where userid=1001 or 1 =1 # andpassword = 'abc123' 制限 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 ステートメントを出力することに慣れています。たとえば、次のようになります。 1 $t_strsql = "select a from b....";

2 if (mysql_query($t_strsql) )
3{
4 // 正しい取り扱い
5}
他6個
7{
8 echo "エラー! SQL ステートメント: $t_strsql rn エラー メッセージ".mysql_query();
9 出口;
10}


このアプローチは非常に危険で愚かです。これを行う必要がある場合は、グローバル変数を設定するか、Web サイト設定ファイルでマクロを定義してデバッグ フラグを設定することをお勧めします:

 1 //全局配置文件中:
 2 define("debug_mode",0);    // 1: debug mode; 0: release mode
 3
 4 //调用脚本中:
 5 $t_strsql = "select a from b....";
 6 if ( mysql_query($t_strsql) )
 7 {
 8   // 正确的处理
 9 }
10 else
11 {
12   if (debug_mode)
13     echo "错误! sql 语句:$t_strsql rn错误信息".mysql_query();
14   exit;
15 }

 

 

 
 

 

对提交的 sql 语句,进行转义和类型检查。

 

四. 我写的一个安全参数获取函数

为了防止用户的错误数据和 php + mysql 注入 ,我写了一个函数 papi_getsafeparam(),用来获取安全的参数值:

 1 define("xh_param_int",0);
 2 define("xh_param_txt",1);
 3 function papi_getsafeparam($pi_strname, $pi_def = "", $pi_itype = xh_param_txt)
 4 {
 5   if ( isset($_get[$pi_strname]) )
 6     $t_val = trim($_get[$pi_strname]);
 7   else if ( isset($_post[$pi_strname]))
 8     $t_val = trim($_post[$pi_strname]);
 9   else
10     return $pi_def;
11
12   // int
13   if ( xh_param_int == $pi_itype)
14   {
15     if (is_numeric($t_val))
16       return $t_val;
17     else
18       return $pi_def;
19   }
20  
21   // string
22   $t_val = str_replace("&", "&",$t_val);
23   $t_val = str_replace("<", "<",$t_val);
24 $t_val = str_replace(">", ">",$t_val);
25   if ( get_magic_quotes_gpc() )
26   {
27     $t_val = str_replace(""", """,$t_val);
28     $t_val = str_replace("''", "'",$t_val);
29   }
30   else
31   {
32     $t_val = str_replace(""", """,$t_val);
33     $t_val = str_replace("'", "'",$t_val);
34   }
35   return $t_val;
36 }

 

 

 


在这个函数中,有三个参数:

$pi_strname: 变量名
$pi_def: 默认值
$pi_itype: 数据类型。取值为 xh_param_int, xh_param_txt, 分别表示数值型和文本型。

 

 

 


如果请求是数值型,那么调用 is_numeric() 判断是否为数值。如果不是,则返回程序指定的默认值。

简单起见,对于文本串,我将用户输入的所有危险字符(包括html代码),全部转义。由于 php 函数 addslashes()存在漏洞,我用 str_replace()直接替换。get_magic_quotes_gpc() 函数是 php 的函数,用来判断 magic_quotes_gpc 选项是否打开。

刚才第二节的示例,代码可以这样调用:

 1 2 if ( isset($_post["f_login"] ) )
3 {
4 // 连接数据库...
5 // ...代码略...
6
7 // 检查用户是否存在
8 $t_struid = papi_getsafeparam("f_uid", 0, xh_param_int);
9 $t_strpwd = papi_getsafeparam("f_pwd", "", xh_param_txt);
10 $t_strsql = "select * from tbl_users where uid=$t_struid and password = '$t_strpwd' limit 0,1";
11 if ( $t_hres = mysql_query($t_strsql) )
12 {
13 // 成功查询之后的处理. 略...
14 }
15 }
16 ?>

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/629717.html技術記事 1. PHP チュートリアル設定ファイル php.ini の magic_quotes_gpc オプションがオンになっておらず、オフに設定されている 2. 開発者がデータ型をチェックしてエスケープしなかった しかし、実際には 2 番目の点が最も重要です。
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!