セキュアな PHP アプリケーションを作成するための 7 つの習慣

Web アプリケーションのセキュリティーを高める

PHP アプリケーションのセキュリティーには、リモートでのセキュリティーとローカルでのセキュリティーに関するものがあります。リモートとローカル両方でのセキュリティーに対応した Web アプリケーションを実装するために、PHP 開発者が身につける必要のある習慣を学びましょう。

Nathan A. Good (mail@nathanagood.com), Senior Information Engineer, Freelance Developer

Nathan A. Good lives in the Twin Cities area of Minnesota. Professionally, he does software development, software architecture, and systems administration. When he's not writing software, he enjoys building PCs and servers, reading about and working with new technologies, and trying to get his friends to make the move to open source software. He's written and co-written many books and articles, including Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution Approach and Foundations of PEAR: Rapid PHP Development.



2008年 9月 30日

セキュリティーを考慮する際には、実際のプラットフォームとオペレーティング・システムのセキュリティーの問題に対処した上で、さらに作成するアプリケーションをセキュアなものにする必要があるということを忘れてはなりません。PHP アプリケーションを作成する際には、可能な限りセキュアなアプリケーションにするために、次の 7 つの習慣を守る必要があります。

  • 入力を検証する
  • ファイルシステムを保護する
  • データベースを保護する
  • セッション・データを保護する
  • XSS (Cross-Site Scripting: クロスサイト・スクリプティング) の脆弱性から保護する
  • フォームへの投稿を検証する
  • CSRF (Cross-Site Request Forgeries: クロスサイト・リクエスト・フォージェリー) から保護する

入力を検証する

データの検証は、セキュリティー対策として採ることのできる習慣のなかで最も重要なものです。そして入力に関する限り、その習慣は単純で、ユーザーを信用してはいけないというものです。皆さんのユーザーはおそらく善良であり、ほとんどのユーザーは皆さんのアプリケーションを想定どおり使うでしょう。しかし入力可能な部分がある限り、非常に悪質な入力をすることもできます。皆さんはアプリケーションの開発者として、悪質な入力からアプリケーションを保護する必要があります。ユーザー入力が現在どのように処理され、どのような入力が適切なのかを注意深く考えることによって、堅牢でセキュアなアプリケーションを作成することができます。

ファイルシステムやデータベースとのやり取りは後ほど説明しますが、あらゆる種類の検証をカバーできる、検証のための一般的なヒントがあります。

  • ホワイトリスト化された値を使う
  • 制限付きの選択肢であっても必ず再検証する
  • 組み込みのエスケープ関数を使う
  • データ型が (数字など) 適切かどうかを検証する

ホワイトリスト化された値は有効な値であり、ブラックリスト化された無効な値とは逆です。ホワイトリストがブラックリストと異なる点は、検証を行う際に、無効な値 (多くの場合は未知の値または想定外の値) をリストにするよりも、取り得る値をリストにした方がリストに示される値も少なく、リストのサイズも小さくなることが多い、という点にあります。

検証を行う際には、未知のあらゆる値に対して保護しようとするよりも、アプリケーションが何を許可するのかを概念化し、それを検証した方が容易な場合が多いということを覚えておくことです。例えばフィールドへの入力値を数字のみに制限する場合には、入力がすべて数字であることを確認するルーチンを作成します。数字ではない値を検索し、そうした値が見つかったら無効とマークするようなルーチンを作成してはいけません。

ファイルシステムを保護する

2000年7月、ある Web サイトから、ある Web サーバー上のファイルの中にある顧客データが流出してしまいました。その Web サイトの訪問者が、そのデータを含むファイルを見られるように URL を操作したのです。それらのファイルは不適切な場所に置かれていたのですが、この例はファイルシステムを攻撃者から保護することの重要性を物語っています。

