For the first time, I am trying to implement the anti-CSRF protection of Fatfree. However, the posted token differs from the stored one, while I am in the same session without any change. Does anyone know what I am doing wrong?
In index.php, before run(), I create a new session. With this session variable, I store a new CSRF token:
// Set up the base class
$f3 = Base::instance();
// Start session, create token agains CSRF attacks
// and store token
$session = new Session();
$f3->set('CSRF', $session->csrf());
// Run the application
$f3->run();
Next, after authentication, I store the created CSRF token in a session variable, like this:
if(password_verify($password, $user->password)) {
$this->logLastLogin($user);
$this->f3->set('SESSION.username', $user->username);
$this->f3->set('SESSION.id', $user->id);
$this->f3->set('SESSION.role', $user->role);
$this->f3->set('SESSION.rolename', $this->getRoleName());
$this->f3->set('SESSION.avatar', $user->avatar);
$this->f3->set('SESSION.name', $user->name);
$this->f3->set('SESSION.email', $user->email);
$this->f3->set('SESSION.class', $user->class_id);
$this->f3->set('SESSION.forget', $isForgetEnabled);
$this->f3->copy('CSRF','SESSION.csrf'); // Save actual token against CSRF in session
$this->f3->reroute('/');
} else {
$this->f3->reroute('/login');
}
Then, I have a form with a hidden input field, which is required. The field has the name 'token' and the value of 'CSRF':
<form method="POST" action="{{ @BASE }}/edit_course_general?course={{ @admin_course['id'] }}" enctype="multipart/form-data">
<input type="hidden" name="token" value="{{ @CSRF }}/>
<div class="br-full-div-form-area">
<div class="form-group row">
<label for="name" class="col-sm-2 col-form-label">{{ @messages.edit_course_shortcode }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="shortcode" placeholder="{{ @admin_course['shortcode'] }}" value="{{ @admin_course['shortcode'] }}">
</div>
</div>
<div class="form-group row">
<label for="name" class="col-sm-2 col-form-label">{{ @messages.edit_course_name }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" placeholder="{{ @admin_course['name'] }}" value="{{ @admin_course['name'] }}">
</div>
</div>
<div class="form-group row">
<label for="role" class="col-sm-2 col-form-label">{{ @messages.edit_course_teacher }}</label>
<div class="col-sm-10">
<select class="form-control" name="teacher">
<repeat group="{{ @admin_teacher }}" value="{{ @teacher }}">
<check if="{{ @teacher['id'] == @admin_course['teacher_id'] }}">
<true>
<option>{{ @teacher['username'] }} ({{ @messages.edit_course_current_teacher }})</option>
</true>
<false>
<option>{{ @teacher['username'] }}</option>
</false>
</check>
</repeat>
</select>
</div>
</div>
<div class="form-group row">
<label for="name" class="col-sm-2 col-form-label">{{ @messages.edit_course_upload_select }}</label>
<div class="col-sm-10">
<input type="file" name="fileToUpload" id="fileToUpload">
</div>
</div>
</div>
<div class="br-full-div-action-area">
<button type="submit" class="btn btn-primary">{{ @messages.edit_course_btnlabel }}</button>
</div>
</form>
After the post, I capture the current token and compare it with the stored one:
$storedToken = $this->f3->get('SESSION.csrf');
$postedToken = $this->f3->get('POST.token');
if($storedToken!=$postedToken) {
echo $storedToken;
echo "\n\n";
echo $postedToken;
} else {
echo "woohoo";
}
The result, is however, that tokens are not the same:
1cpdjtpdvqf4s.39i1wmif918g8 1cpdjtpdvqf4s.3q7ydqzo55s0/>
I am not sure what I am doing wrong. I enabled cache, so that could not be the problem...