I have an edit made with blade to edit a resource, like this:
{{Form::model( $post ,['action'=> ['PostController#update', 'id' => $post->id], 'method' => 'post'])}}
Which generates a form with action
http://example.com/posts/edit/123
And my fields, having text and hidden inputs
Seeing this url, it's very easy for a bad-intentioned user to update other posts.
How can I protect the route to make it fail if the id is manipulated with the inspector? Is there any built-in wat to tokenize the id to make sure it matches? Can this also de applied to all the hidden inputs?
Thanks
EDIT:
An example on my hidden fields usage:
My posts are generally questions and answers, when an user tries to add an answer to a question, I set question_id as a hidden field, and I want to check it is not manipulated.
Limonte's answer is correct to secure the ability to edit other peoples posts - and you should always do that. To answer the second half of your question:
I set question_id as a hidden field, and I want to check it is not manipulated.
The problem is that you can never trust the data supplied by a client to your system. You must always assume it has been tampered with.
One option to help minimize the risk is you can use the encryption service by Laravel to do this:
{{ Form::hidden('question_id', Crypt::encrypt($question_id)) }}
Then in your controller
$question_id = Crypt::decrypt(Input::get('question_id'));
Just make sure you've set a random application encryption key in your app.php config file
To protect route you should check permission in PostController#update.
In the method beginning check if user can edit given post:
public function update($postId)
{
$post = Post::findOrFail($postId);
if ($post->user_id !== Auth::id()) {
abort(403, 'Unauthorized action.');
}
// validate, update record, etc.
}
Related
Going to try my best to explain this...
In my app I have the need to display the validation errors on a form when the user loads the form initially. In short, they've entered data and saved it, but now the data has been checked and we've detect errors they need to correct before they can fully submit the form. (It's multi step form that can be filled out over multiple sessions...think big.)
Previously I was doing something like:
THIS DOESN'T WORK IN SYMFONY >=2.8.10 See this answer
$entity // passed in as param on action method
$form = $this->createForm(..., $entity);
$csrfToken = 'random_string'; // retrieved from FormConfigInterface
// perform the submit but don't clear missing
$form->submit(['_token' => $csrfToken], false);
This was working, but seems to have broken in Symfony 2.8.10+, but works in 2.8.9. In 2.8.10+ there are no validation errors (the form is considered valid).
I'm able to retrieve the validation errors in a ConstraintViolationListInterface, but I can't find a way to "merge" that with the form (which I think would be the prefered way). Since I couldn't, I tried the above which "fake" submits the form...which seems like a bad idea.
Is there a better/proper way?
(Note: the form is much more complicated and includes validation groups...but I'm not concerned about that or the error in 2.8.10+ at this point.)
I am working on a CMS backend,and I use Codeigniter to help with the development.
So, I am working on a user table. For example, I allow the backend admin to insert, update the user info.
First there is a table of the user, for each row there is an "edit" button. After clicking on the "edit" button, there is a form for that particular user.
e.g.
UserName: Mr. ABC
Email: abc#a.com
Password: 1234
Since I need to ensure the username is unique and email is unique, I need to use isUnique validation
However, the problem is, how to handle the case, "only the user modify the data, then add the is Unique rule"? Because if I don't change the username, then I will pass the original name to check , and it can not pass the is Unique check , thanks
$this->form_validation->set_rules('name', 'Username', 'trim|required|min_length[4]|is_unique[admin.username]');
You're sending the userID anyway to the server in order to update, You can run a query to check if that username/userID combo exists. if it does, that mean this user didn't change. if it doesn't, you need to check further with is_unique.
That's probably best implemented in a callback if you insist of using form_validation.
basically in your controller you'll two functions
function form_grabber()
{
//get your form and stuff. run this line :
$this->form_validation->set_rules('name', 'Username', 'call_back_isUserNameNotChanged[userID]');
//assuming userID comes from the form aswell.
}
function isUserNameNotChanged($username,$userID)
{
//query DB, return true if match exists or false if it doesn't
}
I don't use codeigniter much, so I'm not sure the exact code to go about this, but how about something like this:
$current_name = // current name in db
if ($this->input->post('name') != $current_name) {
// Name has been changed. Do validation.
}
...
Basically, just check if the posted name is different than what is already in the db. If so, run your validation and do your update. If it's the same, just ignore it.
On my web page I have Zend_Form with CSRF hash. It submits to the same page and it is used to update user's data (name, surname, birthdate and so on...). I would like to reinitialize CSRF hash after every valid post submission. How I could do it?
Now when I first time submit 'user data' form I get proper behavior (user data gets updated). But if I submit again (right after first, proper submit) to change another form field I get error saying:
The two given tokens do not match
Is there anyway to reinitialize hash properly?
Your problem comes from this function in Zend_Form_Element_Hash the $session->setExpirationHops is set to 1 hop, so if you try to resubmit the same form it will always fail. This is by design and is the root of the security you're seeking.
However you can change this behavior, simply extend Zend_Form_Element_Hash and override this method to set the expirationHops to a value you prefer (you can also set the session options manually at any time if you prefer).
public function initCsrfToken()
{
$session = $this->getSession();
$session->setExpirationHops(1, null, true);
$session->setExpirationSeconds($this->getTimeout());
$session->hash = $this->getHash();
}
It goes without saying that it would be in the interest of security to perform a full refresh and repopulate the form to perform any edits. This should reset the hash.
My problem came from tampering with Zend_Form_Element_Hash init methods, I had this:
$_csrf = new Zend_Form_Element_Hash($this->_csrfName);
$_csrf->setSalt(md5($name));
$_csrf->setAttrib('id', '');
$_csrf->initCsrfToken();
The last line should never be there. When I removed it, everything started to act correctly.
#RockyFord: The initCsrfToken() function was place I was looking at the beginning, but
for me (I mean my intuition) it just couldn't be that. So I just debugged, debugged, debugged,
and at last commenting out 4th line was proper solution. Sorry for holding off reply, I totally forgot.
I would like to do something roughly analogous (but not exactly identical) to the following: I want to create a Person content type, which has an SSN field. I would like to store the SSN field as an integer, but allow the user to input the number as 123-45-6789. This means that before validation triggers, stating that "123-45-6789" is invalid input, I would like to remove the dashes and treat this as an integer.
I've tried to use both a #value_callback function, as well as a non-default validation function. The problem then is that although I can force the value to be validated, the unchanged value is what is passed to the db for insertion, which fails. In example, this means that although I can force "123-45-6789" to be recognized by Drupal as "123456789", the database is still being passed "123-45-6789", which of course fails.
The one obvious solution would be altering this via client side javascript, before the value is even submitted to the webserver. I would strongly prefer to avoid this route.
Apologies if I've misunderstood but you should just be able to do something like this:
function my_validation_handler(&$form, &$form_state) {
if (passes_ssn_validation($form_state['values']['SSN'])) {
// Changing the value in $form_state here will carry on over to the submission function
$form_state['values']['SSN'] = convert_to_db_format($form_state['values']['SSN']);
}
else {
form_set_error('SSN', 'The SSN was invalid');
}
}
Then you'd attach that validation function using $form['#validate'][] = 'my_validation_handler' in either your form build or form_alter function.
Hope that helps
you should use hook_node_presave(). It allows you to change the values of different fields before they are inserted to the database. Here's the official documentation:
http://api.drupal.org/api/drupal/modules--node--node.api.php/function/hook_node_presave/7
Hope this can help :)
On my website, I have user accounts that are configurable with forms that allow users to update everything from first and last names to privacy settings. I use the following function to update the database with that input. (Note that the following code uses WordPress-specific features.)
function update_account() {
global $current_user; get_currentuserinfo();
require_once( ABSPATH . WPINC . '/registration.php' );
$uid = $current_user->ID;
// First Name
if(isset($_POST['first_name']) && $_POST['first_name'] <> $current_user->first_name) {
wp_update_user( array(
'ID' => $uid, 'first_name' => esc_attr($_POST['first_name'])
));
}
// ...and so on 43 more times...
}
This feels like the wrong way to process forms. This also looks like it will negatively impact server performance when there are multiple users and frequent updates, given that the if-then-else conditions for every field, even fields not on a particular page, force checking each field for input.
Moreover, since form data can be expected to remain relatively constant, I added the <> operator to prevent the function from updating fields where there has not been any change, but I suspect this also means that every field is still evaluated for change. To make matters worse, adding new fields -- there are already 44 fields in total -- is an unwieldy process.
What's a better way to process form data?
Keep an array of the fields you will be processing with this code, and iterate over it. This works if all your attributes are strings, for example. If you have different data types such as boolean flags to handle differently from the strings, you may wish to group them into their own array.
// All the fields you wish to process are in this array
$fields = array('first_name', 'last_name', 'others',...'others99');
// Loop over the array and process each field with the same block
foreach ($fields as $field) {
if(isset($_POST[$field]) && $_POST[$field] != $current_user->{$field}) {
wp_update_user( array(
'ID' => $uid, $field => esc_attr($_POST[$field])
));
}
}
There's a lot of things missing with your implementation. I don't know what kinds of data you're allowing the user to manipulate but most usually have some kind of requirements to be acceptable. Like not having certain characters, not being blank, etc. I don't see any validation occurring, so how do you handle values that might be undesirable? And what happens when you receive bad data? How do you inform the user of the bad data and prompt them to correct it?
If we abstract the situation a bit we can come up with generalizations and implement an appropriate solution.
Basically form fields [can] have a default value, a user specified value [on form review], validation requirements and validation errors [with messages]. A form is a collection of fields that upon form submit needs to be validated and if invalid, re-displayed to the user with instructive corrective prompts.
If we create a form class that encapsulates the above logic we can instantiate and use it to pass around our controller/views. Oops, I was just assuming you were using an Model/View/Controller type framework, and I'm not really familiar with wordPress so I don't know if that is exactly applicable. But the principle still applies. On the page where you both display or process the form, here's some pseudo logic how how it might look.
function update_account()
{
// initialize a new form class
$form = new UserAccountInfoForm();
// give the form to your view for rendering
$this->view->form = $form;
// check if form was posted [however your framework provides this check]
if(!Is_Post())
return $this->render('accountform.phtml');
// check if posted form data validates
if(!$form->isValid($_POST))
{
// if the form didn't validate re-display the form
// the view takes care of displaying errors, with the help of its
// copy of the $form object
return $this->render('accountform.phtml');
}
// form validated, so we can use the supplied values and update the db
$values = $form->getValues(); // returns an array of ['fieldname'=>'value']
// escape the values of the array
EscapeArrayValues($values);
// update db
wp_update_user($values);
// inform the user of successful update via flash message
$this->flashMessage('Successfully updated profile');
// go back to main profile page
$this->redirect('/profile');
That makes your controller relatively clean an easy to work with. The view gets some love and care to, utilizing the $form value to display the form correctly. Technically, you can implement a method in the form class to give you the form html, but for simplicity I'm just going to assume your form html is manually coded in accountform.phtml and it just uses $form to get field info
<form action='post'>
<label>first name</label> <input class='<?=$this->form->getElement('first_name')->hasError() ? "invalid":""?>' type='text' name='first_name' value="<?=$this->form->getElement('first_name')->getValue()"/> <span class='errmsg'><?=$this->form->getElement('first_name')->getError()?></span><br/>
<label>last name</label> <input class='<?=$this->form->getElement('last_name')->hasError() ? "invalid":""?>' type='text' name='last_name' value="<?=$this->form->getElement('last_name')->getValue()"/> <span class='errmsg'><?=$this->form->getElement('last_name')->getError()?></span><br/>
<label>other</label> <input class='<?=$this->form->getElement('other')->hasError() ? "invalid":""?>' type='text' name='other' value="<?=$this->form->getElement('other')->getValue()"/> <span class='errmsg'><?=$this->form->getElement('other')->getError()?></span><br/>
<input type='submit' value='submit'/>
</form>
Here the pseudo code relies on the form class method "getElement" which returns the field class instance for the specified field name (which would be created an initialized in the constructor of your form class). Then on the field class methods "hasError" and "getError" to check if the field validated correctly. If the form has not be submitted yet, then these return false and blank, but if the form was posted and invalid, then they will have been set appropriately in the validate method when it was called. Also "getValue" would return either the value supplied by the user when the form was submitted, or if the form has not been submitted, the default value as specified when the field class was instantiated and initialized.
Obviously this pseudo code is relying on a lot of magic that you'd have to implement if you roll your own solution--and it's certainly doable. However, at this point I'll direct you to the Zend Framework Zend_Form components. You can use zend framework components by themselves without having to utilize the entire framework and application structure too. You might also find similar form component solutions from other frameworks but I wouldn't know about those (we are a Zend Framework shop at my work place).
Hopefully this hasn't been too complicated, and you know where to go from here. Of course just ask if you need any clarification.