Edit in Place Update Script Security - php

I'm using an Edit in Place jquery plugin which needs to post the data to a script that will do the actual database update.
The URL to this update script is easily viewable in the html source as well as with Firebug, so I need to add some sort of authentication check before the update is processed. This is of course so the user can't just pass in any old userid / field / value they want and mess with other people's records.
I was initially passing their username and password in as well, but this isn't ideal as it's in a GET request so it's all in the URL. The site itself is SSL at least, but still not a best practice by any stretch.
What's the best way to authenticate this type of update?
FWIW, the update script is in PHP, and the Edit in Place plugin is: jeditable.
Edit: To clarify: The actual data payload is POSTed to the script, but the edit in place plugin has no explicit method for authentication, so I was passing the authentication as part of the URL to the update script, which was then taking those variables via GET and using them to check.
Edit 2: Yes, I can access the session info from the update script, so I've decided to just pull the previously saved User ID and using that in the db update statement. That would appear to be the most secure method.

I think you'd be best off switching the script to a POST method as most edit-in-place uses will be too big to use GET practically. You should never use the SessionId or the password as a URL parameter and I wouldn't use the username for anything but viewing a public profile. If your AJAX URL is a PHP file, I'm fairly certain it should be able to access the session without needing to pass it in either a GET or POST array. As an additional note, make sure that you validate and sanitize all information before updating the database.

Update (based on comment and question updates): You could pass the username/password as submitdata option to Jeditable, like so:
$(".edit_area")
.editable("http://www.example.com/save.php", {
submitdata: { userid:'johnsmith', passwd:'god' }
// ..other settings, etc.
});
Quick and dirty solution - dirty because it exposes the user's privates in plaintext (via View Source).
Since you do have access to the userid/sessionid on the server, using that by far the sanest option.
Hmm... since you say Jeditable uses GET, I can only assume you're using the loadurl option (since the Jeditable uses $.post() to save the changes, and $.post() always uses POST).
So, have you tried switching Jeditable's loadtype setting to "POST", and send the username/password like before?
$(".edit_area")
.editable("http://www.example.com/save.php", {
loadurl: 'http://www.example.com/load.php',
loadtype: 'POST'
// ..other settings, etc.
});
That sounds like the quick and dirty solution - granted you don't have any standard user/session handling on the server end.

Isn't the site still vulnerable to Cross-Site Request Forgery if you simply look up the user in the session?
You can POST all needed information if you include a salted hash field calculated from values of non-editable POST fields. If you include a timestamp, you can prevent script replay as well.
Example:
$(".edit_area")
.editable("http://www.example.com/save.php", {
submitdata: {
userid: 'johnsmith',
pageid: '123', // or other value unique to the page
timestamp: '1324354657', // time when page loaded
hash: '0bee89b07a248e27c83fc3d5951213c1' }
// ..other settings, etc.
});
The hash could be e.g. an MD5 of 'johnsmith$123$1324354657$' + $secret_salt. Check that it matches before saving. Optionally reject if too little or too much time has passed.
The ditch-pycrypto branch of django-magicforms implements this as a re-usable Form base class for Django. It's not directly applicable to AJAX requests, but the documentation and unit tests should provide a good basis for other implementations.

To pass the information you should use the session id in the actual GET string. This way the php script can connect to the session, validate the user, and see if the user has the rights to edit what they've posted. Then if they have the rights, proceed, or else return an error message.
I believe you can, in javascript, get the session id so it needn't be passed overtly.

Related

GET vs POST when requesting data on button click?

I'm using Laravel 5.3.
Essentially, when a user clicks a button on the screen, I need to get data from the database (using AJAX), and then display that data on the screen.
However, I'm not sure if I should be using a GET or POST request? I've only ever used GET requests for routing when the user wants to get to a specific page, like a GET request for /index or /profile.
Which should I use?
There is a difference between GET & POST method in Laravel
GET is used when we want to get some data from the server and we do not send any parameter in request. And the security threat is not a concern, like you are opening a page on browser
POST is used when we want to send some parameter to the server and based on that parameter some processing is done. In laravel it is mandatory to include CSRF token wit the request for security concern.
So choose as per your requirement.
easy! Use GET when you're to getting data, and POST when you're posting data.
There are even more of these request methods (or verbs, if you like). For example a PUT request to edit data, DELETE request to delete data etc. However, these aren't supported in most browsers yet, but i know laravel has a clever workaround so you can use them anyway. check this links:
https://laravel.com/docs/5.3/routing
This is actually something of your own choosing. If the operation is a sensitive one you might consider using POST so that you can have protection over CROSS-SITE REQUEST FORGERY from attackers but if not so you can simply use GET
If you only want save data in database(no return data) so you should use POST. And whenever you want to get data from database so you should use GET.
Ex - If you want to insert a new user information in database so here you use GET method and if you want to edit existing user information and return updated information so you will use GET method.

Avoiding or alternative to use $_GET