ファイルシステムに対するファイル操作を含む PHP アプリケーションに、ユーザーから入力される可変データがある場合には、ユーザー入力を十分に検証し、ユーザーがファイルシステムに対して望ましくないことを絶対に行えないようにする必要があります。リスト 1 は、指定された名前の画像をダウンロードする PHP サイトの例を示しています。

リスト 1. ファイルのダウンロード
<?php
if ($_POST['submit'] == 'Download') {
    $file = $_POST['fileName'];
    header("Content-Type: application/x-octet-stream");
    header("Content-Transfer-Encoding: binary");
    header("Content-Disposition: attachment; filename=\"" . $file . "\";" );
    $fh = fopen($file, 'r');
    while (! feof($fh))
    {
        echo(fread($fh, 1024));
    }
    fclose($fh);
} else {
    echo("<html><head><");
        echo("title>Guard your filesystem</title></head>");
    echo("<body><form id=\"myFrom\" action=\"" . $_SERVER['PHP_SELF'] .
        "\" method=\"post\">");
    echo("<div><input type=\"text\" name=\"fileName\" value=\"");
    echo(isset($_REQUEST['fileName']) ? $_REQUEST['fileName'] : '');
    echo("\" />");
    echo("<input type=\"submit\" value=\"Download\" name=\"submit\" /></div>");
    echo("</form></body></html>");
}

これを見るとわかるように、リスト 1 のスクリプトは比較的危険性が高く、Web サーバーが読み取りアクセス可能な任意のファイルを提供してしまいます。例えばセッション・ディレクトリーの中のファイル (「セッションを保護する」を参照) や、さらには /etc/passwd などのシステム・ファイルさえ提供してしまいます。この例にはファイル名を入力できるテキスト・ボックスがありますが、クエリー・ストリングの中に容易にファイル名を入れることもできるのです。

ファイルシステムへのアクセスをユーザー入力と一緒に構成することは危険なため、そうした構成を完全に避けるようにした方が賢明です。そのためには、データベースと、生成される隠しファイル名を使うようにアプリケーションを設計します。しかし必ずしもそうはいかない場合もあります。リスト 2 はファイル名を検証するルーチンの一例です。この例では、正規表現を使って有効な文字のみがファイル名に使われるようにしており、ドット文字 (.) が続いていないか具体的なチェックをしています。

リスト 2. ファイル名の文字が有効かどうかのチェック
function isValidFileName($file) {
    /* don't allow .. and allow any "word" character \ / */
    return preg_match('/^(((?:\.)(?!\.))|\w)+$/', $file);
}

データベースを保護する

2008年4月、クエリー・ストリングの中に SQL の列の名前が使用されていたことによって、米国のある州の Department of Corrections (刑務局) から機密データが流出してしまいました。この漏洩事件では、悪意のあるユーザーが、表示させたいデータベースの列を選択するようにして、そのページを送信することで、そのデータを取得することができたのです。この漏洩事件によって、アプリケーション開発者がまったく予期しなかったような入力をユーザーが考え出して実行する手口が明らかになり、SQL インジェクション攻撃に対して慎重に対策を施す必要があることが改めて示されました。

リスト 3 は SQL 文を実行するスクリプトの一例を示しています。この例の SQL 文は動的であり、上記の攻撃と同じ攻撃を許してしまいます。このフォームの所有者は、自分たちは安全だと考えたくなるかもしれません。列の名前は選択用リストにあるものに制限されているからです。しかしこのコードは、フォーム・スプーフィングに関して一番最後に注意しなければならないことが漏れています。つまり、たとえコードによって選択肢がドロップダウン・ボックスに制限されているからといって、誰かが何かの悪事 (例えばアスタリスク [*] など) を含むフォームを投稿できないということにはならないのです。

リスト 3. SQL 文を実行する
<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="text" name="account_number"
    value="<?php echo(isset($_POST['account_number']) ? 
        $_POST['account_number'] : ''); ?>" />
