I just read this Sitepoint CSRF discussion which gave a great illustration of how to mitigate CSRF with regard to forms. Is there a way to guard against actions as performed by links? For example, let’s say I have a link:
After my user (with admin privileges) clicks on the link, I’ll first check that the user is an admin and that they can delete that particular user based on their session information. However, won’t there be potential for CSRF in this case? And if so, since there’s no “form”, how could protect myself against it?
How I’ve always done it is with PHP. You check whether the request was through a refer. If it is not, don’t allow the action to take place. Anyone can simply copy and paste a link. However, this won’t really stop them. Next, you check to see if the refer belongs to your domain. If the domain in question is not yours, don’t allow the action to take place. Redirect the user back to a home page or something. This kind of protection can be found on Facebook.
I don’t condone hacks of any sort (even though I took an Ethical Hacking class), but Facebook used to have this safe guard, but I’m not sure why they took it off. You first logoff and view the page source of Facebook’s login. Copy all of their HTML source and open up your favorite IDE editor and paste the code you copied in there and save the file. Next, open up the file you just saved in your favorite web browser. In the login form, type some junk or your actual login information. You’ll get redirected to Facebook and it’ll warn you not to put your information on any site that isn’t located on Facebook. Basically saying that don’t use your Facebook login information on sites that look kind of like Facebook.
The address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.
I’ve been a bunch of googling/thinking since I’ve written this question, and now I’m not convinced that performing the action via a GET will enable me to mitigate the CSRF threat. However, what I can do which should work is to just create a hidden form when the user clicks on delete-user link which has the CSRF token and just submit the form via POST. Does that seem like a better approach?
You shouldn’t actually be doing any CRUD (minus R), via GET. The only time when you should do anything via GET is when you want to use R.
Basically, CRUD is in every application.
C = Create
R = Read
U = Update
D = Delete
Creating, updating, and deleting should NEVER be touched via GET. Anything in the GET parameter can be modified by the client. Same thing goes with POST, but POST is more secure. Still not secure enough, but more secure than GET.
I don’t know as I’d say one is more secure than the other.
BUT GET variables are a lot more visible
Anyone might easily notice ?token=e4ft5e4r
in their browser’s address bar. not so many will look at view-source to see <input type="hidden" name="token" value="e4ft5e4r" />
Point to remember, any user supplied input is suspect and steps should be taken to ensure it is valid and safe to use.
I do agree with this; however, I do a session check and access control to make sure that they are allowed to access the resource. With that said, POSTing seems to lend itself to better defend against CSRF — for example, the token would wind up in the browser history if I put the token in as a GET variable.
If it is important to have a link for the deletion action (say for design purposes, like a logout link in a pulldown menu), then it is better, easier and smarter to make the button look like a link, instead of trying to bend the GET method to do the mutation safely.