PHPでのSQLインジェクションの防止(およびその他の脆弱性)
しばらくweb開発をしてきたなら、”SQLインジェクション”という用語とそれに関する恐ろしい話をほぼ確実に聞いたことがあります。
PHPは、他の多くの言語と同様に、この種の脅威の影響を受けません。 しかし、幸いなことに、SQLインジェクションやその他の同様の脅威からwebサイトを保護することは、具体的な措置を講じることができます。
この記事では、SQLインジェクションとは何か、成功した攻撃の結果は何か、攻撃者が脆弱なPHPコードをどのように利用できるか、それを防ぐために何ができるか、そしてこの種の脅威の対象となる可能性のあるコードの部分を検出するためにどのようなツールを使用できるかを学びます。 さらに、より安全なアプリケーションを作成するために注意する必要がある他のいくつかの一般的な脆弱性について学びます。
SQLインジェクションはどのように機能しますか?
SQLインジェクションからコードを保護するために最初に知っておく必要があるのは、攻撃者がどのように悪用される可能性があるかを理解するこ
エクスプロイトの背後にある考え方はかなり簡単です:攻撃者はあなたのアプリを介してデータベース上で悪意のあるSQLコードを実行します。
どうやって誰かがそれを達成できますか? アプリケーションの入力を悪用することによって。
簡単な例を見てみましょう。 ユーザー名のリストを表示するアプリケーションがあり、各ユーザーに
のような詳細へのリンクがあり、user_details.php
ファイルに次のようなリンクがあるとします:
<?php $sql = "SELECT * FROM user WHERE id = ".$_GET;
ユーザーが期待どおりに動作し、ユーザーの名前をクリックすると、要求URLはhttp://domain.com/user_details.php?id=8
のようになります。
だから、それはどうしたのですか?
$sql
の値は文字列"SELECT * FROM user WHERE id = 8"
になり、クエリは正常に実行されます。
問題は、この文の斜体部分にあります:ユーザーが期待どおりに動作し、いくつかのユーザーの名前をクリックすると、要求URLは次のようになります:
http://domain.com/user_details.php?id=8
.
ユーザーが期待どおりに動作しない場合はどうなりますか?
誰かがIDとして番号以外のものを送信するURLを製造した場合はどうなりますか? Urlがhttp://domain.com/user_details.php?id=Peanuts
のようなものであった場合、結果のSQL文字列は"SELECT * FROM user WHERE id = Peanuts"
になります。
この場合、問題はユーザーの問題になります。 クエリは単に失敗し、最悪のシナリオでは、ユーザーに何らかの奇妙なメッセージが表示されます。
しかし、URLがこのように見える場合はどうなりますか:
http://domain.com/user_details.php?id=1+OR+1%3B
? (ちなみに、これはurlencode('1 OR 1;')
の結果です。)
この場合、結果のSQLは"SELECT * FROM user WHERE id = 1 OR 1;"
になります。 つまり、クエリの結果は、IDが1に等しいユーザーだけではなく、データベース内のすべてのユーザーになります。 痛い
しかし、それはまだあまりにも悪くないでしょうか?
さて、より極端な例を試してみましょう。
URLが次のようなものであるとしましょう
http://domain.com/user_details.php?id=1%27%3B+DROP+TABLE+users%3B--+
, これはid=1; DROP TABLE users;--
に変換され、このSQLコマンドを効果的に生成します:
"SELECT * FROM users WHERE id = 1; DROP TABLE users;-- "
. そして、あなたがこのクエリを実行すると…大きな痛い。
SQL構文に100%慣れていない場合、DROP TABLE
はテーブルを完全に削除します。 それは決して存在しなかったようなものでしょう。
もちろん、最近のバックアップは被害を軽減するのに役立つだろうが、それでも。 これは悪いです。
この種の攻撃についてもっと知りたいなら、ここに素晴らしい投稿があります。
しかし、私はそれが十分に悪いニュースだと思います。 より陽気な場所に移りましょう:PHPアプリでこれらのタイプのSQLインジェクションを防ぐ方法。
PHPでSQLインジェクションを防ぐ方法
あなたが見たように、問題は、攻撃者があなたがそれを知らずにSQLコードを実行する能力を持っているときです。
この状況は、文字列連結を介してその場でクエリを作成し、外部入力(通常はユーザー入力だけでなく、ファイル、API呼び出しへの応答などの他の外部ソース)か
だから、あなたのコードでこの脆弱性を防ぐためには、潜在的な問題の原因を修正する必要があります。
入力の検証
上記の例の脆弱性を修正する簡単な方法は、IDパラメータが実際に期待されているものであるかどうかを確認することです。
この種の検証を行う別の方法は、PHPの組み込みフィルタを利用することです:
<?php
$id = filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT);
そのため、入力を検証することで、攻撃者が自分のコードと一緒に悪意のあるコードを実行するのを防ぎます。
彼らが試みるのを防ぐ簡単な方法はありませんが、彼らの試みが成功しない限り、あなたは行ってもいいです。
準備された文の使用
SQLインジェクションからコードを保護する別の方法は、準備された文を使用することです。 準備された文は、プリコンパイルされたSQLコマンドです。
これらは、特定のデータベースアクセスライブラリ(mysqliなど)またはより汎用的なライブラリPDOで使用できます。
mysqliを使用した例を見てみましょう:
このコードを試してみると(もちろん、データベースの資格情報を置き換えます)、http://domain.com/user_details.php?id=1
のような合法的なURLを介してアクセ PDOを使用したい場合は、コードは次のようになります。
あまり違いはありませんよね?
要約すると、準備された文は、SQLインジェクションを防ぐための素晴らしい方法を提供します。 また、通常、オンザフライSQLよりも優れたパフォーマンスを発揮します。
今、あなたはツールを知っているので、あなたはそれを使用する必要があります。
SQLインジェクションに脆弱なPHPコードを検出する方法
脆弱性が見つかったら、それを修正することは本当に複雑ではありません。 しかし、最初にコード内でこれらのタイプの脆弱性をどのように見つけますか?
まあ、あなたが運が良ければ、あなたのコードベースが十分に小さい場合、コードの簡単なレビューが行います。
しかし、あなたのアプリケーションが中規模から大規模な場合は、余分な助けが必要になります。
この目的のために使用できる非常に人気のある(そしてオープンソースの)ツールの一つは、sqlmap、あなたがそれにフィードし、その結果を報告する任意のURLを攻撃
私のPHPベースのウェブサイトに対する実行からのサンプル出力は次のとおりです:
あなたが使うことができるもう一つのオープンソースのツールは、Web GUIを含み、Rubyで書かれたより洗練されたツールであるArachniです。
CLIを使用して実行したサンプル出力を次に示します:
コードのレビューとテスト以外にも、SqreenなどのRASPソリューションを使用して本番環境を監視し、レビューとテストの段階で悪用が実行されないようにするこ
他にどのような脆弱性に注意する必要がありますか?
コードインジェクション
SQLインジェクションは、より大きな脆弱性ファミリーの一つであるコードインジェクションのメンバーにすぎません。
異なるコード注入技術の背後にある考え方は常に同じです。 これは、無実のアプリケーションをだまして悪意のあるコードを実行することです。
これはいくつかの方法で行うことができます。
PHPには、exec
関数のように、単にオペレーティングシステムに直接コマンドを発行するように設計された関数があります。
これがどのように悪用されるかの簡単な例を次に示します:
<?php
exec( 'cp uploads/'.$_GET.' /secure/');
誰かがhttp://domain.com/exec.php?file=a.txt%3B+rm+-Rf+%2A+%23
を要求した場合、結果はこのコマンドの実行になります:
cp uploads/a.txt; rm -Rf * # /secure/
そして、これはサーバー上のディスク全体を一掃することができます-未検証の入力が再びストライキ!
クロスサイトスクリプティング
もう一つの非常に一般的な脆弱性はクロスサイトスクリプティング(XSS)です。 この場合、被害者はあなたのサイトを訪問しているユーザーです。
XSSは、攻撃者が通常のHTMLフォーム内に悪意のあるJavaScriptコードを挿入し、後で別のユーザーのブラウザによってレンダリングされる場合です。
このPHPスクリプトを見てください:
<?php
echo "<html><p>Hello {$_GET}!</p></html>";
明らかに、ここでの意図は、ユーザーに挨拶する単純なページを作成することです。
しかし、悪者がそれに到達したとき、彼らが要求するのを妨げるものは何ですか
http://domain.com/greet.php?name=Mauro%3Cscript+language%3D%22javascript%22%3Ealert%28%22You+are+hacked%21%22%29%3B%3C%2Fscript%3E
? この要求は、出力として次のHTMLを生成します:
<html><p>Hello Mauro<script language="javascript">alert("You are hacked!");</script></p></html>
これは明らかに非常に素朴な悪用です—結局のところ、誰かに簡単な”あなたがハッキングされている”ことを示すことの害は何ですか?「メッセージ? しかし、物事は少し想像力でかなり深刻になることができます。 サーバーへのすべての要求にはセッションcookieが含まれているため、この脆弱性がユーザーのセッションがハイジャックされる原因になる可能性があり
繰り返しますが、問題は醜いように見えますが、修正は本当に簡単です:それはすべて検証とサニタイズに関するものです。
XSSの場合、実際の出力を生成する前にhtmlentities
を簡単に呼び出すことができます。
セキュリティ脆弱性の修正と検出
この記事で見たように、セキュリティ脆弱性の修正—SQLインジェクションとその他のタイプの両方—は主な課題ではありません。 あなたのコードが脆弱であり、悪用される可能性があることを認識しています。 ここにはいくつかのオプションがあります:
- 非常に強力なコーディング規律を持っている
- セキュリティ問題のために徹底的にアプリケーションをテスト
- 悪用を防止し、タイムリーにアラートを取得するために監視および保護ツールを活用
どちらを選択するかはあなた次第です。 重要なことは、これらの問題に注意を払い、その知識に基づいて行動することです。 気をつけて