<select name="col">
<option value="account_number">Account Number</option>
<option value="name">Name</option>
<option value="address">Address</option>
</select>
<input type="submit" value="Save" name="submit" /></div>
</form>
<?php
if ($_POST['submit'] == 'Save') {
    /* do the form processing */
    $link = mysql_connect('hostname', 'user', 'password') or 
        die ('Could not connect' . mysql_error());
    mysql_select_db('test', $link);
		
		$col = $_POST['col'];

    $select = "SELECT " . $col . " FROM account_data WHERE account_number = " 
        . $_POST['account_number'] . ";" ;
    echo '<p>' . $select . '</p>';

    $result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');

    echo '<table>';
    while ($row = mysql_fetch_assoc($result)) {
        echo '<tr>';
        echo '<td>' . $row[$col] . '</td>';
        echo '</tr>';
    }
    echo '</table>';

    mysql_close($link);
}
?>
</body>
</html>

そこで、データベースを保護するための習慣を身につけるには、動的な SQL コードを可能な限り避けるようにすることです。動的な SQL コードを避けられない場合には、SQL の列に直接ユーザー入力を適用してはいけません。リスト 4 は、静的な列を使うことに加えて account number フィールドに数字以外を入力することができなくなるように単純な検証ルーチンを追加することがいかに強力かを示す一例です。

リスト 4. 検証による保護と mysql_real_escape_string()
<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="text" name="account_number"
    value="<?php echo(isset($_POST['account_number']) ? 
        $_POST['account_number'] : ''); ?>" /> <input type="submit"
    value="Save" name="submit" /></div>
</form>
<?php
function isValidAccountNumber($number) 
{
    return is_numeric($number);
}

if ($_POST['submit'] == 'Save') {

    /* Remember habit #1--validate your data! */
    if (isset($_POST['account_number']) &&
    isValidAccountNumber($_POST['account_number'])) {

        /* do the form processing */
        $link = mysql_connect('hostname', 'user', 'password') or
        die ('Could not connect' . mysql_error());
        mysql_select_db('test', $link);

        $select = sprintf("SELECT account_number, name, address " .
		" FROM account_data WHERE account_number = %s;",
        mysql_real_escape_string($_POST['account_number']));
        echo '<p>' . $select . '</p>';

        $result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');

        echo '<table>';
        while ($row = mysql_fetch_assoc($result)) {
            echo '<tr>';
            echo '<td>' . $row['account_number'] . '</td>';
            echo '<td>' . $row['name'] . '</td>';
            echo '<td>' . $row['address'] . '</td>';
            echo '</tr>';
        }
        echo '</table>';

        mysql_close($link);
    } else {
        echo "<span style=\"font-color:red\">" .
    "Please supply a valid account number!</span>";

    }
}
?>
</body>
</html>

またこの例は mysql_real_escape_string() 関数の使い方も示しています。この関数は入力に無効な文字が含まれないように入力を適切に検証します。magic_quotes_gpc に頼っている方には、PHP V6 ではmagic_quotes_gpc が非推奨となり、削除されることをあらかじめ警告しておきます。magic_quotes_gpc に頼ることを今すぐに止め、magic_quotes_gpc を使わなくてもセキュアであるように PHP アプリケーションを作成する必要があります。また ISP を使用している場合には、その ISP は magic_quotes_gpc を有効にしていない可能性があります。

最後に、改善された例を見ると、SQL 文と出力に動的な列選択が含まれていないことがわかります。こうすることによって、異なる情報を持つ列を後でテーブルに追加する場合には、そうした列を出力することができます。またデータベースを扱うためにフレームワークを使用している場合には、そのフレームワークが SQL 検証を行ってくれるのかもしれません。そのフレームワークのドキュメントを調べ、そのことを確認してください。それでもよくわからない場合には、十分すぎるぐらいに安全になるように検証を行う必要があります。データベースとのやり取りにフレームワークを使用している場合であっても、それ以外の検証は相変わらず必要なのです。


セッションを保護する

