Link to home
Start Free TrialLog in
Avatar of David Williamson
David WilliamsonFlag for United States of America

asked on

more secure way of deleting db record than url variable?

I have a page that lets admins delete users.  The way I've got it configured right now, the userid is passed in the url, where an if statement deletes the user record if it's present.  But, it occurred to me that doing that is not very secure.  If anyone ever wanted to, they could easily delete all the user records by just visiting that URL with a userid attached.

Is there a better way to manage that?  I'm already using the cflogin framework (which should prevent any non-logged in user from hitting the delete url), and I suppose  I could check for a certain user role in the delete code so I make sure the person doing the deleting is authorzied.
SOLUTION
Avatar of SidFishes
SidFishes
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of David Williamson

ASKER

Ok, I have both of those in place now.  Any other ideas for making that process more secure?  Ajaxing the delete template so the userid don't show in the url?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
by the &code, it will definately differencentiable betwen the hashed code and the user_id!

The best is to use the cfqueryparam param or the val function because if someone will try to excecute any sql injection attack, the cfqueryparam with cfsqltype=numeric or val function will handle it and it will not let it exceute the error!

Wrap the whole functionality around the cftry catch block and log that errors in the file!

Your Oprions!

1. use <cfqueryparam> Tag
2. use the Val Function
3. Store the url value in a session Scope or Form Scope and then execute behind the scenes.

Hope you Get What you need
<cfqueryparam will protect against SQL injection, but will not protect the user from changing user_id=123 to user_id=456.   To do that, you need something like the hash
well if the user has the ID as not a PK, then he can encrypt it and decrypt it, elsewith for securing the change in the URL, the best way is to pass the value either through form or session rather than URL, should not use any HASH or something because

<cfset code = hash(user_id & "secret_phrase")>

<a href="deleteUser.cfm?user_id=#user_id#&code=#code#">Delete Me</a>

in this way, he can change the url ID number and that will be verified on the action page too! without even touching the hash!

yes, encryption would work as well, just a bit slower

passing through a form can be hacked almost as easily as the URL, so you would still need hash or encryption

using a session variable is not good because multiple pages can share the same session and you cannot ensure the variable will not be over written by a different session


> he can change the url ID number and that will be verified on the action page too! without even touching the hash

I don't understand this.  You need the hash to verify the URL ID has not changed.


Encryption is not a bad idea

but tell me one thing do your app has many administrators or just one , if it is just one  then any way you will check for the existence of the session and then only allow to go further to delete the records .  this should be checked in each every page of the admin and then proceed to the next action else redirect to log in page .

If multiple administrators then first check for session and then check if this user is authorized to delete this record .

For example If i am an admin of one Zone so I can only delete records of that zone it self etc

So you can maintain another check to see if authorized to delete that record or not .


That's a good point by srikanthmadis.

Another check could be to ensure the user (administrator) has rights to delete the user_id.  He mentions admin rights to a zone, but it could be rights by company or any other way your site divides priviledges.   For example, users may belong to an organization, and you have 2-3 admins for each org.   When the admin goes to delete a user, you can do a quick query to ensure that the admin and the user being deleted are both part of the same organization.

I disagree, however, about the session variable; even if there is one admin, the admin could have multiple pages open attempting multiple tasks.  The session variable could conflict between his own pages.    This is not a good place to use session variables.


@gdemaria

"I disagree, however, about the session variable; even if there is one admin, the admin could have multiple pages open attempting multiple tasks.  The session variable could conflict between his own pages.    This is not a good place to use session variables."

I never said to use session variable my point was if it is a single admin we just check if the admin has logged in or not  and then continue with next step of deleting the record

So my point is to check if the admin has logged in and that session exists .

ex:

isloggedin()

isuserinrole (admin)

then go and delete the record .

naturally in admin portal we keep this check for all the pages and if the user has not logged in we redirect to log in page.

  I see, my mistake.  Of course you want to be sure the admin is logged in

well said experts! btw i think the author already knows this and might have implemented the functionlity, he is just asking the secure way to delete!

well said by all!

1. By encyption
2. Use the hidden form and pass the url value inside it! and then make a cross check on the action like isurl eq form.hiddenparamer, then go for delete.
3. use the cfqueryparam tag or the val function to delete the record.
4. My suggestion will just do not delete the record. just add one column to the DB, isDeleted and set its value to 0 if it is deleted and 1 if not, rather than delete, just update it

Choice is urs

Cheers
@myselfrandhawa

You can easily hack the hidden form variables too .

how does cfqueryparam  helps you in this scenario , for example if there is a url like
http://test.com/delete.php?id=2

and i change it to

http://test.com/delete.php?id=3 how does cfqueryparam solves this .

always delete option will be in a admin area and in admin it is better to have role check to see if the logged in admin has the option of deleting that particular row then only we go a head and delete it.

That is why in most of the delete functionality we give and alert first saying are you sure you want to delete so and so record and then delete it.
My point is if it is an admin and already we check if the correct user is logged in and he is authorized to do this action that check should be enough i guess

4th suggestion is good and also for delete you can add an audit kind  of stuff like this record has been deleted by user logged in IP date and time etc .

Lots of great info, everyone, thanks for the ideas.  I like the hash + salt idea in addition to the things I already have in place (admin checking before deleting, SSL).  With the hash+salt idea, no would be able to intercept and alter the id that's about to be deleted.

If  it is an internal admin  url , you don't  need to do all these checks , First make it in such a way that the url is not accessed from out side and make it secure and other steps which i mentioned in my comment id :35222007.

As i mentioned in my previous comments cfqueryparam  will not help in any way  in this scenario .


how does cfqueryparam  helps you in this scenario , for example if there is a url like
http://test.com/delete.php?id=2

and i change it to

http://test.com/delete.php?id=3

 how does cfqueryparam solves this .


Encrypting /  hash with salt mentioned by gdemaria should solve this

 you need to take certain steps if u want to use  encrypted value probably has characters that the browser doesn't know how to display in the URL box

you could use URL Encode/Decode the var as well, or possibly try using Base64 encoding on it before you pass the var through the URL.
 
ex:

<!--- Encrypt String --->
<cfset encryptstring= 'your val'>
<cfset TheKey = 'secret key phrase'>
<cfset Encrypted = Encrypt(encryptstring, TheKey)>
<cfset encryptstring64 = ToBase64(Encrypted)>
 
 you can pass encryptstring64  to the url  

 and decrypt by .

<!--- Decrypt String --->
<cfset UnlockedSecret = Decrypt(ToString(ToBinary(encryptstring64)), TheKey)>