TOP書籍連動> パフォーマンスの維持




SQLインジェクション
SQLインジェクション

第3回:SQLインジェクションの注意点

著者:Ilia Alshanetsky   2006/1/31
前のページ  1  2  3
パフォーマンスの維持

   普通、スピードが安全性の尺度になることはありませんが、アプリケーションのパフォーマンスが低下することはどんな攻撃に対しても同じ効果があります。%をLIKEで使用させる攻撃が実行されると、高い負荷がかかることに触れましたが、データベースに負荷の大きい繰り返し作業が実行されるとサーバの能力が飽和して新たなコネクションを張ることができなくなります。

   クエリが最適化されていないのと同様の危険性を抱えることになります。クラッカーがそこに目をつけて攻撃してくると、サーバにかかる負荷が増大して同様に新たな処理ができなくなってしまうのです。

   データベースの過負荷を防ぐために、簡単なルールをいくつか覚えておきましょう。まず1つめは、必要なデータだけを取り出すようにする、ということです。'*'を使ってすべてのカラムのデータを取り出している開発者はたくさんいますが、特に複数のテーブルを結合した時には非常に多くのデータを取り出すことになる場合があります。

   データが多いということは取り出した情報が多いということで、データベースがソートに使う一次バッファにより多くのメモリが消費されてしまいます。また、PHPに結果を渡すまでにより多くの時間がかかり、PHPアプリケーションでデータを整形するのにより多くのメモリと時間が必要になり、アプリケーションの速度が低下します。

   それを防ぐために、必要なカラムのみを指定してバッファをなるべく使用しないようにしましょう。クエリの実行速度を飛躍的に上げるために、実行したクエリの結果を小さな断片で少しずつ取り出す、アンバッファードクエリを使ってみてください。(MySQLの場合は、結果カーソルから結果をすべて取り出すまでINSERTやUPDATEなど、他のクエリを実行することはできません。)

   データベースを利用するために、PHPはデータベースへのコネクションを張らなければならないのですが、特にOracle、PostgreSQL、MSSQLなど複雑なシステムの場合には多くのメモリが必要となることがあります。コネクションを張るプロセスをスピードアップする方法の1つが、永続的なコネクションを張ることです。永続的なコネクションを張るとスクリプトを終了してからもデータベースハンドルが有効なまま残ります。

   コネクションが永続的だと、同じウェブサーバプロセスからコネクション要求があった時にコネクションを新たに作るのではなく、再利用するようになります。次のコードではmysql_pconnect()関数を使って永続的なMySQLデータベースコネクションを作っています。普通のmysql_connect()関数と構文的には同じです。

mysql_pconnect("host", "login", "passwd");

   他のよく使われるデータベースでも永続的接続の関数が提供されていて、大体'connect'という単語にpを付け加えたようなシンプルなものになっています。PHPが永続的コネクションを張ろうとする時は、まず同じ認証の値を持つコネクションがすでに存在しないかをチェックします。そのコネクションが使える場合は、PHPは新たなコネクションを作る代わりにそのデータベースハンドルを返します。


注意点

   永続的コネクションにも欠点がないわけではありません。例えばPHPでは、すべてのサーバプロセスでコネクションプーリングが可能な場合、コネクションプーリングをウェブサーバ単位ではなくてプロセス単位で行います。従って、50のApacheプロセスがあれば50のデータベースコネクションが存在することになります。

   データベースがそこまで多くの接続を許可しないように設定されている場合、許可数を超えた分の接続はすべて拒絶され、Webページは止まってしまうことになります。

   データベースがウェブサーバと同じマシン上で動いていることがよくありますが、その場合はデータ転送を最適化できます。遅いTCP/IPを使う代わりに、内部プロセス間通信(Inter Process Communication、IPC)としては2番目に速いUnix Domein Socket(UDG) を利用することができます。

   UDGに切り替えると、2つのサーバ間のデータ伝送速度が飛躍的に向上します。UDGに切り替えるには、コネクションのホストパラメータを変えます。例えばMySQLではホストをUDG へのパスに続けて記述します。

mysql_connect(":/tmp/mysql.sock", "login" , "passwd");
pg_connect("host=/tmp user=login password=passwd");

   特にホストを指定する必要がないPostgreSQLでは、単にホストパラメータをUDGのあるディレクトリに設定すればOKです。


クエリのキャッシュ

   ある状況下では、クエリは最適化され実行されますが、それでも一定の時間がかかります。ハードウェア側に問題を丸投げできない、つまりハードも限界の時は、クエリキャッシュを使ってみてください。クエリキャッシュはクエリの結果を一定時間保持し、その間同じクエリが実行されれば、キャッシュした結果を返します。

   ページへのリクエストがある度にキャッシュがチェックされます。キャッシュが空だったり、設定されている有効期限が切れていたり、UPDATEやINSERTによって無効になっている場合、クエリが再度実行されます。そうでなければキャッシュに入っている結果が返され、時間と手間を省くことができます。

前のページ  1  2  3


Ilia Alshanetsky
著者プロフィール
Ilia Alshanetsky
PHP開発チームの活動メンバーの1人であり、現在のPHP 4.3.X.のリリースマネージャー。また、オープンソース掲示板FUDフォーラム(http://fud.prohost.org/forum/)をはじめとする数多くのプロジェクトにも貢献している。


INDEX
第3回:SQLインジェクションの注意点
  データベースの認証
  Includeを使う場合
  パフォーマンスの維持