デフォルトで、PHP のセッション情報は一時ディレクトリーに書き込まれます。リスト 5 のフォームを考えてみてください。このフォームはユーザーの ID とアカウント番号をセッションに保存する方法を示しています。

リスト 5. データをセッションに保存する
<?php
session_start();
?>
<html>
<head>
<title>Storing session information</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
    $_SESSION['userName'] = $_POST['userName'];
    $_SESSION['accountNumber'] = $_POST['accountNumber'];
}
?>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="userName"
    value="<?php echo(isset($_POST['userName']) ? $_POST['userName'] : ''); ?>" />
<br />
<input type="text" name="accountNumber"
    value="<?php echo(isset($_POST['accountNumber']) ? 
    $_POST['accountNumber'] : ''); ?>" />
<br />
<input type="submit" value="Save" name="submit" /></div>
</form>
</body>
</html>

リスト 6 は /tmp ディレクトリーの内容を示しています。

リスト 6. /tmp ディレクトリーの中のセッション・ファイル
-rw-------  1 _www    wheel       97 Aug 18 20:00 sess_9e4233f2cd7cae35866cd8b61d9fa42b

セッション・ファイルを出力してみると (リスト 7)、ご覧のように非常に読みやすいフォーマットで情報が含まれています。このファイルは Web サーバーのユーザーが読み書きできる必要があるため、セッション・ファイルは共有サーバーを利用している誰に対しても大きな問題を引き起こす可能性があります。これらのファイルを読み取るスクリプトを皆さん以外の誰かが作成し、セッションから値を取得することができてしまいます。

リスト 7. セッション・ファイルの内容
userName|s:5:"ngood";accountNumber|s:9:"123456789";

パスワードの保管

パスワードは、どんなことがあっても決してプレーン・テキストで保管してはいけません。それは、データベースの中であれ、セッション、ファイルシステム、その他どこに保管する場合でも言えることです。パスワードを扱う最善の方法は、パスワードを暗号化して保管し、パスワード同士を比較する際には暗号化した状態のまま行うことです。これは当然のことのように思えるかもしれませんが、現実にはパスワードをプレーン・テキストで保管することは非常によく行われているようです。ユーザーが Web サイトで使っているパスワードを忘れた場合に、パスワードをリセットするのではなくユーザーにパスワードを送信できるようなサイトでは、そのパスワードがプレーン・テキストで保管されているか、あるいは暗号化した状態で保管しているパスワードを復号するためのコードがあるということです。後者の場合であっても、復号用のコードを発見して悪用することは可能なのです。

セッション・データを保護するためにできることは 2 つあります。第 1 の方法は、セッションの中に入れるものをすべて暗号化する方法です。しかし単にデータを暗号化したからといって、そのデータが完全に安全ということにはなりません。そのため、セッションを保護する唯一の手段としてデータを暗号化する場合には、十分に注意する必要があります。もう 1 つの方法は、セッション・データをデータベースなど別の場所に保管する方法です。この場合も必ずデータベースをロックする必要がありますが、この方法を利用すると 2 つの問題を解決することができます。第 1 に、共有ファイルシステムよりも安全な場所にデータを置くことができます。そして第 2 に、複数ホストでセッションが共有されるため、アプリケーションを複数の Web サーバーにまたがるスケーラブルなものにすることができます。

独自のセッション・パーシスタンスを実装するためには、PHP の session_set_save_handler() 関数を調べてみてください。この関数を使うと、セッション情報をデータベースに保管したり、あるいはすべてのデータの暗号化と復号を行うハンドラーを実装したりすることができます。リスト 8 はこの関数の使い方の例と実装用のスケルトン関数を示しています。データベースの使い方の例については「参考文献」で調べることもできます。

リスト 8. session_set_save_handler() 関数の例
function open($save_path, $session_name)
{
    /* custom code */
    return (true);
}

function close()
{
    /* custom code */
    return (true);
}

function read($id)
{
    /* custom code */
    return (true);
}

