BETA

CakePHP2でBlackHole(Authエラー)に引っかかる時の対応

投稿日:2018-12-01
最終更新:2018-12-26

CakePHP2でBlackHoleに引っかかるパターンとして多いのは以下の3通り。

  • ページを開いてから一定時間が経過
  • 保存する際tokenを渡していない(csrfCheckに引っかかる)
  • hiddenデータを書き換えようとしている

hiddenデータの書き換えは前回投稿したので、今回は上ふたつについてまとめる。

基礎知識

CakePHPでは $this->Form->create(); で作成したフォームにtokenが発行される。そのtokenが有効期限以内に渡されているかどうかでセキュリティを担保している。

パターン1: ページを開いてから一定時間が経過

原因

tokenの有効期限切れ。tokenはページを開いた際(=フォーム生成時)に発行され、その有効期限がデフォルトでは30分前後となっている。よってページを開いてから30分以上経過するとBlackHoleに放り込まれる。

対応

有効期限を伸ばさない場合は、JavaScriptなどで一定時間経過するとリロードを促すモーダルウィンドウを表示させる、などの対応が適当かと思われる。

もし有効期限を伸ばすようであればControllerで以下のように設定する。

$components で設定

public $components = [  
  'Security' => [  
    'csrfExpires' => '+1 hour'  
  ]  
];  

beforFilter で設定

$this->Security->csrfExpires = '+1 hour';  

パターン2: 保存する際tokenを渡していない(csrfCheckに引っかかる)

原因

フォーム送信時、発行されたtokenと照合して正しく送られたデータであるかを確かめるため、tokenも一緒に送信しなければいけない。

Ajaxなどで送信する際このtokenのみ送り漏れ、BlackHoleにハマることが多い。
また、一度利用したtokenは使い回せないため、Ajaxで利用した後、tokenを再発行する必要がある。

対応

1. そもそもtokenでのチェック(CSRFチェック)をしない

Controllerで以下のように設定。

$components で設定

public $components = [  
  'Security' => [  
    'csrfCheck' => false  
  ]  
];  

beforFilter で設定

$this->Security->csrfUseOnce = false;  

ただし上記の対応はセキュリティ的に問題があるため、推奨しない。

2. tokenを渡し、利用した後tokenを再発行する

View(JS)

// フォームのデータ取得  
var formName;  
var savedata = $(formName).find('input,select,textarea').serializeArray();  

// tokenをデータと共に送信  
var $formToken = $(formName+' input[name="data[_Token][key]"]').val();  
    savedata[savedata.length] = {name: 'data[_Token][key]', value: $formToken};  

// データを送信  
$.ajax({  
  url: '/Models/action',  
  type: 'post',  
  dataType: 'json',  
  data: savedata,  
}).always(function(data){  
  // トークンキー書き換え  
  if(data.token!=='undefined') {  
    $(formName).find('input:hidden[name="data[_Token][key]"]').val(data.token.key);  
  }  
});  

Controller

public function action() {  
  if($this->request->is('ajax')) {  
    $result = [];  

    /*  
      それぞれ必要な処理を記述  
    */  

    // token再発行  
    if(!empty($this->request->params['_Token'])) {  
      $result['token'] = $this->request->params['_Token'];  
    }  
    return new CakeResponse(json_encode($result));  
  }  
}  

おまけ:ブラックホールコールバックの処理

BlackHoleに吸い込まれた際のハンドリングとして、BlackHoleメソッドを用意し、処理を任せるのが良い。

public function beforeFilter() {  
  $this->Security->blackHoleCallback = 'blackhole';  
}  

public function blackhole($type) {  
  // エラー処理  
}  

$type処理は以下の通り
ブラックホールコールバックの処理(セキュリティ - 2.x)

  • auth: フォームバリデーションエラー、もしくはコントローラ/アクションの不適合エラー
  • csrf: CSRF エラー
  • get: HTTP メソッド制限の失敗
  • post: HTTP メソッド制限の失敗
  • put: HTTP メソッド制限の失敗
  • delete: HTTP メソッド制限の失敗
  • secure: SSL メソッド制限の失敗
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@tanakashiの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!