-
dwlamb Junior Member
 
-
Posts: 21
Threads: 8
Joined: Nov 2014
Reputation:
1
I am having a challenge with the csrf token for resetting a password in ion_auth. I have read other posts here and on other sites about ion_auth & csrf.
In a nutshell, it seems the csrf data stored in flashdata under $_SESSION does not survive from the form created and when the form is submitted.
PHP Code: public function reset_password($code = NULL) { if (!$code) { show_404(); }
$user = $this->ion_auth->forgotten_password_check($code);
if ($user) { // if the code is valid then display the password reset form
$this->form_validation->set_rules('new', $this->lang->line('reset_password_validation_new_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[new_confirm]'); $this->form_validation->set_rules('new_confirm', $this->lang->line('reset_password_validation_new_password_confirm_label'), 'required');
if ($this->form_validation->run() === FALSE) { // display the form
// set the flash data error message if there is one $this->data['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message');
$this->data['min_password_length'] = $this->config->item('min_password_length', 'ion_auth'); $this->data['new_password'] = array( 'name' => 'new', 'id' => 'new', 'type' => 'password', 'pattern' => '^.{' . $this->data['min_password_length'] . '}.*$', ); $this->data['new_password_confirm'] = array( 'name' => 'new_confirm', 'id' => 'new_confirm', 'type' => 'password', 'pattern' => '^.{' . $this->data['min_password_length'] . '}.*$', ); $this->data['user_id'] = array( 'name' => 'user_id', 'id' => 'user_id', 'type' => 'hidden', 'value' => $user->id, ); $this->data['csrf'] = $this->_get_csrf_nonce(); $this->data['code'] = $code;
$this->data['site_title'] = 'Reset Password — '.$this->config->item('site_title');
// render $this->_render_page('reset_password_form', $this->data); } else { // do we have a valid request? if ($this->_valid_csrf_nonce() === FALSE || $user->id != $this->input->post('user_id')) {
// something fishy might be up $this->ion_auth->clear_forgotten_password_code($code);
show_error($this->lang->line('error_csrf'));
} else { // finally change the password $identity = $user->{$this->config->item('identity', 'ion_auth')};
$change = $this->ion_auth->reset_password($identity, $this->input->post('new'));
if ($change) { // if the password was successfully changed $this->session->set_flashdata('message', $this->ion_auth->messages()); redirect("auth/login", 'refresh'); } else { $this->session->set_flashdata('message', $this->ion_auth->errors()); redirect('auth/reset_password/' . $code, 'refresh'); } } } } else { // if the code is invalid then send them back to the forgot password page $this->session->set_flashdata('message', $this->ion_auth->errors()); redirect("auth/forgot_password", 'refresh'); } }
public function _get_csrf_nonce() { $this->load->helper('string'); $key = random_string('alnum', 8); $value = random_string('alnum', 20); $this->session->set_flashdata('csrfkey', $key); $this->session->set_flashdata('csrfvalue', $value);
return array($key => $value); }
public function _valid_csrf_nonce() { $csrfkey = $this->input->post($this->session->flashdata('csrfkey')); if ($csrfkey && $csrfkey === $this->session->flashdata('csrfvalue')) { return TRUE; } else { return FALSE; } }
Stepping through the code with Xdebug, the flashdata of the csrf key and its value is not persisting in $_SESSION between the instant it is set at the time the form is rendered and when the form is submitted. The flashdata is set by
Code: $this->data['csrf'] = $this->_get_csrf_nonce();
when "$this->form_validation->run() === FALSE".
The steps involved to check the csrf token occur after "// do we have a valid request?". The function "_valid_csrf_nonce()" returns FALSE for the 'csrfkey' and 'csrfvalue' are no longer present.
I have tried setting cookies by a file or sessions managed by a database, as recommended on Ben Edmunds' github page.
Has anyone else encountered such a problem and can recommend a solution? Thanks for taking the time to read this.
-
dwlamb Junior Member
 
-
Posts: 21
Threads: 8
Joined: Nov 2014
Reputation:
1
(02-07-2018, 02:02 PM)ChicagoPhil Wrote: Are you using the forms that came in ion auth? I'm still thinking of what is going wrong here but are you sure the problem stems from the controller?
I did not foresee it as an issue but it turns out using forms improved from those provided with the ion_auth package are somehow responsible for the flashdata being deleted from the $_SESSION.
So the question becomes what do I do to make the flashdata persist or what to look for in my forms that is causing the session to regenerate?
I can't identify something in the form to cause the session to regenerate. All I changed was some of the semantic mark up of html, head and body tags so css or javascript can be incorporated. The forms in ion_auth are only the form. No other mark up. I did not change any of the semantics inside the form_open and form_close syntax.
I tried the following syntax to make the session persist. It was inserted at the point form validation is FALSE and the form for submitting a new password is generated (second to last line):
PHP Code: if ($this->form_validation->run() === FALSE) { // display the form
// set the flash data error message if there is one $this->data['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message');
$this->data['min_password_length'] = $this->config->item('min_password_length', 'ion_auth'); $this->data['new_password'] = array( 'name' => 'new', 'id' => 'new', 'type' => 'password', 'pattern' => '^.{' . $this->data['min_password_length'] . '}.*$', ); $this->data['new_password_confirm'] = array( 'name' => 'new_confirm', 'id' => 'new_confirm', 'type' => 'password', 'pattern' => '^.{' . $this->data['min_password_length'] . '}.*$', ); $this->data['user_id'] = array( 'name' => 'user_id', 'id' => 'user_id', 'type' => 'hidden', 'value' => $user->id, ); $this->data['csrf'] = $this->_get_csrf_nonce(); $this->data['code'] = $code;
$this->data['site_title'] = 'Reset Password — '.$this->config->item('site_title'); //added to keep flashdata persistent $this->session->keep_flashdata(array('csrfkey','csrfvalue'));
// render $this->_render_page('reset_password_form', $this->data);
-
ChicagoPhil Member
  
-
Posts: 64
Threads: 6
Joined: Jan 2015
Reputation:
6
This is copied from the user guide. Perhaps your form is missing this post data?
Code: $csrf = array(
'name' => $this->security->get_csrf_token_name(),
'hash' => $this->security->get_csrf_hash()
);
...
<input type="hidden" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />
-
dwlamb Junior Member
 
-
Posts: 21
Threads: 8
Joined: Nov 2014
Reputation:
1
(02-08-2018, 12:43 AM)ChicagoPhil Wrote: This is copied from the user guide. Perhaps your form is missing this post data?
Code: $csrf = array(
'name' => $this->security->get_csrf_token_name(),
'hash' => $this->security->get_csrf_hash()
);
...
<input type="hidden" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />
No, this is not the issue of missing data. The missing token name and token value are present in the DOM. It is the identical values in the $_SESSION that go *poof* somehow with rendering the view.
-
dwlamb Junior Member
 
-
Posts: 21
Threads: 8
Joined: Nov 2014
Reputation:
1
(02-08-2018, 08:11 AM)dave friend Wrote: I suspect that session and or cookie configs are wrong. Care to share those config settings?
Researching this further, there are some threads that mention the csrf programming in ion_auth can be dropped in favour of the csrf protection built-in to CI 3.x. If I enable csrf protection using settings below I get the following error when I submit a form:
Code: An Error Was Encountered
The action you have requested is not allowed.
My understanding is all of the checks for csrf protection are done automatically by CI. The form I tested did not use ion_auth csrf protection.
These are the config statements for csrf protection taken from application/config/config.php
PHP Code: $config['csrf_protection'] = TRUE; $config['csrf_token_name'] = 'csrf_test_name'; $config['csrf_cookie_name'] = 'csrf_cookie_name'; $config['csrf_expire'] = 7200; $config['csrf_regenerate'] = TRUE; $config['csrf_exclude_uris'] = array();
These are the config statements for sessions taken from application/config/config.php
PHP Code: $config['sess_driver'] = 'database'; $config['sess_cookie_name'] = 'ci_session'; $config['sess_expiration'] = 7200; $config['sess_save_path'] = 'ci_sessions'; $config['sess_match_ip'] = FALSE; $config['sess_time_to_update'] = 300; $config['sess_regenerate_destroy'] = FALSE;
These are the config statements for cookies taken from application/config/config.php
PHP Code: $config['cookie_prefix'] = ''; $config['cookie_domain'] = ''; $config['cookie_path'] = '/'; $config['cookie_secure'] = FALSE; $config['cookie_httponly'] = FALSE;
-
dave friend Posting Freak
    
-
Posts: 1,015
Threads: 15
Joined: Jun 2015
Reputation:
50
The error: "The action you have requested is not allowed." might be because you either
1) Did not use form_open() in your view or
2) Did not add a hidden field to the form with the CSRF token and hash.
form_open() automatically adds the hidden field for you.
Nothing jumps out at me as wrong in your config settings.
I developed a simple controller and view to test if sessions are working.
It's easy to install (and remove) from a project and should provide a definitive answer to the question, "Are sessions working?"
The files are on github HERE
Hope it is helpful.
-
dwlamb Junior Member
 
-
Posts: 21
Threads: 8
Joined: Nov 2014
Reputation:
1
(02-08-2018, 11:02 AM)dave friend Wrote: The error: "The action you have requested is not allowed." might be because you either
1) Did not use form_open() in your view or
2) Did not add a hidden field to the form with the CSRF token and hash.
form_open() automatically adds the hidden field for you.
Nothing jumps out at me as wrong in your config settings.
I developed a simple controller and view to test if sessions are working.
It's easy to install (and remove) from a project and should provide a definitive answer to the question, "Are sessions working?"
The files are on github HERE
Hope it is helpful.
Thanks for the sessions testing package. I ran it and according to it, sessions are working.
The csrf protection is not working despite using form_open. The hidden fields for csrf data are present in the form and the values present in $_POST at the time of form submission.
I am shifting from trying to resolve csrf as implemented by ion_auth to using csrf as implemented by CI 3.x. I figure better to implement it site-wide and debug the challenges than getting it to work one way and then having to debug the ion_auth methods.
With `$config['csrf_regenerate'] = TRUE;` and using html valid forms, csrf protection fails. Using the barebones forms supplied with ion_auth, csrf protection passes. Stepping through function csrf_verify() (line 206 of Security.php in CI ver. 3.1.6) there is a discrepancy between the crsf_hash in the cookie, $this->_csrf_hash and the hash within $_POST. It is as though somehow html valid forms are submitted twice, the second pass the new value of the csrf hash in $_POST is not updated to the cookie before the form is submitted.
If this convoluted and confusing, I apologise. Trying to get a handle on this is proving a challenge.
|