php SQL注入
9885 ワード
多くのWeb開発者は、SQLクエリーが改ざんされることに気づかず、SQLクエリーを信頼できるコマンドとしています.知りませんが、SQLクエリーはアクセス制御を迂回し、認証と権限チェックを迂回することができます.さらに、SQLクエリーを使用してホストOSレベルのコマンドを実行する可能性もあります.
直接SQLコマンド注入は、攻撃者が既存のSQL文を作成または変更する技術であり、隠しデータを取得したり、重要な値を上書きしたり、データベースホストオペレーティングシステムコマンドを実行したりする目的を達成します.これは、アプリケーションがユーザ入力を取得し、静的パラメータと組み合わせてSQLクエリーを作成することによって実現されます.以下に、いくつかの真実の例を示します.
入力したデータの検証が不足し、スーパーユーザーまたは新しいユーザーを作成する権限のある他のデータベースアカウントを使用して接続されているため、攻撃者はデータベースにスーパーユーザーを新規作成できます.
Example#1データのページング表示を実現するコード......スーパーユーザー(PostgreSQLシステム)の作成にも使用できます.
一般的なユーザーは、$offsetがビン値されている「前のページ」、「次のページ」のリンクをクリックします.元のコードは$offsetが数値だとしか思えません.しかし、次の文を先に通過しようとする人がいる場合は
urlencode()処理してURLに入れると:
彼はスーパーユーザーを作成することができますそれに注意
0; 元のクエリを完全に補完し、エラーが発生しないように正しいオフセット量を提供するためにすぎません.
Note:
--SQLのコメントタグです.一般的には、SQLインタプリタに後の文を無視するように伝えるために使用できます.
検索結果を表示するページに手をつけるのは、パスワードを得ることができる方法です.攻撃者がしなければならないのは、SQL文に使用され、適切に処理されていない変数を特定することにすぎません.このような変数は、通常、WHERE、ORDER BY、LIMIT、OFFSETなどのSELECTクエリの条件文に使用されます.データベースがUNION構造をサポートしている場合、攻撃者は任意のデータテーブルからパスワードを得るために完全なSQLクエリーを元の文に添付することもできます.したがって、パスワードフィールドの暗号化は重要です.
Example#2記事を表示します.パスワード(データベースシステム)
元のクエリーに基づいて別のクエリーを追加できます.
SELECTはパスワードを取得するために検索します:
上記の文が
'と
--)に$queryのいずれかの変数が加わると面倒になります.
SQLのUPDATEも攻撃を受ける.このクエリは、上記の例のように、別の完全なリクエストを挿入または添付することもできる.しかし、攻撃者はSET句に手を出したいと思っています.そうすれば、データテーブルのデータを変更することができます.この場合、クエリの変更に成功するには、データベースの構造を知る必要があります.フォーム上の変数名でフィールドを推測したり、暴力的に解読したりすることができます.ユーザー名とパスワードを格納するフィールドでは、名前を付ける方法は多くありません.
Example#3パスワードのリセットから、より多くの権限の取得まで(任意のデータベースシステム)
しかし悪意のあるユーザーは
' or uid like'%admin%'; -- 変数の値として$uidにコミットしてadminのパスワードを変更したり、$pwdの値を
「hehehehe',admin='yes',trusted=100」(後ろにスペースがある)では、より多くの権限を取得できます.すると、クエリ文は実際には次のようになります.
次の恐ろしい例では、一部のデータベースでシステムコマンドを実行する方法を示します.
Example#4データベースが存在するホストのオペレーティングシステム(MSSQL Server)を攻撃する
攻撃がコミットされた場合
a%' exec master..xp_cmdshell'net user test testpass/ADD'--変数$prodの値として$queryは
MSSQLサーバは、システムにユーザーを追加するコマンドを含むSQL文を実行します.もしこのプログラムが
saが実行され、MSSQLSERVERサービスに十分な権限があれば、攻撃者はシステムアカウントを取得してホストにアクセスすることができます.
Note:
以上の例は、特定のデータベース・システムに対するものであるが、他のデータベース・システムに対して同様の攻撃を実施できないわけではない.異なる方法では、さまざまなデータベースが被害を受ける可能性があります.
予防措置
攻撃者はデータベース構造の情報を知ってこそ、上記の攻撃を実施することができると自慰する人もいるかもしれません.そう、確かにそうです.しかし、攻撃者がこれらの情報を得られないことを保証する人はいません.しかし、データベースが漏れる危険があります.オープンソースのパッケージでデータベース、例えばフォーラムプログラムにアクセスしている場合、攻撃者は関連するコードを得ることができます.これらのコードの設計が不良であれば、リスクはさらに大きくなります.
これらの攻撃は常にセキュリティ意識の弱いコードを発掘する上で確立されている.したがって、外部から入力されたデータ、特にクライアントからのデータは、選択ボックス、フォーム非表示ドメイン、クッキーなど、いつまでも信頼しないでください.上記の最初の例のように、通常のクエリーでも災害が発生する可能性があります.
スーパーユーザーまたは所有者アカウントを使用してデータベースに接続しないでください.権限が厳しく制限されているアカウントを使用します.
入力したデータに所望のデータフォーマットがあるかどうかを確認します.PHPには入力をチェックできる関数がたくさんあります.簡単な変数関数や文字タイプ関数(is_numeric()など)、ctype_digit()から複雑なPerl互換正規表現関数まで、この作業を完了できます.
プログラムが数字の入力を待つ場合は、is_を使用することを考慮します.numeric()でチェックしたり、settype()を直接使用してタイプを変換したり、sprintf()で数値にフォーマットしたりすることができます.
Example#5ページングをより安全に実現する方法
データベース固有の機密文字エスケープ関数(mysql_escape_string()やsql_など)を使用するescape_string()は,ユーザが提出した非デジタルデータをエスケープする.データベースに専用の機密文字エスケープ機能がない場合addslashes()とstr_replace()はこの仕事を完成する代わりにすることができます.最初の例を見てみると、クエリの静的部分に引用符を付けるだけでは十分ではなく、クエリが簡単に破棄されます.
手段を選択しないと、データベースに関する信頼性、特にデータベース構造が表示されないようにします.エラーレポートとエラー処理関数を参照してください.
データベースのストアド・プロシージャや事前定義されたポインタなどのプロパティを使用して、データ・テーブルやビューに直接アクセスできないデータベース・アクセスを抽象化することもできます.しかし、この方法には別の影響がある.
また、許可されている場合は、コードまたはデータベース・システムを使用してクエリー・ログを保存するのも良い方法です.ログは攻撃を防ぐことはできませんが、どのプログラムが攻撃を試みたかを追跡することができます.ログ自体は役に立たないので、その中に含まれている情報を調べなければなりません.結局、もっと多くの情報はないよりいいです.
直接SQLコマンド注入は、攻撃者が既存のSQL文を作成または変更する技術であり、隠しデータを取得したり、重要な値を上書きしたり、データベースホストオペレーティングシステムコマンドを実行したりする目的を達成します.これは、アプリケーションがユーザ入力を取得し、静的パラメータと組み合わせてSQLクエリーを作成することによって実現されます.以下に、いくつかの真実の例を示します.
入力したデータの検証が不足し、スーパーユーザーまたは新しいユーザーを作成する権限のある他のデータベースアカウントを使用して接続されているため、攻撃者はデータベースにスーパーユーザーを新規作成できます.
Example#1データのページング表示を実現するコード......スーパーユーザー(PostgreSQLシステム)の作成にも使用できます.
<?php
$offset = $argv[0]; // , !
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
$result = pg_query($conn, $query);
?>
一般的なユーザーは、$offsetがビン値されている「前のページ」、「次のページ」のリンクをクリックします.元のコードは$offsetが数値だとしか思えません.しかし、次の文を先に通過しようとする人がいる場合は
urlencode()処理してURLに入れると:
0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
select 'crack', usesysid, 't','t','crack'
from pg_shadow where usename='postgres';
--
彼はスーパーユーザーを作成することができますそれに注意
0; 元のクエリを完全に補完し、エラーが発生しないように正しいオフセット量を提供するためにすぎません.
Note:
--SQLのコメントタグです.一般的には、SQLインタプリタに後の文を無視するように伝えるために使用できます.
検索結果を表示するページに手をつけるのは、パスワードを得ることができる方法です.攻撃者がしなければならないのは、SQL文に使用され、適切に処理されていない変数を特定することにすぎません.このような変数は、通常、WHERE、ORDER BY、LIMIT、OFFSETなどのSELECTクエリの条件文に使用されます.データベースがUNION構造をサポートしている場合、攻撃者は任意のデータテーブルからパスワードを得るために完全なSQLクエリーを元の文に添付することもできます.したがって、パスワードフィールドの暗号化は重要です.
Example#2記事を表示します.パスワード(データベースシステム)
<?php
$query = "SELECT id, name, inserted, size FROM products
WHERE size = '$size'
ORDER BY $order LIMIT $limit, $offset;";
$result = odbc_exec($conn, $query);
?>
元のクエリーに基づいて別のクエリーを追加できます.
SELECTはパスワードを取得するために検索します:
'
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable;
--
上記の文が
'と
--)に$queryのいずれかの変数が加わると面倒になります.
SQLのUPDATEも攻撃を受ける.このクエリは、上記の例のように、別の完全なリクエストを挿入または添付することもできる.しかし、攻撃者はSET句に手を出したいと思っています.そうすれば、データテーブルのデータを変更することができます.この場合、クエリの変更に成功するには、データベースの構造を知る必要があります.フォーム上の変数名でフィールドを推測したり、暴力的に解読したりすることができます.ユーザー名とパスワードを格納するフィールドでは、名前を付ける方法は多くありません.
Example#3パスワードのリセットから、より多くの権限の取得まで(任意のデータベースシステム)
<?php
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
?>
しかし悪意のあるユーザーは
' or uid like'%admin%'; -- 変数の値として$uidにコミットしてadminのパスワードを変更したり、$pwdの値を
「hehehehe',admin='yes',trusted=100」(後ろにスペースがある)では、より多くの権限を取得できます.すると、クエリ文は実際には次のようになります.
<?php
// $uid == ' or uid like'%admin%'; --
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";
// $pwd == "hehehe', admin='yes', trusted=100 "
$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
...;";
?>
次の恐ろしい例では、一部のデータベースでシステムコマンドを実行する方法を示します.
Example#4データベースが存在するホストのオペレーティングシステム(MSSQL Server)を攻撃する
<?php
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";
$result = mssql_query($query);
?>
攻撃がコミットされた場合
a%' exec master..xp_cmdshell'net user test testpass/ADD'--変数$prodの値として$queryは
<?php
$query = "SELECT * FROM products
WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);
?>
MSSQLサーバは、システムにユーザーを追加するコマンドを含むSQL文を実行します.もしこのプログラムが
saが実行され、MSSQLSERVERサービスに十分な権限があれば、攻撃者はシステムアカウントを取得してホストにアクセスすることができます.
Note:
以上の例は、特定のデータベース・システムに対するものであるが、他のデータベース・システムに対して同様の攻撃を実施できないわけではない.異なる方法では、さまざまなデータベースが被害を受ける可能性があります.
予防措置
攻撃者はデータベース構造の情報を知ってこそ、上記の攻撃を実施することができると自慰する人もいるかもしれません.そう、確かにそうです.しかし、攻撃者がこれらの情報を得られないことを保証する人はいません.しかし、データベースが漏れる危険があります.オープンソースのパッケージでデータベース、例えばフォーラムプログラムにアクセスしている場合、攻撃者は関連するコードを得ることができます.これらのコードの設計が不良であれば、リスクはさらに大きくなります.
これらの攻撃は常にセキュリティ意識の弱いコードを発掘する上で確立されている.したがって、外部から入力されたデータ、特にクライアントからのデータは、選択ボックス、フォーム非表示ドメイン、クッキーなど、いつまでも信頼しないでください.上記の最初の例のように、通常のクエリーでも災害が発生する可能性があります.
スーパーユーザーまたは所有者アカウントを使用してデータベースに接続しないでください.権限が厳しく制限されているアカウントを使用します.
入力したデータに所望のデータフォーマットがあるかどうかを確認します.PHPには入力をチェックできる関数がたくさんあります.簡単な変数関数や文字タイプ関数(is_numeric()など)、ctype_digit()から複雑なPerl互換正規表現関数まで、この作業を完了できます.
プログラムが数字の入力を待つ場合は、is_を使用することを考慮します.numeric()でチェックしたり、settype()を直接使用してタイプを変換したり、sprintf()で数値にフォーマットしたりすることができます.
Example#5ページングをより安全に実現する方法
<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// %d, %s
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",
$offset);
?>
データベース固有の機密文字エスケープ関数(mysql_escape_string()やsql_など)を使用するescape_string()は,ユーザが提出した非デジタルデータをエスケープする.データベースに専用の機密文字エスケープ機能がない場合addslashes()とstr_replace()はこの仕事を完成する代わりにすることができます.最初の例を見てみると、クエリの静的部分に引用符を付けるだけでは十分ではなく、クエリが簡単に破棄されます.
手段を選択しないと、データベースに関する信頼性、特にデータベース構造が表示されないようにします.エラーレポートとエラー処理関数を参照してください.
データベースのストアド・プロシージャや事前定義されたポインタなどのプロパティを使用して、データ・テーブルやビューに直接アクセスできないデータベース・アクセスを抽象化することもできます.しかし、この方法には別の影響がある.
また、許可されている場合は、コードまたはデータベース・システムを使用してクエリー・ログを保存するのも良い方法です.ログは攻撃を防ぐことはできませんが、どのプログラムが攻撃を試みたかを追跡することができます.ログ自体は役に立たないので、その中に含まれている情報を調べなければなりません.結局、もっと多くの情報はないよりいいです.