php PHPでベーシック(Basic)認証をかける

2013年6月21日

.htaccess の設定をせずに、php の関数として認証をかける方法のメモ。(ベーシック認証は、パスワードがそのままHTTPのネットワークを流れるので、盗聴などセキュリティ上の危険性がある。)

PHP による HTTP 認証

  • header() 関数を使うと、 “Authentication Required” メッセージをクライアントブラウザに送ることができる。
  • これにより、クライアントブラウザではユーザー名とパスワードの入力要求 ウインドウがポップアップ表示される。
  • 一度、ユーザーがユーザー名と パスワードを入力すると、PHP スクリプトを含むその URL は、次回以降、 定義済みの変数 PHP_AUTH_USER と、 PHP_AUTH_PW と、 PHP_AUTH_TYPE にそれぞれユーザー名、 パスワード、認証型が代入された状態で呼ばれる。
  • 定義済みの変数は、配列 $_SERVER および $HTTP_SERVER_VARS でアクセス可能

Basic HTTP 認証の関数の作成

  • 「header(‘WWW-Authenticate: Basic realm=”Restricted Area”‘);」と「header(‘HTTP/1.0 401 Unauthorized’);」で認証ダイアログをブラウザで表示するようにサーバ側からクライアントへ指示。
  • 認証画面上でキャンセルを押した場合、「die(“Authorization Failed.”);」が実行される。
  • $_SERVER[‘PHP_AUTH_USER’]:HTTP 認証しているときにそのユーザー名がセットされる。
  • $_SERVER[‘PHP_AUTH_PW’]:HTTP 認証しているときにそのユーザーの パスワードがセットされる。
  • 「isset」でユーザー名とパスワードがセットされているかを判定。
  • セットされていれば、それらの値が正しいかを判定し、正しければこの関数を終了。
  • 正しくなければ繰り返される。
  • ユーザー名とパスワードは crypt 関数を使って暗号化しておく。
  • 判定の際も、 crypt を使用し、異なったハッシュアルゴリズムが使用された際の問題を避けるために、crypt()の結果全体($hashed_user,$hashed_password)をパスワード比較用のsaltとして渡す必要がある。
function basic_auth(){
  $hashed_user = "m1kfDGkLDoDfI";  //別途 crypt 関数を使って作成しておく
  $hashed_password = "i/b3VZ7dsxl7Q";  //同上
  if (isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW'])){
    if (crypt($_SERVER['PHP_AUTH_USER'], $hashed_user) == $hashed_user && crypt($_SERVER['PHP_AUTH_PW'], $hashed_password) == $hashed_password){
      return;
    }
  }
  header('WWW-Authenticate: Basic realm="Restricted Area"');
  header('HTTP/1.0 401 Unauthorized');
  header('Content-type: text/html; charset='.mb_internal_encoding());
  die("Authorization Failed.");
}

WordPress のログインにベーシック認証を使用する例

add_action( 'login_init', 'basic_auth' );
function auth_login_init() {
    if ( ! is_user_logged_in() ) {
        basic_auth();  //前述の関数の呼び出し 
    }
}

セキュリティを高めるためにベーシック認証を使うので、WordPress のユーザー名とパスワードとは別のものを使用するほうがいいと思う。(平文でネット上に流れるため)

以下はプラグイン「WP Basic Auth」にあるコードで、これを前述の関数の変わりに使えば、WordPress のユーザー名とパスワードでログインできる。

function basic_auth(){
    nocache_headers();
    if ( is_user_logged_in() )
      return;

    $usr = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
    $pwd = isset($_SERVER['PHP_AUTH_PW'])   ? $_SERVER['PHP_AUTH_PW']   : '';
    if (empty($usr) && empty($pwd) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
      list($type, $auth) = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);
      if (strtolower($type) === 'basic') {
        list($usr, $pwd) = explode(':', base64_decode($auth));
      }
    }

    if ( !is_wp_error(wp_authenticate($usr, $pwd)) )
      return;

    header('WWW-Authenticate: Basic realm="Please Enter Your Password"');
    header('HTTP/1.1 401 Unauthorized');
    echo 'Authorization Required';
    die();
}

関連ページ:「PHP で Basic 認証のパスワードを作る

.htaccess を使ってベーシック認証を行うには「WP インストール時の注意点とセキュリティ」の「ログインにベーシック認証を使用」を参照。