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.
Related
So, it's impossible to do AJAX requests securely without using SSL. I get it. You can either view-source the data that's being sent via Javascript, or you can directly access the PHP page by spoofing headers, yada yada.
But let's say this web app doesn't particularly require true security, and instead it's just a sort of game to keep most reverse-engineers at bay. What sort of hurdles should I employ?
I'm not looking for some ridiculously over-the-top Javascript implementation of an encryption algorithm. I want simplicity as well as mild security... if that isn't contradictory by nature. So, what would you guys recommend?
For example, I'm running a contest where if a user clicks an image successfully (jQuery), it passes their userid and a timestamp to a PHP page, both MD5 salted by random data and then encoded with MIME. The PHP page then validates this userid and timestamp, then returns a winning "code" in the form of another salted MD5 hash. I'm also employing multiple header checks to help ensure the request is from a valid location. Am I missing anything, or is that about all I can do? It seems like someone could just fire the jQuery click event and ruin the whole thing, but I don't see how I can prevent that.
I'll be awarding the answer to anyone who comes up with an ingenious faux-security mechanism! Or... just whomever tells me why I'm stupid this time.
I believe header checks can be easily fooled. Doesn't hurt though.
Since your algorithm is exposed on the client side, the user can simply send the appropriate data to your server with an automated script to fool your server into thinking it was clicked.
In addition to that, you have to watch out for session hijacking. A user can essentially submit this ajax request on behalf of someone else, especially if they have the algorithm. Does your application have different behavior for certain users? If so, then the session hijacking could turn into priviledge escalation issue.
It is not necessarily true that you need to encrypt the payload with SSL in your case in order to build a secure application. From what you've described, there is no sensitive data being sent over the wire.
Ensure that you have some basic silly checks on the server side to check for automated or malicious behavior. For example, if you find that the header information is missing, you may want to have some sort of flag/alert that someone is toying with the response. Another place you may want to do this is the pattern of requests.
A more secure model is to have the server assign the user some session token that they cannot reverse-engineer. This session token ideally should begin with the timestamp instead of the username to promote the avalanche effect of the salted hashing algorithm.
Since it seems like your application deals with prizes and potentially money, I would invest some more time in securing this app. Hope these tips have helped you.
What is the best solution to "form spoofing" besides filtering the inputs?
I understand the followings:
Referrer can be spoofed
Telnet can be used to fool the server
Client side filtering can be bypassed
i understand that i should avoid GET
I can use Captcha
How can i prevent somebody to post to my form processing scripts from anywhere?
If someone can manually post a form, they can do it automatically too. There's no way to stop that besides moderation. You can make it harder by using captcha's. But personally I hate captcha's, because they are just a solution made up by lazy moderators to make the users solve their problems.
Here is a way to use tokens.
http://shiflett.org/articles/cross-site-request-forgeries
Not much really. Every client-side check can be spoofed or bypassed. Some authentication method is best, either using HTTP Auth or a simple system you coded yourself with sessions.
I don't know what the best solution is necessarily, but you can use a session variable on the script that should have generated the form and check it in the script that the form POSTs to. You can md5 the variable contents and make it something somewhat random for increased security as well.
The real question is why do you want to prevent people from being able to post to your webpage from anywhere? Your webpage should be prepared to accept any input no matter where it comes from. There are measures you can take to reduce automatic posting such as tokens, but there is no way you can prevent it completely.
Instead of trying to prevent it, though, I would welcome it. Advertise your cross-site post API and profit.
Postel's law:
TCP implementations should follow a general principle of robustness: be conservative in what you do, be liberal in what you accept from others.
Set a hidden input on the form that's equal to the md5 value of a string made up of the session id + a secret "salt" string value. Then, when you process the form, you can get the session id, add the secret value, and compare the mp5 out of that to the value that was passed with the form.
I was doing some research on StackOverflow on how to properly set sessions and prevent hijacking, etc. I found an answer that someone posted on one of the questions and he provided the following code:
For when a user logs in and the username and password match
$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] .''. $_SERVER['REMOTE_ADDR']);
Checking if user is logged in, for protected pages:
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] .''. $_SERVER['REMOTE_ADDR'])) {
session_destroy();
header('Location: login.php');
exit();
}
It seems to work fine, but my questions are: how secure is this, is this a good method or should I try something else? The post had no upvotes or anything so not sure if it's good.
Also, not sure how to get information about a user with this session .. do I need to store anything in the database?
Thank you!
There are two major problems with this code.
1) IP addresses change for legitimate reasons. If the client is behind a load balancer, like at a corporate network, then he will be unable to use your web app.
2) Checking the user agent is a lot like having a get variable that says ?is_hacker=false. If the hacker has the session id, he has the user agent and its trivial to spoof.
Further more i have no idea why you would want to use md5 for this when doing a plain text comparison is actually more secure. Because the user agent is first an attacker could use the md5 prefixing attack to produce a collision and there for would bypass the REMOTE_ADDR check. (A useful md5 collision attack doesn't come up too often, but this one is fun!)
Even with this check in place CSRF and XSS can still be used to influence the session. XSS can be used to read a CSRF token and then use XHR to make any request the attacker desires. One could make the argument that this is trying to mitigate OWASP a9, but really you need to be using SSL to protect the session id.
This looks like a good method, however the fingerprint hash is generated by client data, which can be spoofed. A good method to use for the login form is to generate a random token that is stored in the session and passed through the form. Once the token is validated (or not) it should be unset for a one time use only.
The session should also store the user id once the user is logged in to retreive the user info stored in the databse.
I agree with Rook's comments, it's a pretty good analysis of your code.
There's lots to consider for securing PHP sessions but with an up to date version of PHP it's not difficult to achieve, some things to think about:
- Where the session files are stored on your server (mainly an issue if it's a shared server)
- Using a secure connection for all sensitive data and cookies going between the client & server
- Doing what you can to make the cookie session ID on the client secure
- Not storing any sensitive data in a session variable
As for storing things in a database it depends on your needs but I'd say you probably don't need it and storing data in the session variable is fine for security, just (as I've already stated) don't store anything sensitive there. Retrieve sensitive data from another location, most likely a database.
If you need to know more about PHP session security I've got a series of blog posts on the subject.
I don't run a mission critical web site so I'm not looking for an industrial strength solution. However I would like to protect against basic attacks such as someone mocking up a false page on the hard disk and attempting to gain unauthorized access. Are there any standard techniques to ensure that form submission is only accepted from legitimate uses?
A few techniques come close:
Produce a form key for every form. The key would relate to a database record, and something else unique about the page view (the userID, a cookie, etc.). A form cannot be posted if the form key does not match for that user/cookie. The key is used only once, preventing an automated tool from posting again using a stolen key (for that user).
The form key can also be a shared-secret hash: the PHP generating the form can hash the cookie and userID, for example, something you can verify when the form is posted.
You can add a captcha, requiring a user to verify.
You can also limit the number of posts from that user/cookie (throttling), which can prevent certain forms of automated abuse.
You can't guarantee that the form isn't posted from disk, but you can limit how easily it is automated.
You can't. There's no reliable way to distinguish between an HTTP request generated from a user on your page, or a malicious user with their own web-page.
Just use a proper password authentication approach, and no-one will be able to break anything unless they know the password (regardless of where the HTTP requests are coming from). Once you have reliable server-side authentication, you don't need to waste time jumping through non-robust hoops worrying about this scenario.
You should not create a login-system yourself because it is difficult to get it right(security). You should NOT store the passwords(in any form whatsoever) of your users on your site(dangerous) => Take for example lifehacker.com which got compromised(my account too :(). You should use something like lightopenid(as stackoverflow also uses openid) for your authentication.
The remaining forms you have on your site should have the following protection(at least):
CSRF protection: This link explains thorougly what CSRF is and even more important how to protect against CSRF
Use http-only cookies: http-only sessions, http-only cookies
Protect against XSS using filter.
Use PDO prepared statement to protect youself against SQL-injection
i also recommend:
Save the IP of the computer that sends the form (to block it from the server if it.s annoying)
Use CAPTCHA when required, to avoid robots...
Send users to another page when the info is loaded, so the POST data won't be retrieved when you refresh the page.
Proper validation of form data is important to protect your form from hackers and spammers!
Strip unnecessary characters (extra space, tab, newline) from the
user input data (with the PHP trim() function)
Remove backslashes () from the user input data (with the PHP
stripslashes() function)
for more detail, you can refer to Form Validation
Okay, since none of you guys like my question, let me rephrase it.
User logs into an HTML form. With JavaScript, their password is hashed locally (salted too). The server knows what the password + salt should be, user is already registered, blahblahblah. Now the user requests a page. The server sends a random ID to the user. When the user loads the next page, this random ID is appended to the key they have locally stored, it's hashed, and THAT is sent to the server. The server knows what they key is and the random ID, performs the same hash, and compares. If they match, congrats, it came from the proper computer. If not, then someone's been sniffing your TCP/IP traffic.
All of this is obviously without SSL, otherwise this would be highly redundant.
My question - HOW DO I STORE THE KEY ON A CLIENT PC?
Original Post:
Hello;
I'm working on developing a PHP Content Management System, and came up with a secure login system. The only problem is that it would require some form of client-side storage (for a very small key, 40 characters in length) - otherwise the user would have to type in their password on every page load.
Is there a way that, using either PHP or JavaScript, I can store a small 40-character string on a client's PC an retrieve it later?
EDIT: COOKIES ARE NOT AN OPTION. This 40-character string can NOT leave the client's computer, and all set cookies are sent with each HTTP header.
I REPEAT - COOKIES ARE INSECURE AND NOT A VIABLE OPTION FOR THIS.
Let me rework it like this - client submits an HTTP form. With some scripting language (e.g. JavaScript), the password is stripped from the form, NOT sent to the server, encrypted, and is kept CLIENT-SIDE, which I can retrieve and verify (by hashing it with a key sent to the user from the server). This verification is sent to the server, never the key.
There's already a browser-based system that uses keys to secure data transfer. It's called SSL.
You can use a couple of different tricks to keep state on the client, you can keep a top level frame and store a javascript variable there.
You can use Flash local "SharedObject",
Silverlights' IsolatedStorage
or the equivelant in Google Gears.
but..
Don't follow this line of thinking. You need SSL. You are not going to build something secure, you are going to build something that shoots you or someone using your app in the foot.
First I'll answer the question of "can I store client side data without using a cookie":
You could use a Flash SharedObject, but of course requires Flash, and the user has to click a confirmation box to allow it.
HTML5 features client-side databases, so there's another emerging option for you.
Use Google Gears on the client side and use their local database API
BUT - for your purposes you could engineer a login form which doesn't transmit the password but sends a hash of it. Your PHP script would send a form which included a secret salt value, and then you have some javascript which hooks into the submit event and replaces the password entered with the salted hash.
I'm not a PHP developer but I would advocate that you search for pre-existing authentication systems. They will more often than not be a bit more secure than what you would write (as that would be their primary purpose). It would also allow you to review the code and see how they did it and figure out why.
Edit: You almost always want to handle authentication on the server. It's acceptable to transfer session information to the user in the form of a cookie or url param but the actual processing should be done on the server. You are opening yourself up to major risks otherwise.
Use a cookie if you want to save it between browser visits. It'll be stored on the client's machine.
Use a session if you want to save it for a shorter duration. It'll be stored on the webserver.
If you wanted to create something that never traveled over the internet, you would basically have to do it all in JavaScript.
First, create a piece of code that starts something like Google Gears. Use the database in Google Gears to store the key.
Next, on the rest of the pages, have a piece of javascript that checks the key in the Google Gear database. If the key is not valid, delete the key, redirect the user, and make them log in again.
Cookies are the way to do that, but you won't store any password in a cookie, that's (almost) an order ;-).
You could use session to store information between page load on the server side.
http://fr.php.net/manual/en/book.session.php
Adding to what Bryan says, if you can use the HTML 5 spec, then you can take advantage of local storage.
http://ajaxian.com/archives/webkit-does-html5-client-side-database-storage
I see problem with your approach. First load of initial JavaScript can be sniffed, so salt algorithm is not protected from hacker. Then ID is also "public". I.e. seems like you have next schema (please correct me if I'm wrong) :
password + SHA1 => hashed password
hashed password + (ID from server) + (salt from server) => mega hashed password
I really have a problem to see why "mega hashed password" is more secure than hashed.