Phalcon CSRF (跨網站偽造請求) protection

CSRF (cross site request forgery)特別對於表單的保護(尤其是登入頁面)很重要,在 Phalcon framework (3.x) 中可以參考以下範例(或者參考官方文件的 example)。

在登入頁面 (e.g. login.volt) 加上一個 hidden field,其 field name 與 field value 都是由 controller 產生給予。

<div class="container-fluid">
    <div id="loginPanel">

        {{ form("login/login", "method":"post", "autocomplete" : "off", "class" : "form-horizontal") }}
            <input type="text" class="form-control" id="username" name="user[username]" placeholder="Username">
            <input type="password" class="form-control" id="password" name="user[password]" placeholder="Password">
            <input type="submit" class="btn btn-default" id="login" value="Log In">
            <input type="hidden" name="{{csrfTokenKey}}" value="{{csrfToken}}">
        {{ link_to('login/forget', "password forgot?") }}
        </form>
    </div>
</div>

然後在 controller 裏頭

<?php
class LoginController extends ControllerBase
{
    public function indexAction()
    {
        // restart a session
    	$this->session->destroy();
        $this->session->start();

        // generate token for form forgery protection
        $this->view->csrfTokenKey = $this->security->getTokenKey();
        $this->view->csrfToken = $this->security->getToken();
    }

    public function loginAction()
    {
        if (!$this->request->isPost())
        {
            $this->flashSession->error("Should be a form post");
            return $this->response->redirect("login/index");
        }
		
		// get the key of the last POST data element
		end($_POST);
		$key = key($_POST);

        if (!$this->security->checkToken($key, $_POST[$key], false))
        {
            $this->flashSession->error("No form forgery");
            return $this->response->redirect("login/index");
        }
		
		// do other things
		// ...
    }
}

比較要注意的是 security->getTokenKey() , security->getToken() , security->checkToken() 這三個 function call。官方文件在呼叫checkToke()時,是沒有傳任何參數,但實際上是等於拿 $_POST 資料的 tokenkey 跟 token 去做驗證 (如同上面的 sample code)。