Prevent Arrays as Field Names in codeigniter - php

I am using codeigniter 2.xx, I found out that on passing Arrays as Field Names in the html form it throws php and database errors. This is a serious vulnerability and what if an user does the same using chrome html debugging tool? It can cause security breach in the website! So, I was looking for a method to turn off the acceptance of Arrays as Field Names in codeigniter by default, but couldn't find it anywhere!
Is there any workaround with the core functionality so that form_validation, set_value() function and database drivers won't accept an array from the field name unless it is programmed for it?

Okay guys I didn't get any response for my question, So I came up with a work around. I made this small function which may get rid of input array injection.
1) Create a library file or a model. import it into the controller you wish to conduct this validation.
2) paste the following code into the model or library you just made:
/*
* Description: Checks for the array attacks in the input forms.
* #param $allowedArrayInputs, the input field name which may contain array values
* #param $method, post, get or request.
* #return boolean, in case no conflicts is detected else invoke error.
* */
public function array_inputs ($allowedArrayInputs = array (), $method = 'post') {
if ($method == 'request') {
$method_param = $_REQUEST;
}
elseif ($method == 'get') {
$method_param = $_GET;
}
else {
$method_param = $_POST;
}
foreach ($method_param as $key => $val2) {
if (is_array($val2)) {
if ($allowedArrayInputs && is_array($allowedArrayInputs)) {
if (in_array($key, array ( 'confirm_password' ))) {
continue;
}
}
show_error('User input was invalid. Try again!');
exit;
}
}
return true;
}
Hope this helps someone who is facing this similar problem!
Good day to all!

Related

Alternative to $form->isValid() for use in a Symfony DataMapper?