function write($id, $sess_data)
{
    /* custom code */
    return (true);
}

function destroy($id)
{
    /* custom code */
    return (true);
}

function gc($maxlifetime)
{
    /* custom code */
    return (true);
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

XSS の脆弱性から保護する

XSS の脆弱性は、Web サイトの脆弱性に関する 2007年の報告全体の大きな部分を占めています (「参考文献」を参照)。XSS の脆弱性は、ユーザーが Web ページに HTML コードを注入できる場合に起こります。HTML コードではスクリプト・タグの中に JavaScript コードを含めることができるため、ページが描画されると JavaScript を実行できてしまいます。リスト 9 のフォームは、テキストを入力することが一般的な、フォーラムやウィキ、ソーシャル・ネットワーキング、その他すべてのサイトに当てはまります。

リスト 9. テキストを入力するためのフォーム
<html>
<head>
<title>Your chance to input XSS</title>
</head>
<body>
<form id="myFrom" action="showResults.php" method="post">
<div><textarea name="myText" rows="4" cols="30"></textarea><br />
<input type="submit" value="Delete" name="submit" /></div>
</form>
</body>
</html>

リスト 10 は、このフォームがどのように結果を出力するか、またこのフォームに対して XSS 攻撃が可能なことを示しています。

リスト 10. showResults.php
<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo($_POST['myText']);
echo("</p>");
?>
</body>
</html>

リスト 11 は新しいウィンドウをポップアップして Google のホーム・ページを開く方法の基本的なサンプル・コードです。Web アプリケーションが XSS 攻撃に対して保護されていない場合、被る被害を制限する唯一の方法は、どんな攻撃が可能かを想像してみることです。例えば、サイトのスタイルを真似たリンクをフィッシングの目的で追加することができます (「参考文献」)。

リスト 11. 悪意の入力テキストのサンプル・コード
<script type="text/javascript">myRef = window.open('http://www.google.com','mywin',
'left=20,top=20,width=500,height=500,toolbar=1,resizable=0');</script>

XSS 攻撃から保護するためには、変数の値が出力として表示される場合に必ず htmlentities() 関数によるフィルターに入力を通す必要があります。Web アプリケーションでの名前や E メール・アドレス、電話番号、請求情報などの入力に対して、ホワイトリスト化された値を使って入力データを検証する、という第 1 の習慣に従うことを忘れないでください。

テキスト入力がある、もっと安全なバージョンのページを次に示します。

リスト 12. よりセキュアなフォーム
<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo(htmlentities($_POST['myText']));
echo("</p>");
?>
</body>
</html>

無効な投稿に対して保護する

フォーム・スプーフィングというのは、誰かがフォームに対して想定外の場所から投稿することです。フォーム・スプーフィングを行う最も簡単な方法は、フォームにすべての値を送信して渡すような Web ページを作成することです。Web アプリケーションはステートレスであるため、投稿されたデータが想定の場所から来たのかどうかを絶対確実に確認する方法はありません。結局のところ、IP アドレスからホスト名まで、あらゆるものがスプーフィングの対象となりうるのです。リスト 13 は情報を入力するための典型的なフォームです。

リスト 13. テキストを処理するためのフォーム
<html>
<head>
<title>Form spoofing example</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
    echo("<p>I am processing your text: ");
    echo($_POST['myText']);
    echo("</p>");
}
?>
</body>
</html>

リスト 14 はリスト 13 のフォームに投稿されるフォームです。このフォームを使ってフォーム・スプーフィングを試すためには、このフォームを Web サイトに置き、リスト 14 のコードを HTML 文書としてデスクトップに保存し、保存したフォームをブラウザーで開きます。次にフォームにデータを入力したら、フォームを送信し、データが処理される様子を観察します。

リスト 14. データを収集するためのフォーム
<html>
<head>
<title>Collecting your data</title>
</head>
<body>
<form action="processStuff.php" method="post">
<select name="answer">
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
<input type="submit" value="Save" name="submit" />
</form>
</body>
</html>

