CodeIgniterの学習 56 - 特定のコントローラのみ、使用できるipアドレスを制限するようにする

今日はCodeIgniterで、

ある特定のコントローラは、特定のipアドレスからのリクエストのみを受け付けるような制限を追加してみる。

すごく簡単なネタ。


(昨日のネタは遅々として進行中)

目的

ある特定の機能は

だけに使える端末を制限したい。


.htaccessのベーシック認証以外にも、こういうフィルタリングをしたい時がある。

自鯖から自鯖にxmlrpcのリクエストを送ったりする時のフィルタリングの一つ。
実際はこれ以外にも仕掛けを入れてるが)


コード

手順1)
機能毎に適当なconfigファイルを設置する。(ここではhogehoge_config.php

application/config/hogehoge_config.php

<?php if ( ! defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' );

$config['ALLOW_IP_LIST'] = "127.0.0.1,192.168.1.10,192.168.2.";//接続許可するIPアドレスのリスト

/* End of file hogehoge_config.php */
/* Location: ./application/config/hogehoge_config.php */
 ?>

こんなかんじで、カンマ区切りのリストで持たせてみた。チェック側で分解して前方一致でチェックする。
(実際はローカルIPアドレスではなく、固定のグローバルIPアドレスだったりするだろう)




手順2)
コントローラのコンストラクタで、チェックを行うようにする。(ここではHogehogeコントローラ)

<?php ( defined( 'BASEPATH' ) ) OR exit( 'No direct script access allowed' );

class Hogehoge extends Controller {
  // コンストラクタ
  function Hogehoge()
  {
    parent :: Controller();
    if(! $this->_check_ip_address()){
      exit;
    }
  }
  //起動を許可するipアドレスチェック
  function _check_ip_address()
  {
    $this->load->config('hogehoge_config',true);
    $conf = $this->config->item('hogehoge_config');
    //ローカルアドレス以外を除外
    if(defined('CRON') && CRON){
      return true;//CRON経由は起動OK
    }
    //$ip = $this->input->ip_address();
    $ip = $this->input->server('REMOTE_ADDR');//REMOTE_ADDRに変更
    if(!$ip){ return false; }
    $allow_ip_list = preg_quote($conf['ALLOW_IP_LIST']);
    $arr = explode(',',$allow_ip_list);
    foreach($arr as $v){
      $s=trim($v);
      if(preg_match("#^{$s}#iu",$ip)){//前方一致
        return true;//起動OK
      }
    }
    return false;//デフォルトは起動NG
  }
//(下略)
}

 ?>

てな感じ。以上。
defined('CRON')の所は、
バッチ経由でCodeIgniterを起動した時には、define('CRON') = TRUE;が設定されているため。
(バッチ起動については以前のエントリーを参照)


簡単のためコントローラ側に書いているけど、実際はコントローラ毎に仕込むのではなく、
どこかのヘルパに持たせて、共通化してログも取った方が良いかもね。


余談

httpd.conf(.htaccess)で、
特定のIPアドレスはノーパスワードで接続許可し、それ以外はベーシック認証を掛けたい時は、

<VirtualHost>
 (上略)
  <Directory "/var/vhosts/xxx.example.com/CodeIgniter_1.7.0/html">
            Options Includes FollowSymLinks ExecCGI MultiViews
            AllowOverride All
            AuthType Basic
            AuthName "please enter hogefuga"
            AuthUserFile /var/vhosts/xxx.example.com/.htpasswd
            AuthGroupFile /dev/null
            Require valid-user
            Order deny,allow
            Deny from all
            Allow from 許可したいIPアドレス1
            Allow from 許可したいIPアドレス2
            Satisfy Any
  </Directory>
 (下略)
</VirtualHost>


みたいに、Satisfy Anyを使えばよい。(ベーシック認証の設定方法については説明省略)




今日はここまで。(エントリー手抜きだなー)


説明追記

(2009/01/01追記)

id:Kenji_s 様ご指摘ありがとうございます。
コメントのご指摘に伴い、記述追加します。舌足らずですみません。


実際は、

  1. 偽装できるかもしれないIPアドレスでの簡易チェック(このエントリーのコレ)と、
  2. 特定コントローラ内での処理起動用認証(api起動用id認証)と、
  3. httpd.conf側でのmod_rewriteでの制限と、
  4. 内部専用の機能は、そもそも外部に置かない。

を複合させておこなっています。(取り扱うデータの性質により異なる。)



1)
1に関しては、
$_SERVER['HTTP_CLIENT_IP'];を返す可能性のある、

$this->input->ip_address();

をやめて

$this->input->server('REMOTE_ADDR');

に訂正しました。



2)
2に関しては、
認証をかけたいコントローラ別(メソッド別)の認証を行っています。

当然一般ユーザーの認証とは別ロジック(|別DB|別テーブル)で、
起動するapi(xmlrpc)の種類毎の個別認証です。

(実装と構成は取り扱う内容・重要度によって異なります。)



3)
3に関しては、

RewriteEngine On
RewriteBase /
RewriteRule \.db$ - [F]
#RewriteRule \.db$ - [R=404]

RewriteCond %{REMOTE_ADDR} !^(127\.0\.0\.1$|192\.168\.1\.10$)
RewriteRule ^(.*)hogehoge_svs(.*)$ - [L,R=403]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|images|img|css|js|xajax_js|tmp|robots\.txt|.+\.gif$|.+\.jpg$|.+\.png$|.+\.js$|.+\.css$)
RewriteRule ^(.*)$ /index.php/$1 [L]

のように、mod_rewrite側(httpd.conf又は.htaccess側)での制限を行っています。
URIにhogehoge_svsが含まれている場合は無条件で制限(ipアドレスとhogehoge_svsは説明用ダミー))



最悪リモートアドレス偽装をされても、2の認証側で弾きます。
(当然2の認証が漏れたり破られたりしたらどうしようもありませんが)



4)

実際は4のソース構成・機能構成が一番重要で、
外部(フロントエンド)に晒す必要のない機能はソースを外部向けでは丸ごと削除して、
イントラ内の内向きwebサーバ(バックエンド用)のみに設置します。
(イントラといえど信用できないので、認証はかける)


ここから先は、
要件レベル(予算)・対象とする利用者・ネットワーク構成など、
システム全体の構成の問題により、条件・対処が異なりますので、この日記では割愛します。


以上補足します。


(追記おわり)