Say I have one form that changes its content (fields and options) based on the user's current state in a multi-state process. Say that it always leads to the same action, which means the action needs to figure out what event occurred and on which entity.
<form action='/somecontroller/someaction' method='post'></form>
What is the most common way of transferring this sensitive data to the controller? I'm reluctant to even suggest hidden fields, as those can be changed by anyone. Two way encryption of some sort which is then decrypted in the action and used to determine the rest, server-side? Perhaps serialize sensitive info, encrypt it, and put it in a single hidden field on the client side of the form, then decrypt and unserialize in the controller?
<?php
$hiddenData = unserialize($this->decrypt($_POST['hiddenData'], SALT));
unset($_POST['hiddenData']);
$data = array_merge($hiddenData, $_POST);
...
Basically - how do I send some data with a form securely without exposing it to outside alterations, that is, without making sure something can go wrong if it is altered? Is there some kind of best practice regarding this?
You never send that data to the client at all.
Store it server-side within the session management capability (for PHP, you can access that using the $_SESSION variable) and only send the session token (long random number, PHP has routines for generating/maintaining good session identifiers as well) to the client (typically done in the form of a cookie). For keeping track of data in a multi-step process (including the state that the user is in), you never want to expose that to the client.
Interesting question. What I would do is a combination of the following (if sessions are not a solution for you):
employ a AES_256 / modifyed AES_256 crypt/decrypt on a serialized representation
make a MD5 + SALT (or similar) hash of the variables that you could compare with a stored hash to determine if any manipulation took place
use something like the user's IP as SALT to generate the hashes or for the crypt functions, thus if a user's IP should change you'll know that (beware: an IP address might change under some circumstances)
Related
I'm developing a mobile app where I wish to implement a simple user authentication, and as i'm new to hybrid mobile developing with its front-end restrictions, i'm quite terrified by the idea of holding any back-end related data in the form of localStorage / sessionStorage / ngCookies (as I have seen some people do).
So my question is, how secured can these methods be of holding such data? Do app users have the ability to access and modify let's say... the sessionStorage, from the application itself? Cause it sure is easy on the web.
Sorry if it's a stupid question, I just don't wish to take any security risks when it comes to this. Much thanks for any help!
TLDR; Cookies and storages should be assumed to be stored in plain text and accessible by client side script that comes from the same domain. Assume the worst; anything can go wrong with your script due to bugs or XSS attacks. If the data will be used both by the client and the server back again, most definetly sign it. If the data is only relevant to server side code, sign and encrypt it. If the data is only for printing stuff to screen or DOM evaluation, leave it plain text.
Let's be clear about what cookies, session storages and local storages are before beginning to an example implementation.
Cookies are data created by server or client, stored in plain text by browsers, that is sent on every http request to the server if the path matches. They are good for storing authentication tokens, meta data regarding tracking, analytic, website interface preferences, shopping carts and many other.
Storages are - as indicated by their name - storage space assigned to your domain and only scripts from your domain and XSS attacks can alter it. This means, if you use them for the purposes I listed above, you have to append data stored in them to your HTTP requests by hand. If your site depends on many async HTTP calls, it is not wrong to use storages like cookies. Otherwise they are useful for caching things like template data and site resources.
If you use cookies for storing user related data that is needed for your server, those kind of cookies can be encrypted on server side before sent to the client. You can still access such cookies with ngCookies but the only harm that can be done is that some injected code may invalidate them. If somehow your encryption scheme is revealed and they become readable to an attacker, you can invalidate modifications to them by appending a signature (created with a secure hash algorithm) on every store and check your signature on every retrieval. Let's illustrate that process.
$userState = json_encode($yourStateObjectOrAnAssociativeArray);
$sign = my_hash($userState);
$encryptedState = encrypt($userState);
setcookie("user" , $encryptedState);
setcookie("sign" , $sign);
Here we have encoded our state as JSON, then first generated a hash. You can use some SHA1, SHA256 and such with a stored key you choose to come up with a my_hash() function. Below is an example that is correct but you shouldn't use it since even I shouldn't know your algorithm.
// hash() is reserved so use something else
function my_hash($object) {
return sha1(md5($object) . "some giberish key that is stored as config data or in a db" . sha1($object))
}
Note that my_hash() is not extremely secure since it uses a static string as key and a generation structure that is not complex. In the end, it is sha1() of some randomly structured string. It is sufficient for a cookie sign though.
You can write your own encrypt() / decrypt() pair by using AES encryption or some equally secure algorithm of your choice. Here is an example from this site.
Now our cookie is stored and ready to be sent on the next request. Below is how you decrypt and validate your cookie from the example above.
$sign = $_COOKIE["sign"];
$encryptedState = $_COOKIE["user"];
$userState = decrypt($encryptedState); //If this fails, it indicates someone tried to replace your cookie by hand, it is a failed attack
$assoc = true; //If true, json_decode returns array, otherwise it returns an object
$yourStateObjectOrAnAssociativeArray = json_decode($userState, $assoc); //If this fails, it indicates someone tried to replace your cookie by hand, it is a failed attack
if($sign == my_hash($yourStateObjectOrAnAssociativeArray)) {
//Noone modified your cookie, you are safe
//Do something with it
}
else {
// Someone tried to replace your sign cookie to imitate your server but he failed
// or
// Someone managed to decrypt your cookie and modified it but failed to generate a valid sign (very unlikely)
// You are still safe
// Log this line and check every once in a while to detect unsuccessful hackers
}
The good part of using a state object is that it can be used to implement many kinds of restrictions and tracking mechanisms. For example storing system time during creation of your cookie gives you the chance to expire it later. Embedding client IP is a way to restrict sharing cookies across networks.
So sometimes when I pass variables around from page to page, if I want to pass a variable into a form action, I would simply store it in an <input type="hidden"> element. This generally works well but I realized that someone could easily go into the HTML markup and simply change hidden to type text and therefore they could easily edit what is being passed (this can be bad if say they were editing their own profile and I had stored in the hidden input field their ProfileID and they changed it to someone else's)
I was wondering if there is a best practice to resolving this issue? I talked to some coworkers and they said to put checks on the server when they submit the form to make sure they aren't passing in the incorrect info. Is the best way of going about it or are there other ways?
Security-wise, you cannot trust any information that comes from the client, as you correctly noted. This means that you have to store it server-side when such pages are called.
A common practice is to give each client a session identifier in a cookie and on the server-side, you can relate all sensitive information to that session identifier. The session identifier should be random, because if it was sequential, you could just change its value and hijack someone else's session at random.
There are multiple ways to store information with regards to a session identifier. The most flexible one in PHP, and probably the easiest to implement, is to use built-in session support. PHP handles the session identifier for you and lets you store any serializable object in the $_SESSION superglobal. This is an okay-ish solution, as session data is often stored in the temporary folder of your server, and if it's a shared server, chances are other websites on that server could theoretically snoop in and see or even manipulate session data. Of course, if what you're doing is really low-impact, then it's kind of unlikely that someone would go as far as rent the same server just to mess with you. Still, for instance, OAuth providers recommend that you do not store OAuth tokens in $_SESSION storage in public environments.
<?php
session_start();
// place anything you need to save between pages in $_SESSION
$_SESSION["foo"] = array("bar", "baz");
// until you unset $_SESSION["foo"], it will be available in every page that called
// session_start().
?>
It's a good practice to call session_destroy when users log out to make sure that their session data doesn't exist for longer than it needs to.
On the other hand, you can also store information in a database, such as MySQL. This is better security-wise as you should run away from any host that doesn't have distinct database users or distinct databases for each server user, and you can be assured that no one else will be able to change (or even just see) the session information. However, this isn't as flexible, as you need a table structure to store anything you want to store.
Hello all,
While taking my time in the bath I though of something interesting. In PHP, how do you tell if the users' forms submitted is valid and not fraud (i.e. some other form on some other site with action="http://mysite.com/sendData.php")? Because really, anyone can create a form that will try send and match $_POST variables in the real backend. How can I make sure that that script is legit (from my site and only my site) so I don't have some sort of cloning-site data-steal thing going on?
I have some ideas but not sure where to start
Generate a one-time key and store in hidden input field
Attempt (however possible) to grab the url on which the form is located (probably not possible)
Using some really complicated PHP goodies to determine where the data is sent (possible)
Any ideas? Thanks all!
Most of these attempts from hackers will be used by curl. It's easy to change the referring agent with curl. You can even set cookies with curl. But spoofing md5 hashed keys with a private salt and storing it in session data will stop most average hackers and bots. Keeping the keys stored in a database will add authentication.
There are few simple ways like:
Checking $_SERVER['HTTP_REFERER'] to ensure your host was the referring script
Adding hashing keys in the forms and checking them with the server session variable stored.
But all the above can be manipulated and spoofed in some way. So, you can use CSRF Validations. Here is a very good article on this.
Other additional techniques I have encountered are:
Adding time limits to forms and ensure they are submitted with in that time.
On every interaction with the form, send AJAX request to validate and reactive the form's timelimit.
HTML5 provides a new input type . The purpose of the element is to provide a secure way to authenticate users.The tag specifies a key-pair generator field in a form.
When the form is submitted, two keys are generated, one private and one public.
The private key is stored locally, and the public key is sent to the server. The public key could be used to generate a client certificate to authenticate the user in the future.
Keygen tag in HTML5
RFC
How can I prevent users from forging forms on the PHP or jquery side, I am using Jquery's ajax functionality to submit the forms, and this means that tech-wise people can change some variables such as the value of something (that shouldn't be changed / is a user id or something like that) through the use of firebug or web inspector and likewise.
So how can I prevent users from changing these variables or making sure they are unchangeable through a secure and good way?
Thanks
As the others have already stated, you can't prevent the user from tampering.
You are receiving data from me, and I can send you anything I want, I can even do an HTTP request by hand, without even using a browser, and you can't do anything about it.
If you don't want a user to be able to alter an information, don't provide it to him.
You can store it in PHP's session, which is stored server side (do not use cookies, they too are sent to the user) or save it in a database, both of them are not accessible to the end user.
If you still want to pass the data to the user, compute some sort of hash (a secure hash, using a secure hashing algorithm and a secure message digest as Gumbo noted, this rules out algorithms like CRC32 or MD5 and MACs like your name or birthday) of the data and store it server side, then when the user submits back the data, check if the hashes match.
But do know that this solution is not 100% secure. Hashing functions have collisions, and bad implementation exists.
I would recommend to stick to the golden rule: if it's not there, it cant break / be tampered / be stolen / etc.
You cannot prevent users from doing so.
Store these variables in a Session.
You can never trust the client. Validate the form on the server to ensure the data is sane. This means checking that a given user ID has permissions to post their form, etc.
I'm going to go with... you can't. You never trust the user's data; client side verification is always only the first line of defense.
I've had another developer pose the possibility of combining and encrypting/obsfucating all the parameters to pages for php, as a security measure against manipulations via crafted urls and to prevent interior knowledge of the database (e.g. knowing the id in the database of a specific entry).
In other words, instead of single or multiple public query parameters like ids, there would be a single encrypted blob that would be decrypted server-side, and re-encrypted when links are crafted.
Are there problems with this approach? Are there substantial advantages that make it worthwhile? Is this approach used in the wild to good effect?
You should design your system to prevent unauthorized access. Obsfucating (useful encryption on data the client generates is not a possibility) is not a worthwhile defense.
For instead, instead of giving the user a database ID, given them a hash (with perhaps a session seed) of the ID. The 128bit+ search space of the hash and (for reasonable DB sizes) low probability of collisions would be a much better approach. You could also encrypt the ID on the server for values the client never needs to manipulate (with a seed) but make sure it has the same properties as the hash I mentioned—namely that the search space is very large compared to the possible value space.
If you want to prevent users from messing around with the GET arguments, i would recommend the following:
Add a hidden form to all of your pages. Clicking anywhere on the page, would fill-in some data into the form and submit it securely through POST / SSL. Along the submission details, pass the URL where you want to direct user to.
On the server side, collect arguments, put them into session either globally or under some sort of identifier which you append to the destination URL. Send redirect back. This way if user refreshes page, he's not nagged about POST data. Also if he starts messing with going back and sideways in the application, kill that session cache and send him to starting page.
I have seen this technique in some on-line banking softwares. Another benefit is that user can't open new window.
In my opinion it can add some degree of security, but would severely change development approach and give you more work. I never used this approach myself and I think that ID's are safe to pass around as long as you have a proper ORM system in place which under no circumstances won't let user A access data by user B regardless of what kind of code your developers will write.
There may be some cases when this type of URL encryption (or Obsfucating) is useful. Let's say you build a pretty robust security in your application and all your hosts are safe and sound.
Now if your operations staff happens to be external and you don't want them to know/see these sensitive data (IDs) by changing log levels on the fly then it is better to encrypt them and decrypt them on demand by individual module.
As a general practice one should not pass any sensitive data in URL parameters and care should also be taken to NOT to log them even at higher level.