We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

CRF check

Hi,

I can't seem to get the CSRF check working, could you please help?

This is the code:

LoginForm.php

<?php

public function initialize() {

    $crf_name = $this->security->getTokenKey();
    $crf_value = $this->security->getToken();

    $crf = new Hidden("crf");
    $crf->setAttribute("name", $crf_name);
    $crf->setAttribute("value", $crf_value);
    $this->add($crf);
    ...

The hidden element crf is created like this:

<html>
    <input type="hidden" id="crf" name="..." value="...">

LoginController.php

<?php
    ...
        if ($this->request->isPost()) {
            if ($this->security->checkToken()) {
    ...

The value exists in the $_POST and there is a value in the $_SESSION however it never seems to pass the check. I don't know much about this, the value in $_POST and $_SESSION differ but I assume that is the point.

I've tried changing the id of the crf element to the value of getTokenKey() such that the value returned by getTokenKey() exists in both the id and the name, result is similar to this:

<html>
    <input type="hidden" id="..." name="..." value="...">

Perhaps you can see what I've done wrong.

@ShadMickelberry Thanks for your response, I have started a Session. In the Session there are two variables in my debug window: $PHALCON/CSRF/KEY$ and $PHALCON/CSRF$.

Too bad it wasn't so easy . I had trouble with this check using Chrome due to no favicon so if you are using it may try different browser. Sorry if that isn't the case

I have tried using mulitple browsers without success.

Looking at Vokuro, on this line:

{{ form.render('csrf', ['value': security.getToken()]) }}

The result of security.getToken() should be identical to getSessionToken(), seen on here:

$csrf = new Hidden('csrf');
$csrf->addValidator(new Identical(array(
    'value' => $this->security->getSessionToken(),
    'message' => 'CSRF validation failed'
)));

But I would really like some feedback.

Sorry, this question has already been solved here.

This was the solution inspired by the solution in the post above.

LoginForm.php

        ...
        // Cross-Site Request Forgery (CSRF) protection
        $csrf_value = $this->security->getSessionToken() ? : $this->security->getToken();

        $csrf = new Hidden("csrf");
        $csrf->setAttribute("value", $csrf_value);
        $csrf->addValidator(new Identical([
            "value"     =>  $this->security->getSessionToken(),
            "message"   =>  "CSRF invalid"
        ]));
        $this->add($csrf);
        ...

LoginController

        ...
        if ($this->request->isPost()) {
            if ($form->isValid($this->request->getPost())) {
        ...

More feedback would've been appreciated.

I am having the same problem. I have just put up a post before seeing this one (should have checked). I also have Sessions set in the DI, and have Sessions working across the application. I am using chrome, I will check with a different browser.

Also tried in Safari, same problem



7.7k
Accepted
answer
edited May '15

I'll have a look at your solution above, thanks.

That seemed to do the trick for me as well, although I adpated your solution slightly to keep the code cleaner.

login/index.volt

    ...
    {% for element in form %}
        {% if is_a(element, 'Phalcon\Forms\Element\Hidden') %}
            {{ element.render(['name': this.security.getTokenKey(), 'value': this.security.getToken()]) }} {#<- CSRF#}
        {% else %}
        ...