Am I under risk of CSRF attacks in a POST form that doesn't require the user to be logged in?

Monika Sulik picture Monika Sulik · Mar 7, 2010 · Viewed 18.2k times · Source

I'm probably being a total noob here, but I'm still uncertain about what a CSRF (Cross-Site Request Forgery) attack is exactly. So lets look at three situations...

1) I have a POST form that I use to edit data on my site. I want this data to be edited only by users that are logged in.

2) I have a site, which can be used by both users who are logged in as well as guests. Parts of the site are for logged in users only, but there are also POST forms that can be used by all users - anonymous and not (for example a standard contact form). Should the contact form be safeguarded against CSRF attacks?

3) I have a site which doesn't have an authentication system at all (well, perhaps that's unrealistic, so lets say it has an admin site which is separate from the rest of it and the admin part is properly safeguarded). The main part of the site is only used by anonymous users. Do the POST forms on it need to be safeguarded?

In the case of 1) the answer is clearly yes. But in the case of 2 and 3 I don't know (and is the difference between 2 and 3 even significant?).

Answer

BalusC picture BalusC · Mar 8, 2010

There's means of CSRF whenever malicious HTML or JavaScript which is targeted on your website is been embedded in another HTML page (or an email message) which is been successfully executed.

An example is the following which is been placed in another webpage which innocently asks for your name and age before proceeding:

<form action="http://yoursite.com/transferfunds" method="post">
    Your name: <input type="text"><br>
    Your age: <input type="text"><br>
    <input type="submit">
    <input type="hidden" name="amount" value="1000">
    <input type="hidden" name="toaccount" value="12345678">
</form>

Note that the action points to your website and that the hidden inputs contains the needed POST information. This example will try to transfer a fund of 1000 (in whatever currency) to account number 12345678. If you require a login on your form and also actually checks on that, then the above will of course only be successfully executed if the unaware user has recently logged in your website, but not logged out yet, or the session is not expired yet.

To prevent that to happen, your best bet is to add a request based token to the form and validate it in the server side. I.e. generate a long, unique and impossible-to-guess random string which you store in the session and embed as <input type="hidden"> element of the form. When the form is submitted, compare the submitted token value with the one already in session (and immediately remove the one in session). To go a step further, make use of a CAPTCHA.

In your particular case, I think you're actually more worrying about XSS, which is an opposite of CSRF, but which in turn can also be a source for CSRF. An example of XSS is when the user enters the following in an input field which is going to be redisplayed sooner or later at the same website:

<form name="delete" action="admin/deleteusers" method="post"></form>
<script>document.form.delete.submit();</script>

Whenever you -as being the administrator- views the page with the comment with the (invisible!) form and script inside, then it will be successfully executed.

Preventing XSS is actually quite easy. Just HTML-escape any user-controlled input (i.e. request URL, request headers, request parameters and request body) prior to displaying them at the webpage. In PHP you can use htmlspecialchars() for this and in Java/JSP the JSTL fn:escapeXml(). This way under each the < will be converted to &lt; and > to &gt; which will make that any entered HTML/JS will be displayed literally as-is and thus can't be executed.