I've been tasked with updating a website that was developed in 2003-2004 before Cross-Site Request Forgery (CSRF or XSRF) was really well known to be an issue. The system is currently built on mod_perl2 and HTML::Mason (Mason 1, not 2), and it uses Apache2::AuthCookieDBI for user authentication. I'm sure it was state-of-the-art back in 2003-2004, but the basic building blocks haven't been updated since then. A recent security audit revealed that most of this site's CGIs are vulnerable to CSRF, and I need to fix it.
Switching to a completely different framework/middleware like CGI::Application, Dancer, Catalyst, or Plack would take too much effort, I think. And everyone is happy with how the site works currently, so avoiding any user-visible changes would be preferable.
So what's the best way to incorporate CSRF protection into a site that uses mod_perl, Mason, and Apache2::AuthCookieDBI (or Apache::AuthCookie in general)? Has anyone done anything like this?
MasonX::Request::WithApacheSession looks promising, but Apache::Session doesn't appear to be updated as frequently as CGI::Session or as well regarded, I think. There's also Apache::SessionManager, but it hasn't been updated since 2004. A lot of these modules seem to overlap conceptually with Apache::AuthCookie. It appears I'd be almost generating two session IDs if I go with one of these approaches in addition to using Apache::AuthCookieDBI. Can I reuse the AuthCookieDBI ticket as the session ID with any of these modules?
Or should I just roll my own class to generate a random, one-time-use-only, expirable token, stick it in just the forms that have consequences as a hidden parameter, and store the token in the server-side database? I don't want to reinvent the wheel, but there is similar code already in this project for handling password resets which I could potentially generalize and refactor, so I'm very tempted to go this route. The problem with that is that it's not a comprehensive solution, so it would require identification and modification of the vulnerable forms that modify the database and there's always the possibility I could miss a form. Even if I don't, some future web developer might add a new form without thinking it through.
Thanks for any advice!