セキュリティ対策を行う・1(PHP+PEARでウェブサービス勉強記録・7)

勉強記録1-6で、ユーザー認証システムは概ね、かたちになりました。

(ユーザー登録からログイン、ログアウトまで)

ここで一度、これまでのロジックを見直し、セキュリティ対策を見直します。

  1. PEAR::DBでデータ登録する際のプレースホルダ利用
  2. セッションIDの再生成(session_regenerate_id)
  3. hidden値の書き換え
  4. リンク元のURL照合

今回は上記のうち、1,2について考えます。

 

1. PEAR::DBでプレースホルダ利用

勉強記録3で、ユーザーデータ、Emailデータの重複確認のために、PEAR::DBを利用して、マッチングを行いました。

このコードの中で、WHERE後の変数取り扱いが、セキュリティホールになりうることに気が付きました。

($usernameなどに悪意あるデータを入れられる可能性があり、かつエスケープ処理していない)

 

修正前のマッチング処理

/* 入力されたユーザーIDとパスワードを変数に取得 */

$username = $_POST["username"];
$email = $_POST["email"];

/* PEAR::DBを利用してユーザー名とメールアドレスの有無を取得 
すでに存在する場合、各変数にユーザーId、メールアドレスのみの配列が生成される
require_once("DB.php");

$dsn = "mysqli://pear:peartest@localhost/pear";

$myDB = DB::connect($dsn);
	
$user_exist = $myDB -> getRow("SELECT username FROM auth WHERE username='$username' ");
$email_exist = $myDB -> getRow("SELECT email FROM auth WHERE email='$email' ");

 

この箇所を、PEAR::DBのプレースホルダを利用して対応します。

修正後のマッチング処理

/* 入力されたユーザーIDとパスワードを変数に取得 */ $username = $_POST["username"]; $email = $_POST["email"]; /* PEAR::DBを利用してユーザー名とメールアドレスの有無を取得 すでに存在する場合、各変数にユーザーId、メールアドレスのみの配列が生成される require_once("DB.php"); $dsn = "mysqli://pear:peartest@localhost/pear"; $myDB = DB::connect($dsn); $user_exist = $myDB -> getRow("SELECT username FROM auth WHERE username=? ", array($username)); $email_exist = $myDB -> getRow("SELECT email FROM auth WHERE email=? “, array($email));

プレースホルダについては、書籍「PEAR入門」の02.01章にも詳しく書かれておりました。

PEAR入門 PHP標準ライブラリを極める!
PEAR入門 PHP標準ライブラリを極める!

最初に、この書籍を見たときには

「プレースホルダってなんだろう?」

と思っておりました(恥)。

自分で書いたコードのセキュリティを確認して、プレースホルダを利用して書き直すと、その重要性が改めてわかりますね。

プレースホルダについては、いつもお世話になっているMTハッカー・ToI企画の天野さんからご指摘いただきました。天野さん、いつもありがとうございます!

オンラインでは、PHPBookさんの「クエリの実行」ページにも、詳しく書かれております。

 

2. セッションIDの再生成(session_regenerate_id)

今回のユーザー登録ロジックでは、単純にsession_start()関数を利用してセッションを生成しておりました。

ここで、セッションIDの値が何らかの原因で判明した場合、セッションハイジャック攻撃の危険性が発生します。イメージとしてはこんな感じでしょうか。

no_regenerate_session

 

セッションIDの固定化によるハイジャック攻撃を防ぐために、セッションIDの値を都度書き換える「sesshion_regenerate_id()関数」を利用して、セッションIDの変更を実行することにします。

with_regenerate_session

入力フォームでデータを入力後、確認画面に移動する際に、セッションIDの変更を試みます。

 

以下「勉強記録6」で作成したロジックの一部と、修正後のロジックになります。

コード作成には、書籍「PHP逆引きレシピ」および「PHPプロ!」さんの記事を参考にさせていただきました。

修正前のregistConfirm.php(冒頭部)

<?php

session_start();

?>

修正後のregistConfirm.php(冒頭部)

<?php

session_start();

/* 現在のセッションIDを変数に格納 */

$old_id = session_id();

/* session_regenerate_id関数で、セッションIDを変更 */

session_regenerate_id(TRUE);

/* PHPのバージョンが5.1.0未満の場合は、
    前セッションIDファイルを消去する */

if(version_compare(PHP_VERSION, '5.1.0', '<')) {

    unlink(session_save_path() . '/sess_' . $old_session_id);

}

?>

 

 

 

次回はセキュリティ対策の続き

次回は

  • hidden値の書き換え
  • リンク元のURL照合

について考えてみたいと思います。