I am building a Symfony data transformer class called EventDataMapper. It handles two fields: A TextType field called My mapDataToForms() definition looks like this:
public function mapDataToForms($data, $forms)
{
$existingTitle = $data->getTitle();
$existingAttendees = $data->getAttendees();
$this->propertyPathMapper->mapDataToForms($data, $forms);
foreach ($forms as $index => $form) {
if ($form->getName() === 'title' && !is_null($existingTitle)) {
$form->setData($existingTitle);
}
if ($form->getName() === 'attendees' && !is_null($existingAttendees)) {
$form->setData($existingAttendees);
}
}
}
The problem is that I'm setting data before validation runs, so if I submit a form with a non-numeric string in the "attendees" field, I get an ugly TransformationFailedException ('Unable to transform value for property path "attendees": Expected a numeric'). And if I try to do a check for whether my field is valid by adding a call to $form->isValid() in the line before I call $form->setData(), I get a LogicException. ('Cannot check if an unsubmitted form is valid. Call Form::isSubmitted() before Form::isValid().')
Is there any way for my to preemptively call a validator on this specific field from within my DataMapper?
(Yes, this can be somewhat prevented with frontend logic. But I don't want to rely too much on that.)
Closing the loop on this. Here's what we did.
A colleague made a new form type corresponding to a new adapter class that wraps our two previous classes, providing a uniform set of wrapper methods for interacting with them.
We passed Symfony's validator service into our new form type using the constructor.
In that form type, we're using $builder->addEventListener() to add a callback/listener on the POST_SUBMIT event. Here's the callback:
function(FormEvent $event): void {
$adapter = $event->getData();
$form = $event->getForm();
$errors = $adapter->propagate($this->validator);
foreach ($errors as $error) {
$formError = new FormError($error->getMessage());
$targetPath = self::mapPropertyPath($error->getPropertyPath());
$target = $targetPath !== null ? $form->get($targetPath) : $form;
$target->addError($formError);
}
}
The adapter, in turn, has some logic that does various translations of data into a form that can be used in our legacy classes, followed by this:
return $validator->validate($this->legacyObject);
This works well for us. I hope it helps somebody else out too.

Effective form processing using php

I'm working on some project and I want to process requests from forms in several templates. The question is how is to invoke a proper function in the handling scrip. Although, I've been coding for a while, I still cant come up with anything better then using a variable in a hidden field:
if ($_POST['somehiddenfield'] == 1) {
some_function_1();//doesnt matter if its a function or a method
}
if ($_POST['somehiddenfield'] == 2) {
$mainclass->somemethod();
}
//goes on indefinitely
Also I want to keep everything in a single handler file, where my main class is invoked. So is there a more effective way than using if ... else?
I'd do the following:
still have a hidden field, but let it contain something like the form name
<input type="hidden" name="formName" value="post">
Then you can do something like that in the consuming php script:
<?php
// whatever class you use... this is just a simple dummy
class FormsProcessor {
public function post($params) {
echo "processing post form";
}
}
$formName = "post"; // would be $formName = filter_input(INPUT_POST, $_POST['formName'],FILTER_SANITIZE_STRING,FILTER_FLAG_STRIP_HIGH);
// BUT BE SURE TO SANITIZE THE INPUT!!!
$params = []; // dummy
$formsProcessor = new FormsProcessor();
// here's the trick.
$formsProcessor->{$formName}($params);
// to be even safer you could check first if this method_exists()
// and/or if it's in a list of allowed methods.
Be aware that there mustn't be any other methods in this class that the user shouldn't invoke. You could go around that by really compose the method name of two parts:
$methodName = $formName."Processor";
//....
$formsProcessor->{$methodName}();`
I would keep a key=>value array hardcoded with all the possible options. Pass the hidden input field, check if there are any intersections between your post values and the keys of the hardcoded options and call any matching values as functions.
$map = [
'yourHiddenField' => 'myFunctionName',
'anotherHiddenField' => 'myOtherFunctionName',
'yourOtherHiddenField' => 'yetAnotherfunctionName',
];
$intersection = array_intersect(array_keys($map), array_keys($_POST));
foreach ($intersection as $key) {
$this->{$map[$key])();
}
This code hasn't been tested.
EDIT:
Be careful with allowing ANY input to be ran without predefining which functions you should allow to be ran.
Example of how dangerous it could be even with sanitisation:
class Test {
public $i = 1;
function __construct(){
$this->i++;
}
}
$formVariable = '__construct';
$t = new Test();
$t->{$formVariable}();
echo $t->i;

API Request $_POST returning empty array

I'm using Zurmo and trying to create a new account using REST API. I followed this documentation precisely: http://zurmo.org/wiki/rest-api-specification-accounts to pass the required parameters as json array.
This is my php code:
public function actionCreateOrUpdate()
{
$params=$_POST;
$modelClassName=$this->getModelName();
foreach ($params as $param)
{
if (!isset($param))
{
$message = Zurmo::t('ZurmoModule', 'Please provide data.');
throw new ApiException($message);
}
$r=$this->GetParam($param);
$res= array('status' => 'SUCCESS', 'data' => array($r));
print_r(json_encode($res,true));
}
}
function GetParam ($param){
$modelClassName=$this->getModelName();
if (isset($param['mobile_id'] ) && !$param['mobile_id']=='' &&!$param['mobile_id']==null)
{ $id=$param['mobile_id'];
$params=array();
foreach ($param as $k => $v) {
if(!($k=='mobile_id')) {
$params[$k] = $v;}
}
if ($params=null){$message = Zurmo::t('ZurmoModule', 'Please provide data.');
throw new ApiException($message);}
$tableName = $modelClassName::getTableName();
$beans = ZurmoRedBean::find($tableName, "mobile_id = '$id'");
if (count($beans) > 0)
{
$result = $this->processUpdate($id, $params);
}else{
$result = $this->processCreate($params,$id);
}
}
return $result;
}
The problem is that the $_POST method is returning an empty array. While debugging I tried to use print_r($_POST) and it also returned an empty array. I also tried to pass parameters as plain text and got the same result. I tried $_GET method and it worked. I think the problem is in the $_POST method, maybe I need to change something in my .php files. Any ideas please?
You should first hit the api with static data, to check if it works fine, then try to integrate php within that static data. You will need to read the documentation for which action accepts which format, and which method is supported(GET OR POST). Then try die(); , before sending if the array formed is as per the documentation.
I had similar issue when creating Account using REST API from java client. The problem was I did not send the proper POST request.
Another symptom also was on server side print_r(file_get_contents("php://input"),true); php code returned the correct request data.
Specifically the root cause was:
The Content-Type HTTP header was not "application/x-www-form-urlencoded"
The value field value in POST request was not properly encoded ( I used java.net.URLEncoder.encode method to overcome this)
After fixing these it worked.

How do I pass $_FILE and $_POST data into a form?

So far this is what I know to be the way to pass the data from a post into the form.
$form->setData( $this->getRequest()->getPost() );
I thought that this might work
$form
->setData( $this->getRequest()->getPost() )
->setData( $this->getRequest()->getFiles() );
Which it does not. Looking through the framework source I confirmed that it shouldn't. So I was thinking about merging the file data into post data. Surely this cannot be the desired solution? It's not as if getPost() and getFiles() return easily mergeable arrays, they return Parameter objects.
Please note this is Zend Framework 2 specific.
Have you tried getFileInfo knowing now or paying mind to the fact that your using Zend. Typically on a per file basis $_FILE is an array based on the information of the file being uploaded. Filename, extension, etc.. Zends getFileInfo outputs that information in a similar fashion. Though I haven't played with it in sometime, its worth looking into
Example concept (more for multiple file uploads I know, but works with one, good concept to leave in tact just incase you wanna add a second or more files down the road)
$uploads = new Zend_File_Transfer_Adapter_Http();
$files = $uploads->getFileInfo();
foreach($files as $file => $fileInfo) {
if ($uploads->isUploaded($file)) {
if ($uploads->isValid($file)) {
if ($uploads->receive($file)) {
$info = $uploads->getFileInfo($file);
$tmp = $info[$file]['tmp_name'];
$data = file_get_contents($tmp);
// here $tmp is the location of the uploaded file on the server
// var_dump($info); to see all the fields you can use
}
}
}
}
After attempting to use Zend's file transfer adapter I went with a workaround in the controller. I think that the setData() in the form class should merge the items into the data instead of replacing them. (IMHO)
protected function getPostedData()
{
if ( is_null($this->postedData) )
{
$this->postedData = array_merge(
(array) $this->getRequest()->getPost(),
(array) $this->getRequest()->getFiles()
);
}
return $this->postedData;
}
I am using array_merge:
$form = $this->getForm('my_form');
$request = $this->getRequest();
if($request->isPost())
{
$file = $this->params()->fromFiles('name_of_file');
$form->setData(array_merge(
$request->getPost()->toArray(),
array('arquivo' => $file['name'])
));
if ($form->isValid()) {
// now i can validate the form field
I use variable variables like this article explains to create variables and then echo them as the values for each form entry.
example:
// create array of GET/POST variables then convert each variable to a local variable
$fields = array_keys($_REQUEST);
foreach ($fields as $field) {
$$field = $_REQUEST[$field];
}

How to get validation errors in an array?

I am developing an REST API using Codeigniter.
I need to have all error messages from Form validation in array format so that
I can easily respond in either JSON or XML.
Right now Codeigniter is delivering error messages with <p> as delimiters (see below)
but that is not good for a REST based API.
<p>There was an error with this item</p>
How can I get errors in an array?
Thankful for all input!
The form validation library stores errors in an array and loops through them to generate the error string. They are stored in a private variable called $_error_array. You could extend the library with a simple method that returns the error array.
class MY_Form_validation extends CI_Form_validation
{
function get_error_array()
{
return $this->_error_array;
}
}
I assume you are familiar with extending core CI libraries, but this extension of the form validation library will give you a method to return the errors as an array with the name attribute's value as the key and the message as the value. I tested it out on one of my projects and it worked fine.
You can transform it easily:
/**
* #param $errors string
* #return array
*/
function transformErrorsToArray ($errors) {
$errors = explode('</p>', $errors);
foreach ($errors as $index => $error) {
$error = str_replace('<p>', '', $error);
$error = trim($error);
// ... more cleaning up if necessary
$errors[$index] = $error
}
return $errors;
}

Categories