views:

172

answers:

8

I have a web application which has basic authentication - username, password, session and stuff. However I have a specific need to prevent users from spoofing the POST requests (even for logged in users). In my application, I am specifically validating the user's session before accepting the POST data (taking care of XSS and stuff also).

Like:

if(user session exists)
{
    // handle the data POSTed
}

else {
   // ...
}

I am storing the sessions IDs in the database. Is there anything else I should be aware of to prevent bogus POST requests or is this sufficient?

+2  A: 

You could try generating post keys for each post request. Sort of additional param that shows that post request is valid and was executed from a form on your page.

Eimantas
+1  A: 

If you are building valid POST requests in Javascript in the user's browser, there is not much you can do to prevent a determined user from submitting bogus POSTs to your server. The user has a valid session id that he can use to make a POST request. He also has access to all of the code and all the other data that code has access to for building the request.

You can't rely on browser-side code to secure your system. The security has to be enforced at the server. For example, all operations on objects should be authenticated and authorized.

Ned Batchelder
+1 for "The security has to be enforced at the server." This can't be said often enough.
Don Branson
A: 

In my current application I have some code which is sent to the browser and the browser then posts back and must not be able to modify it. What I do is to append a secret string to the value, get the SHA1 checksum of that full string, and then require the browser to send back both the value and the checksum. I'm pretty sure this is how .NET does viewstate, too.

erikkallen
A: 

If user session is long-lived, you are still susceptible to XSRF. You need to take measures against that too.

If you are on .NET, check out AntiForgeryToken,

http://msdn.microsoft.com/en-us/library/dd492767.aspx

ZZ Coder
The anti-forgery-token simply means the page was posted from a previous GET, which limits basic fraudulent POSTs. Any variety of screen recorders could record/playback these pages.
bryanbcook
A: 

When accepting user input, the zero-level thing you need to do, before storing things in the database is to make sure you run the data via the mysql_real_escape_string($MyPostData) function.

Also, it is good for every variable/data you want to accept via POST to validate it programmatically based on its type and what you intend to do with it.

These are two main rules for making sure there's no 'funny' business coming from the user: making sure you work with valid variables AND making sure data that gets to the database is verified and escaped properly.

Cristi Cotovan
+1  A: 

Use a CAPTCHA image.

The web is built on REST, which by definition is all about transferring state from one point to another. Someone with enough time on their hands could craft a POST request that emulates an active session.

Like all secure requests, CAPTCHA is validated server-side.

bryanbcook
A: 

With your model (and especially if you use integer numbers for your session IDs) an attacker can easily submit a request on behalf of another user (e.g. decrement your own session ID and you are already someone else provided this session ID exists). You need to have a unique session key/guid associated with each session ID and stored both in the DB and on the client in the cookies. Each time your client submits a request you should read not only session ID but also the session GUID and then validate them both against your database values. In addition to that you may also want to consider some XSRF mitigation strategies.

DmitryK
+2  A: 

I am specifically validating the user's session before accepting the POST

If you mean what is normally meant by ‘session’: a persistent token stored in a cookie that identifies the user and associated session data, then no, that's not enough. That cookie is sent automatically by the browser even if the POST request was provoked by another (attacker) site.

The keyword you are looking for here is Cross-Site Request Forgery or XSRF, where an authenticated user can be made by an attacker (via scripting or other methods) to make a GET or POST request to your site. Such requests are not generally distinguishable from legitimate requests. (Some people try to do so though checking the HTTP referrer data, but this is unreliable.)

These attacks are not quite as immediately damaging as server-side (SQL, command) or client-side (HTML, JavaScript) injections, but they are more common than both: few web programmers both to include the proper countermeasures, unfortunately. Until they get their sites compromised by an XSRF hole anyway.

There are various way to defend against XSRF, but the only really effective approach is to include in each submittable form a secret value that the third-party attacker won't know. This is often known as a post key, as mentioned by Eimantas.

There are various ways to generate such secret information. A simple approach is to add a randomly-generated code to each user's account details, then put that in a hidden field in the form and check for its presence in the submission. eg in PHP:

<form method="post" action="delete.php"><div>
    <input type="hidden" name="key" value="<?php echo(htmlspecialchars($user['key'])); ?>"/>
    <input type="submit" value="Delete" />
</div></form>

if ($_POST['key']!=$user['key'])
    // error

An attacker won't know the key for that user so can't make a link/form that contains it.

You could also use a cryptographic hash function on the user's ID with a server-secret key, rather than keeping a separate code. With a hash, you can also throw in other stuff like an expiry time so that forms have to be submitted within a certain timeframe. Or you can generate a one-use transaction key, which you can also use to make sure you can't submit the same form twice (for stopping double-posting).

bobince