フォーム・スプーフィングによる本当の影響は、ドロップダウン・ボックスやラジオ・ボタン、チェックボックス、その他制限付きの入力を持つフォームがある場合、そうした制限がフォーム・スプーフィングによってまったく無意味になってしまうことです。リスト 15 のコードについて考えてみてください。このコードには無効なデータを持つフォームが含まれています。

リスト 15. 無効なデータを持つフォーム
<html>
<head>
<title>Collecting your data</title>
</head>
<body>
<form action="http://path.example.com/processStuff.php" 
    method="post"><input type="text" name="answer"
    value="There is no way this is a valid response to a yes/no answer..." />
<input type="submit" value="Save" name="submit" />
</form>
</body>
</html>

少し考えてみてください。ユーザーの入力を限られたデータに制限するドロップダウン・ボックスやラジオ・ボタンがあると、入力の検証は必要ないと考えがちです。しかし結局のところ、その入力フォームは、ある限られたデータのみをユーザーが入力できるように保証しているのです。フォーム・スプーフィングを制限するためには、投稿者が本人であるらしいということを確実にする手段を講じる必要があります。そのために使用できる 1 つの手法として、1 回しか使用できないトークンを使う方法があります。1 回限りのトークンを使う場合であってもフォーム・スプーフィングは不可能ではありませんが、フォーム・スプーフィングを非常に行いにくくすることができます。フォームが描画されるたびにトークンが変更されるため、攻撃をしようとする人は、送信されるフォームのインスタンスを取得し、そこから抽出したトークンをスプーフィング用のフォームに入れなければなりません。この手法によって、望ましくないリクエストをアプリケーションに投稿するための永久的な Web フォームを誰かが作成できる可能性が非常に低くなります。リスト 16 はこのワンタイム・トークンを埋め込んだフォームの例を示しています。

リスト 16. ワンタイム・トークンを埋め込んだフォームを使う
<?php
session_start();
?>
<html>
<head>
<title>SQL Injection Test</title>
</head>
<body>
<?php

echo 'Session token=' . $_SESSION['token'];
echo '<br />';
echo 'Token from form=' . $_POST['token'];
echo '<br />';

if ($_SESSION['token'] == $_POST['token']) {
    /* cool, it's all good... create another one */

} else {
    echo '<h1>Go away!</h1>';
}
$token = md5(uniqid(rand(), true)); 
$_SESSION['token'] = $token; 
?>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="myText"
    value="<?php echo(isset($_POST['myText']) ? $_POST['myText'] : ''); ?>" />
<input type="submit" value="Save" name="submit" /></div>
</form>
</body>
</html>

CSRF に対して保護する

クロスサイト・リクエスト・フォージェリー (CSRF 攻撃) は、攻撃を実行できるユーザー特権を悪用します。CSRF 攻撃では、ユーザーが簡単に思いもよらぬ共犯者になることができます。リスト 17 は、あるアクションを実行するページの例を示しています。このページはクッキーからユーザーのログイン情報を調べます。クッキーが有効である限り、この Web ページはリクエストを処理します。

リスト 17. CSRF の例
<img src="http://www.example.com/processSomething?id=123456789" />

CSRF 攻撃は多くの場合 <img> タグの形で行われますが、これはブラウザーが画像を取得しようとして不注意にその画像の URL を呼び出すからです。しかしその画像のソースは、同じサイト上のページにある、渡されたパラメーターに基づいて何らかの処理を行う URL であることも十分考えられるのです。XSS 攻撃が潜んだ <img> タグが置かれると (これは報告された攻撃のうち最も一般的なものです)、ユーザーは自分たちのクレデンシャルを使って (気付かないうちに) 容易に何かをすることができ、従って CSRF が行われてしまいます。

