In February, I wrote a three part series on how we fixed JForum on coderanch to protect from CSRF. In included;
Remaining problems
Unfortunately, there were three remaining problems.
- Some mobile devices weren’t able to handle the JavaScript which added the tokens. Meaning our site didn’t work on all mobile devices.
- The CSRF token was in the URL of thread links which meant people were sharing those links with tokens in them. This isn’t a significant security risk, but it does confuse Google which is bad for SEO. It is a tiny security risk in that if someone posts their current CSRF token, that user can be targeted for a CSRF attack until that token expires.
- Some people take a really long time to write a post or have lunch in the middle and the token expires. Giving them a CSRF error page when they finally finish.
This blog post shows how we solved these problems.
Ending requirement for JavaScript to set CSRF token and getting token out of URLS
In general, there are three options for setting a CSRF token in forums/URLs: JavaScript, a filter to change the HTML at runtime before it gets served to the client or hard coding the token.
Based on our experience with mobile devices, we decided not to go with option1 (JavaScript.) I had used a technique similar to option 2 (changing the HTML as it goes by) to transform our JForum URLs to a different format. This turned out to be more complex on a forum where users routinely post code. The same problem would occur here so I decided against that option. We don’t want to be adding CSRF tokens to code user’s post in questions. And we certainly don’t want someone to be able to inject a CSRF attack in a post!
This left me with option 3 – hard coding the token. There were a few steps to implementing this option:
- The JavaScript solution added the token to URLs in addition to forms. This wasn’t “good” in the first place in that URLs shouldn’t be changing database state. I had recognized this as a shortcoming back in February but lacked the time to fix it then. There’s a representative list of these pages/URLs on github. Many were fixed by a one to one conversion of links to forms. (with POST as the method.) A few were fixed with a generic form on the page and JavaScript that calls it. We used the generic JavaScript form for some admin links to save bandwidth. Most of these aren’t available in the mobile view anyway. And moderators weren’t the ones having JavaScript issues in the first place – probably because we have newer mobile devices.
</span></span>function submitActionForForum(actionVerb, forumId) { var action = document.actionForm.action; action = action.replace("ACTION", actionVerb); action = action.replace("FORUM_ID", forumId); document.actionForm.action = action; document.actionForm.submit(); }
- At this point we don’t need to add tokens to anchors.
- Remove AddJavaScriptServletFilter and JavaScriptServlet so tokens are no longer generated by JavaScript.
- Add token to all forms:
<input type="hidden" name="OWASP_CSRFTOKEN" value="${OWASP_CSRFTOKEN!""}" />
- For forms containing multipart/form-data (there were less than 10 of these), add to the URL:(this is needed because the multipart request is only parsed once – later on in the process and the parameter isn’t available to us in the filter)
?OWASP_CSRFTOKEN=${OWASP_CSRFTOKEN!""}
- In parallel to the previous two steps, I wrote a unit test to ensure I didn’t miss any required tokens AND to alert anyone adding a form to the codebase in the future about the need to add a token. Unit test available on github.