tags:

views:

63

answers:

3

Hey All,

Sort of a methods/best practices question here that I am sure has been addressed, yet I can't find a solution based on the vague search terms I enter.

I know starting off the question with "Fast and easy" will probably draw out a few sighs, so my apologies.

Here is the deal.

I have a logged in area where an ADMIN can do a whole host of POST operations to input data relating to their profile. The way I have data structured is pretty distinct and well segmented in most tables as it relates to the ID of the admin.

Now, I have a table where I dump one type of data into and differentiate this data by assigning the ADMIN's unique ID to each record. In other words, all ADMINs have this one type of data writing to this table. I just differentiate by the ADMIN ID with each record.

I was planning on letting the ADMIN remove these records by clicking on a link with a query string - obviously using GET. Obviously, the query structure is in the link so any logged in admin could then exploit the URL and delete a competitor's records.

Is the only way to safely do this through POST or should I pass through the session info that includes password and validate it against the ADMIN ID that is requesting the delete?

This is obviously much more work for me.

As they said in the auto repair biz I used to work in... there are 3 ways to do a job: Fast, Good, and Cheap. You can only have two at a time. Fast and cheap will not be good. Good and cheap will not have fast turnaround. Fast and good will NOT be cheap. haha

I guess that applies here... can never have Fast, Easy and Secure all at once ;)

Thanks in advance...

+3  A: 

As a general rule, any operation that alters state (whether its session state, or database state) should use POST. That means the only 'safe' SQL operation you can perform with GET is SELECT. Even if you're only using a back-end admin thing, you shouldn't use get. Imagine re-opening your browser and finding that the last time you closed firefox was on your 'DELETE EVERYTHING' GET->delete page resulting in everything being deleted again.

One of the main reasons for this is preventing cross-site request forgeries. For example, if you had a page that took a GET variable such as http://example.com/account?action=logout, an attacker could post an image on your site like this:

<img src="http://example.com/account?action=logout" />

and anyone who opened a page containing that image tag would be immediately logged out, even if they were an admin. It would be very annoying to then search through your raw database for that data and remove it.

Although POST operations are 'nearly' as easy to forge, as a general rule with any web security issue, the trade-off is speed/simplicity vs. security, so you're going to have to choose one or the other.

Lotus Notes
+1 for the warning about XSS. But you still want real business logic that enforces the rules about what you are allowed to delete. Relying on POST to discourage people from deleting each others' records would be foolish.
timdev
Thanks Byron. All excellent tips across the board. I appreciate it. Beacuse of your precedence I am giving you the answer. Tim's was great advice too!
rob - not a robber
A: 

You're saying: "What if Admin 123 access the URL of Admin 321 directly, thus deleting his stuff?" no?

If that's so then, every admin that is logged in should have at least one session with some unique identifier to that admin. If not, he shouldn't be able to be in the admin section in the first place. Can't you just compare the identifier in the URL with the identifier in the session?

If any user, not just an admin, access those 'delete me' URLs he should be identified by a session as the original 'owner' (admin) of that data.

Ben
hey omfgroflmao... yeah, I figured that's what I'd have to do. I know my OP meandered so I don't fault you for not seeing that I vaguely proposed that within the "question" Thanks for the tip!!!
rob - not a robber
+2  A: 

You should have some kind of session set up.

Using POST over GET gets you nothing tangible as far as security is concerned. POSTs can be forged just like GETs.

So assuming once your admin logs in, you've got some kind of identifier in the session, you just leverage that.

Consider something roughly similar to this:

<?PHP
session_start();

if (empty ($_SESSION['admin_id'])) die("Log in, son.");

if (empty($_GET['record_id'])) die("You've got to tell me which record to delete!");

if (! is_numeric($_GET['record_id'])) die("Invalid record ID");

//just to be totally safe, even though we just enforced that it's numeric.
$record_id = mysql_real_escape_string($_GET['record_id']));

$sql = "DELETE FROM table WHERE record_id='{$record_id}' AND admin_id = {$_SESSION['admin_id']}";

mysql_query($sql);

echo "Record was deleted (assuming it was yours in the first place)";
?>

In that example, we're avoiding the "delete someone else's records" problem by leveraging the WHERE clause in the DELETE query. Of course, to be more user friendly, you'd want to first fetch the record, then compare the admin_id on the record to the admin_id in $_SESSION, and if they don't match, complain, log something, throw an error, etc.

HTH

timdev
Hey Tim... thanks.. .it's me, Rob from Spartan.. I'lltake your advice into account. Hope all is well!!!
rob - not a robber
Bwahaha! Small world. Feel free to email me if you want more intense help.
timdev