CSRF から保護するためには、フォームの投稿を検証するための習慣で使用する、ワンタイム・トークンによる手法を使います。また、$_REQUEST ではなく、明示的な $_POST 変数を使う必要があります。リスト 18 は、お粗末な Web ページの例を示しています。この Web ページは、そのページが GET リクエストによって呼び出されるのか、あるいはそのページにフォームが投稿されたために呼び出されるかにかかわらず、同じように処理してしまいます。

リスト 18. $_REQUEST からデータを取得する
<html>
<head>
<title>Processes both posts AND gets</title>
</head>
<body>
<?php
if ($_REQUEST['submit'] == 'Save') {
    echo("<p>I am processing your text: ");
    echo(htmlentities($_REQUEST['text']));
    echo("</p>");
}
?>
</body>
</html>

リスト 19 はフォームの POST によってのみ動作するように改善したバージョンを示しています。

リスト 19. $_POST のみからデータを取得する
<html>
<head>
<title>Processes both posts AND gets</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
    echo("<p>I am processing your text: ");
    echo(htmlentities($_POST['text']));
    echo("</p>");
}
?>
</body>
</html>

まとめ

この記事で紹介した、セキュアな PHP Web アプリケーションを作成するための 7 つの習慣から始めることによって、容易に悪意のある攻撃の犠牲者になる事態を避けることができます。他の多くの習慣と同様、これらの習慣も最初は面倒に思えるかもしれませんが、時間が経つにつれ自然なことに思えるようになります。

最初の習慣、つまり入力の検証が鍵であることを忘れないでください。入力が不適切な値を含まないことを確認した後、ファイルシステムやデータベース、そしてセッションの保護に進むことができます。最後に、PHP コードが XSS 攻撃やフォーム・スプーフィング、CSRF 攻撃に耐えられること確認する必要があります。こうした習慣を注意しながら身につけることが、簡単に攻撃される事態を防ぐ上で非常に効果的なのです。

参考文献

学ぶために

  • developerWorks のチュートリアル「Locking down your PHP applications」を読み、開発者が決して破ってはならない 4 つのセキュリティー・ルールを学んでください。
  • PHP encryption for the common man」を読み、PHP アプリケーションでデータをセキュアにする方法を学んでください。
  • PHP Security Consortium には PHP のセキュリティーに関する情報が豊富に用意されています。
  • PHP の公式 Web サイトにある PHP セキュリティーのサイトには、セキュリティーに関するさまざまなヒントが掲載されています。
  • カスタムのセッション・ハンドラーの実装について、PHP の公式サイトの session_set_save_handler のページで学んでください。
  • ウィキペディアには XSS が適確に解説されています。
  • Chris Shiflett による Essential PHP Security が PHP.org で公開されています。
  • PHP.net には PHP 開発者のためのリソースが集められています。
  • Recommended PHP reading list」を調べてみてください。
  • developerWorks には他にもPHP に関する資料が豊富に用意されています。
  • IBM developerWorks の PHP project resources で PHP のスキルを磨いてください。
  • developerWorks podcasts では、ソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
  • PHP でデータベースを使うのであれば、Zend Core for IBM を調べてみてください。これはシームレスでそのまま使用でき、インストールも容易な、IBM DB2 V9 をサポートする PHP の開発環境であり実動環境です。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • IBM オープンソース開発者にとって関心のある、世界中で今後開催される会議や業界展示会、ウェブキャスト、その他の Events について調べてみてください。
  • developerWorks の Open source ゾーンをご覧ください。オープンソース技術を使った開発や、IBM 製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。
  • IBM のオープンソース技術や製品機能を調べ、学ぶために、無料の developerWorks On demand demos をご覧ください。

製品や技術を入手するために

  • 皆さんの次期オープンソース開発プロジェクトを IBM ソフトウェアの試用版を使って革新してください。ダウンロード、あるいは DVD で入手することができます。
  • IBM 製品の試用版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=348803
ArticleTitle=セキュアな PHP アプリケーションを作成するための 7 つの習慣
publish-date=09302008