CodeIgniter 2.1.4
After doing a little research about CodeIgniter's XSS protections, I decided to quickly and crudely test this by typing some random HTML into any input field on my CodeIgniter forms.
When I typed in <script>, the page is redirected to the server's default 403 error ("Forbidden") page. It's not even a CodeIgniter error page.
I'm very glad that any input data containing <script> is stopped, however, I'm not understanding why this is generating a 403 error page instead of a validation error, or at least pass the data with the offending parts stripped out.
I'm using htmlentities() to convert the < and > but this makes no difference.
It doesn't even matter if implement the form validation. The input data of <script> will generate a 403 error even without it.
Can anyone explain what's happening here and if I need to be worried out how this is being handled/redirected? To me it just seems like I should be getting some sort of CodeIgniter validation error or stripped down data rather than a 403 error.
Here is a concise version of one of my Controllers. (It's happening on all Controllers with data input fields.)
public function search($search_slug = NULL)
{
$this->load->library('form_validation');
$this->form_validation->set_rules('search-terms', 'Search Terms', 'xss_clean');
if ($this->input->post('search-terms') && ($this->form_validation->run() !== FALSE))
{
$search_slug = url_title(htmlentities($this->input->post('search-terms')), 'dash', FALSE);
}
if ($search_slug !== NULL)
{
$search_terms = preg_replace('/-/', ' ', $search_slug);
$query = // get my results from model;
if ($query['count'] > 0)
{
$data['results'] = $query['results'];
}
else
{
$data['results'] = '<h3>Sorry, nothing found.</h3>';
}
}
else
{
$data['results'] = '<h3>Please enter your search terms.</h3>';
}
$this->template->load('default', 'search', $data);
}
After reading the comments on my OP and digging into it deeper, this 403 redirect doesn't seem to have anything to with CodeIgniter after all.
Also, after installing ZenPhoto on the same account, I see the 403 redirect when entering <script> into the ZenPhoto search box too.
Since it's shared hosting, I cannot say, with 100% certainty, that this is the result of something in Apache protecting itself, but all evidence seems to point there.
This character is not allowed.
check accepted answer # SO - characters allowed in a url
Your request wasn't reaching index.php
Apart from that have a look at application/config/config.php
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
These are the characters your application allows when a request reaches it.
Related
PHP Controller:
$this->form_validation->set_rules('phone', $this->language->get_text('phone', 'global'), 'max_length[0]');
I need to put an IF condition for the above line code to return this:
if (The_Above_Line_Code is NOT empty)
{
$this->output->set_status_header(400);
exit;
}
So, if the input field don't contain characters it's OK and the contact form to work properly, but if contain characters, then should return a blank page (set_status_header(400)).
PS: It's a way to combat spam in contact form.
$this->form_validation->set_rules('phone', $this->language->get_text('phone', 'global'), 'max_length[0]|numeric');
If it's not a number then form validation fails. I don't see the logic in serving a 400.
https://www.codeigniter.com/userguide3/libraries/form_validation.html?highlight=form%20validate#rule-reference
Update
After understanding your reasoning better you can simply do this:
if (!empty($this->input->post('phone'))) {
show_404(); // sets header + exits
}
You can even use show_404() (CI function) as a way to log the error: show_404('bot detected', true);.
I have this piece of code in PHP web app.
if (isset($require_admin) && $require_admin) {
if(!check_admin()) {
$toolContent_ErrorExists = $langCheckAdmin;
$errorMessagePath = "../../";
}
}
The normal behavior is that if the variable $require_admin is set and true,the code will check if the visit is by the admin.
I try to add a similar piece of code some lines below so as to make other things like checking for cross-origin(especially CSRF) requests.
if (isset($require_token) && $require_token) {
if( !checkToken( $mycsrf_token, $myform)) {
$toolContent_ErrorExists = $langCheckToken;
$errorMessagePath = "../../";
}
}
I had in mind that in this way i will have a check that the posted forms I get are valid and if no,there would be an error message.
However,when $require_token is set and true,and the condition is verified i have a very strange result.Not only nothing happens for the csrf validation,but the above function stops working properly and admin restriction stops to work.
I know the question maybe is ambiguous but I cannot get what's going on there.I'm not so experienced on web programming and totally new in PHP so maybe someone could have a better idea!
I'm attempting to validate a users login attempt and inform them that
Their username is wrong or
their password is wrong (because I personally hate with a blind fury when a website doesn't inform me WHICH it is but that's beside the point).
I've read a lot of SO posts on this issue but the ones I've found are years old and I'm dealing with CodeIgniter 3.0.1.
This is the code that I have in place. I'm using Eclipse PDT to as my IDE and I like it quite a bit (but that's getting off track) so I've been able to step through the execution and watch as it just fails completely.
IF (!$this->User->login( //Testing shows this works fine - the SWITCH statement gets executed as it should and the BADUSERNAME case is followed through.
addslashes(strtolower($this->input->post('username', TRUE))),
addslashes($this->input->post('password', TRUE)),
$this->getIP())){
SWITCH($this->User->ID){
CASE 'BADUSERNAME':
$this->session->set_flashdata('user_msg', 'Invalid Username');
BREAK;
CASE 'BADPASSWORD':
$this->session->set_flashdata('user_msg', 'Invalid Password');
BREAK;
CASE 'ALREADYLOGGEDIN':
$this->session->set_flashdata('user_msg', 'You are logged in elsewhere.');
BREAK;
DEFAULT:
$this->session->set_flashdata('user_msg', 'Something has gone terribly wrong. Please try logging in again.');
BREAK;
}
redirect(base_url());
}
Then a bit further down I load the header, body, and footer views - The body is where the error message should be displayed but it's not..
<div id="contentarea">
<div class="container">
<?PHP
ECHO $this->session->flashdata('show_validation') ? validation_errors() : '';
$error = $this->session->flashdata('user_msg'); //This is where it's supposed to get it...
IF ($error) //And this is where it's supposed to show it...
ECHO "<div class='error'>$error</div>";
?> //But the value is wiped so it only ever grabs NULL.
I've followed the path of execution after calling the redirect after setting the flash data and I've noticed that after the redirect finishes it's chain of execution, it calls exit;.
Then everything loads again from the index.php file, and when Session finally pops up... the value 'user_msg' is nowhere to be found.
So clearly I'm doing something wrong here - what am I doing wrong here? Will the flash_data only persist until that redirect is called? Even the session_data values (calling $this->session->value = 'some arbitrary user message' fails to persist).
How can I persist the message for the next time the body element is loaded so that it can tell the user "Hey, didn't find you" or "Hey, your password wasn't right"?
EDIT 1
So it turns out I do not need to redirect for what I am doing as POSTing (submitting the user name and password) handles that for me.
I'm going to leave the question here for anyone else who may need it answered though - perhaps the answer is simply that Flash data just doesn't survive a redirect?
Flashed data is only available for the next http request, if you reload the page a second time, data is gone.
To persist data in the session, you want to set the variable in the session.
Codeigniter
Adding Session Data
Let’s say a particular user logs into your site. Once authenticated, you could add their username and e-mail address to the session, making that data globally available to you without having to run a database query when you need it.
You can simply assign data to the $_SESSION array, as with any other variable. Or as a property of $this->session.
Alternatively, the old method of assigning it as “userdata” is also available. That however passing an array containing your new data to the set_userdata() method:
$this->session->set_userdata($array);
$this->session->set_userdata('username', 'username is wrong');
in the view
$this -> session ->userdata('username');
or
$this ->session -> username;
Reference Session Library Codeigniter.
hope this help.
All you have to do is use $this->session->keep_flashdata('user_msg') with $this->session->unset_userdata('user_msg')
here is the solution (view file)
<?php
$error = $this->session->flashdata('user_msg');
if (isset($error)) {
echo '<div class="error">' . $error . '</div>';
$this->session->unset_userdata('user_msg');
}
?>
After that in your controller construct function (In that controller where you redirecting)
public function __construct() {
parent::__construct();
//.....
$this->session->keep_flashdata('user_msg');
}
I had same problem and this works. do not forget to clear cache when try or try in different browser
You can use codeigniter's flashdata to display errors separately.
This is what I usually use.
Controller:
$errors = array();
foreach ($this->input->post() as $key => $value){
$errors[$key] = form_error($key);
};
$response['errors'] = array_filter($errors);
$this->session->set_flashdata($response['errors']);
redirect('your-page', 'refresh');
And the to display the errors use
<?php echo $this->session->flashdata('field_name'); ?>
So, I've been struggling with this for some time, but to no avail. My research didn't help much, either. Here it is: I built a test to prevent people to go to the alter page of an module by typing the address directly in the url without the id of the registry to be altered (therefore causing trouble in the DB). Simply put, it searches for the id passed as parameter in the url in the DB; if it has a match, it proceeds, if not, I redirect to the main module page with an error message passed via flashdata. I use a similar process to impede the insertion/alteration of registries if a field from a different table is not defined (as it is required in both in order to work, as the tables are related). A rough example of what I'm doing in the Controller is:
if(is_numeric($id)) $search=$this->model_foo->search($id);
else
{
$this->session->set_flashdata('error_message','not numeric');
redirect('myurl/index','refresh');
}
if($search->num_rows()==0)
{
$this->session->set_flashdata('error_message','not found');
redirect('myurl/index','refresh');
}
$search=$this->model_foo2->list();
if ($search->num_rows()==0)
{
$this->session->set_flashdata('error_message','other table empty');
redirect('myurl/index','refresh');
}
And my view (index) is like this:
<?php
$error=$this->session->flashdata('error_message');
$success=$this->session->flashdata('success_message'); /*success_message goes after a successful inset/update*/
if ($error!="")echo $error;
?>
So here is the issue: the success messages show up normally (I checked and double checked, they are being declared in the Controller the exact same way the error ones), as well as the 'not numeric' one, but not the 'not found' and 'other table empty' ones. I'm really confused by this one, since the flashdata seems to work in some instances and not in others, which is specially weird given the flashdata are being declared in pretty much the same way... =/ Sorry if I wasn't clear enough, this is my first post here, so (try to) be patient ;D Thanks in advance for any help in this matter.
EDIT: Found out the source of the issue. It was something with my browsers cache storage. Rebooted my machine and cleaned the cache and the output worked like a charm. Thanks for all the help.
So, i just improved your code a little bit so you can try and debug...
Controller:
$arr = array('error_message' => '');
if(!empty($id) && is_numeric($id)) {
$search=$this->model_foo->search($id);
if($search->num_rows()==0) {
$arr['error_message'] = 'not found';
} else {
$search=$this->model_foo2->list();
if ($search->num_rows()==0) {
$arr['error_message'] = 'other table empty';
}
}
} else {
$arr['error_message'] = 'not numeric';
}
$this->session->set_flashdata($arr);
redirect('myurl/index');
View (same):
<?php
$error=$this->session->flashdata('error_message');
$success=$this->session->flashdata('success_message'); /*success_message goes after a successful inset/update*/
if ($error!="")echo $error;
?>
Give a try with this and before check if the message appears, make sure the flashdata is set.
I have a strange problem with my cake (cake_1.2.0.7296-rc2).
My start()-action runs twice, under certain circumstances, even though only one request is made.
The triggers seem to be :
- loading an object like: $this->Questionnaire->read(null, $questionnaire_id);
- accessing $this-data
If I disable the call to loadAvertisement() from the start()-action, this does not happen.
If I disable the two calls inside loadAdvertisement():
$questionnaire = $this->Questionnaire->read(null, $questionnaire_id);
$question = $this->Questionnaire->Question->read(null, $question_id);
... then it doesn't happen either.
Why?
See my code below, the Controller is "questionnaires_controller".
function checkValidQuestionnaire($id)
{
$this->layout = 'questionnaire_frontend_layout';
if (!$id)
{
$id = $this->Session->read('Questionnaire.id');
}
if ($id)
{
$this->data = $this->Questionnaire->read(null, $id);
//echo "from ".$questionnaire['Questionnaire']['validFrom']." ".date("y.m.d");
//echo " - to ".$questionnaire['Questionnaire']['validTo']." ".date("y.m.d");
if ($this->data['Questionnaire']['isPublished'] != 1
//|| $this->data['Questionnaire']['validTo'] < date("y.m.d")
//|| $this->data['Questionnaire']['validTo'] < date("y.m.d")
)
{
$id = 0;
$this->flash(__('Ungültiges Quiz. Weiter zum Archiv...', true), array('action'=>'archive'));
}
}
else
{
$this->flash(__('Invalid Questionnaire', true), array('action'=>'intro'));
}
return $id;
}
function start($id = null) {
$this->log("start");
$id = $this->checkValidQuestionnaire($id);
//$questionnaire = $this->Questionnaire->read(null, $id);
$this->set('questionnaire', $this->data);
// reset flow-controlling session vars
$this->Session->write('Questionnaire',array('id' => $id));
$this->Session->write('Questionnaire'.$id.'currQuestion', null);
$this->Session->write('Questionnaire'.$id.'lastAnsweredQuestion', null);
$this->Session->write('Questionnaire'.$id.'correctAnswersNum', null);
$this->loadAdvertisement($id, 0);
$this->Session->write('Questionnaire'.$id.'previewMode', $this->params['named']['preview_mode']);
if (!$this->Session->read('Questionnaire'.$id.'previewMode'))
{
$questionnaire['Questionnaire']['participiantStartCount']++;
$this->Questionnaire->save($questionnaire);
}
}
function loadAdvertisement($questionnaire_id, $question_id)
{
//$questionnaire = array();
$questionnaire = $this->Questionnaire->read(null, $questionnaire_id);
//$question = array();
$question = $this->Questionnaire->Question->read(null, $question_id);
if (isset($question['Question']['advertisement_id']) && $question['Question']['advertisement_id'] > 0)
{
$this->set('advertisement', $this->Questionnaire->Question->Advertisement->read(null, $question['Question']['advertisement_id']));
}
else if (isset($questionnaire['Questionnaire']['advertisement_id']) && $questionnaire['Questionnaire']['advertisement_id'] > 0)
{
$this->set('advertisement', $this->Questionnaire->Question->Advertisement->read(null, $questionnaire['Questionnaire']['advertisement_id']));
}
}
I really don't understand this... it don't think it's meant to be this way.
Any help would be greatly appreciated! :)
Regards,
Stu
Check your layout for non-existent links, for example a misconfigured link to favicon.ico will cause the controller action to be triggered for a second time. Make sure favicon.ico points towards the webroot rather than the local directory, or else requests will be generated for /controller/action/favicon.ico rather than /favicon.ico - and thus trigger your action.
This can also happen with images, stylesheets and javascript includes.
To counter check the $id is an int, then check to ensure $id exists as a primary key in the database before progressing on to any functionality.
For me it was a JS issue.
Take care of wrap function with jQuery that re-execute JS in wrapped content!
You might want to try and find out where it comes from using the debug_print_backtrace() function. (http://nl.php.net/manual/en/function.debug-print-backtrace.php
Had the same problem, with a certain action randomly running 2-3 times. I tracked down two causes:
Firefox add-on Yslow was set to load automatically from it's Preferences, causing pages to reload when using F5 (not when loading the page from the browser's address bar and pressing Enter).
I had a faulty css style declaration within the options of a $html->link(); in some cases it would end up as background-image: url('');, which caused a rerun also. Setting the style for the link to background-image: none; when no image was available fixed things for me.
Hope this helps. I know this is quite an old post, but as it comes up pretty high in Google when searching for this problem, I thought it might help others by still posting.
Good luck
Jeroen den Haan
I had a problem like this last week.
Two possible reasons
Faulty routes (DO check your routes configuration)
Faulty AppController. I add loads of stuff into AppController, especially to beforeFilter() and beforeRender() so you might want to check those out also.
One more thing, are where are you setting the Questioneer.id in your Session? Perhaps that's the problem?
Yes, it occurs when there is a broken link in the web page. Each browser deals with it variously (Firefox calls it 2x). I tested it, there is no difference in CakePHP v1.3 and v2.2.1. To find out who the culprit is, add this line to the code, and then open the second generated file in you www folder:
file_put_contents("log-" . date("Hms") . ".txt", $this->params['pass'] ); // CakePHP v1.3
file_put_contents("log-" . date("Hms") . ".txt", $this->request['pass'] ); //CakePHP v2.2.1
PS: First I blame jQuery for it. But in the end it was forgotten image for AJAX loading in 3rd part script.
I had the same problem in chrome, I disabled my 'HTML Validator' add on. Which was loading the page twice
I was having a similar issue, the problem seemed to be isolated to case-insensitivity on the endpoint.
ie:
http://server/Questionnaires/loadAvertisement -vs-
http://server/questionnaires/loadavertisement
When calling the proper-cased endpoint, the method ran once -whereas the lower-cased ran twice. The problem was occurring sporadically -happening on one controller, but not on another (essentially the same logic, no additional components etc.). I couldn't confirm, but believe the fault to be of the browser -not the CakePHP itself.
My workaround was assuring that every endpoint link was proper-cased. To go even further, I added common case-variants to the Route's configuration:
app/config/routes.php
<?php
// other routes..
$instructions = ['controller'=>'Questionnaires','action'=>'loadAvertisement'];
Router::connect('/questionnaires/loadavertisement', $instructions);
Router::connect('/QUESTIONNARIES/LOADADVERTISEMENT', $instructions);
// ..etc
If you miss <something>, for example a View, Cake will trigger a missing <something> error and it will try to render its Error View. Therefore, AppController will be called twice. If you resolve the missing issue, AppController is called once.