I am currently using to process results via $_GET variable from querystring (URL) http://example.com?id=c02df and to update etc, as you know user can see what id being sent to the next page via url (from above example id is c02df) and can change the id from the URL himself. Kindly let me know is there any alternative way to exchange the ids between pages to process the functionality accordingly which user can't see or mess with?
The best solution would be to use $_SESSION, if you don't want to allow users to tamper with the request.
If you provide more info on your code, I can provide more info on the solution.
EDIT: Here's a "workaround" for using both $_SESSION and $_GET (still without seeing your code at all):
You set $_SESSION['allowed_gets'][] = 'c02df';
Then, when the user is making the request, you check whether they are allowed to do that request:
if (!in_array($_GET['id'], $_SESSION['allowed_gets'])){ die(); }
If you have content users shouldn't be able to see, you should have a login system.
If you just want unguessable URLs, avoid sequential IDs for the $_GET parameter. You could, for example, generate a salted MD5/SHA1 hash of the ID, store it in the database alongside the ID, and use that in the URL.

Data from the exact form

I have been googling a lot but i am still without an answer so i decided to ask this question here:
Is there a way in PHP how to check that the data i am receiving in some script are from the specific form on the page? I am asking because everyone can see the name of the script i am using for saving the data to my database, so if somebody is able to find out the whole URL, he is also able to send some fake data to the script and i need a condition, that the saving process is triggered only when the data comes from the proper form on my page.
I am using jQuery to call AJAX function, so basically if i click on the button "send", the $.POST() method is triggered to call the script for saving the data.
Thanks,
Tomas
Use tokens to check if request is valid
You could always add some kind of security token when submitting data:
Tokens can be easily extended for many different uses and covers wide area when it comes to checking if some request is valid, for example you could let your non critical forms open for public, ask users to get their secret keys from some page (forcing them to open that page) and then use those keys to identify them when submitting data.
Of course all of this can be completely transparent to user as you could give keys from front page via cookies (or session cookies, it does not matter here, no more or less security as server keys should change after use and invalidate within specified time or when user's identity changes).In this example of use, only user that opened front page can submit data to server.
Another case is when cookies is given away at same page which contains form for submitting data to server. Every user that open page will have their keys to submit data straight away, however if someone tries to make request from outside it will fail.
See OWASP Cross Site Request Forgery
and codinghorror.com Blog CSRF and You
Only with AJAX?
Here is my answer to another question, this answer covers different methods for inserting additional data to ajax request: Liftweb: create a form that can be submitted both traditionally and with AJAX (take a closer look at
$.ajax({
...
data: /* here */
...
Currently I am using tokens this way:
Form used to submit
This hidden input can be added to form, it is not requirement as you can use methods described earlier at another answer.
<input type="hidden" name="formid" value="<?php echo generateFormId(); ?>" />
Function generateFormId()
Simply generate random string and save it to session storage
function generateFormId() {
// Insert some random string: base64_encode is not really needed here
$_SESSION['FORM_ID'] = 'FormID'.base64_encode( uniqid() );
// If you want longer random string mixed with some other method just add them:
//$_SESSION['FORM_ID'] = 'FormID'.base64_encode( crypt(uniqid()).uniqid('',true) );
return $_SESSION['FORM_ID'];
}
Processing submitted form data
if (!isset($_SESSION['FORM_ID']) || $_SESSION['FORM_ID'] != $_POST['formid']) {
// You can use these if you want to redirect user back to form, preserving values:
//$_SESSION['RELOAD_POST'] = $_POST;
//$_SESSION['RELOAD_ID'] = uniqid('re');
echo 'Form expired, cannot submit values.';
//echo 'Go back and try again';
exit(1); // <== Stop processing in case of error.
}
If you need to check which form is submitting data
Then you could just add prefix when generating id's and check for that prefix when processing form data.
This is case when one php script deals with many different forms.
Remember that only ultimate answer to prevent evil users is to pull off all wires from your server...
This is an interesting topic, but you are missing an important point: A spam robot / bad user could also bomb your database by using that specific form page (!).
So, the question is not how to check if the request comes from that page or not, the question is how to check if he's a regular user or a robot/spammer/bot.
Do it with a captcha, like http://www.recaptcha.net
In case i slightly misunderstood the question: If you want to be sure that the request comes from a "real" user you will have to work with a login system / user system and check for users id / password (via db or sessions) every time you want to do a db request.
You can verify that the page is being requested via AJAX with checking against this:
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest'
You could also check the HTTP_REFERER.
But it sounds like you're trying to protect a page that processes vulnerable data. This requires more than just the two things above. I'd recommend googling 'CSRF Forgery' to get more information on this.
These are something that you should take a look at.
Capthcas.
Referer check.
Use POST than GET. [Still Curl can automate it.]

Hiding actual link in hyperlink

I have
echo <a href=\"javascript:;\" onClick=\"window.open('". $link ."','no','scrollbars=yes,width=550,height=400')\" >View report</a>
$link contains sensitive information, so I'm wondering if there is a simple way to prevent this link showing up explicitly when you "view source code" on the browser. Any alternative to href would be fine. I just need to give the user an option to click and see his processing result after he submits some data. I would like to avoid having auto popups as soon as the processing is submitted.
UPDATE: so the $link is a GET URL that includes a user ID and password.. It's internal right now so it's fine, but I'm thinking of putting this on our online server in the future. I'm very much a novice with PHP, so this is probably not in the near future as I don't know much about security features that need to be implemented for a live site on the Internet. Right now, it seems that utilizing a database would be the best way to go. Correct me if I'm wrong, please, and thanks for all of the support!
If the user has to navigate to the link, there is no way to actually hide the information. You should rethink how your process works so sensitive information is not displayed in the link.
Perhaps you can store the information in a database table and the link would just use the id of the row that has the information.
Simply put: No. If you send me to a URL, I will be able to see it using some sort of tool. Wireshark, Fiddler, etc. Consider using a different link structure.
If the user already owns a session, this is an option:
If you render a page and need to protect this given sample secret URL
http://www.MyHost.com/?what?secret&id=23232
save the URL in the user's session and associate a hash value with the secret URL.
Instead of sending the URL to the result HTML-page, insert another URL, e.g.
http://www.MyHost.com/?continueWith=<hashValue>
If this URL gets called, check the user's session and retrieve and delete the secret URL. Then continue to evaluate, as if the user had called the secret URL.
This way, no parameter of the original secret URL ever reaches the user's browser.
To refine the schema, attach a lifetime to the URL saved in the session. If a request comes later as the end of life, return an error.
If you protect all URL in such a way, users won't be able to call arbitrary URLs, since all acceptable URLs are those inside their sessions. Thus, a user will even not be able to change parameters of less secret URLs.
How is $link generated in the first place? If it is sensitive, this implies that the user has already been authenticated somehow. Thus, the information in $link can be stored in the session where it's safe
Save all the information in your PHP session (or preferably the session system your PHP framework uses) and then just send some kind of non-db-associated identifier in the link so that the code knows what you want to do next.
For example you could have a link to "http://www.yourdomain.com/sec/special_action/4" with "sec" meaning secure, "special_action" being the name of the action to take, and "4" being the action id reference.
So lets say you have to have it associated to their social security number. Then you would in your back end use a salted hash to encrypt the SSN and save it to the session data. You then append it to the end of your session array and get an array count. If it returns 5 then you know that the encrypted SSN is saved in index 4 (since PHP uses 0 based indexing). So you send along that index as part of the link to confuse things even more. Heck you can even salt and hash the index if you want.
The user clicks on the link, the code finds the index, grabs the encrypted content, decrypts it, then uses it. Easy and secure.

Zend Framework - Secure way to pass parameter from view to controller

I used Zend Framework for near 3 month and I'm searching for a method to pass parameters from the view to the controller in a secure way. I prefer to pass the parameters like $_POST method, but I don't want to use forms.
Is there any method to use in ZF? I only know the url() method but I don't know if this method is works well to passing important data to the controller.
HTTP is a stateless protocol and you can basically choose from four solutions to preserve information between requests (as this is, I think, what you are trying to do, isn't it):
Query string
Hidden elements in forms
Cookie
Session
Session would be the safest. In ZF you have Zend_Session component to help you with session managment.
As far as sending POSTs without form it is rather difficult. Have a look at: Zend Framework: How to POST data to some external page (e.g. external payment gate) without using form?. However, if you only want to sent POST data than you could do it in PHP using cURL.
I think you might be looking for Session variables.
You want to send something that can't be seen from URL into the next request, right? Session is ideal for that.
Update:
I read your question as:
"There is this variable in page, that somehow changes. I want the user to send it to the server, but it should not appear in the URL. But without using forms."
There is no way to initiate POST request (like let the user post a password or sth like that) from browser without forms or javascript axaj call. To send some data via POST you can use Zend_Http_Client(), but that's done server-side and you still need to make a GET request first.
May I ask you how would you implement it using GET? That would help us to understand what exactly you'd like to do.
And the last idea:
I'm searching for a method to pass
parameters from the view to the
controller in a secure way
JUST BEACUSE IT'S NOT IN URL IT'S NOT SECURE! :)
I think what you can use is a digest key
The method has nothing to do with security GET, POST, Cookies or Session a person on the client side can manipulate the params.
Example:
mywebsite.com/widget.php?id=1234&action=delete
A person can change the GET param id and delete whatever they want. Obviously, your controller should implement Auth and perhaps an ACL, for authentication and authorisation, but this still wont prevent URL tampering. For example, what's the stop Bob logging in and altering a URL to edit John's widget.
you generate a digest key by concating the params into a string:
1234+password = "1234password" then generate the MD5 of the result = d5b1ee4b463dc7db3b0eaaa0ea2cb5b4
pass this along the url.
mywebsite.com/widget.php?id=1234&action=delete&mac=d5b1ee4b463dc7db3b0eaaa0ea2cb5b4
inside widget.php you can use the same formula to calculate the digest key and check to see if it matches. If they attempt to change the id to say 4567 the MD5 result would be 09fef3620249f28ae64adc23bded949, so you can deny the request.
If you have more than 1 param on your URI, string them together, add the password and generate an MD5 or SHA1.

Categories