Handling CSRF protection I'm currently working on an implementation of a CSRF protection. What is the best practice when we detect a CSRF? Is it better to 404 the page, 403 (forbidden), 200 (OK) with an error message, something else?

Bonus : here's my code.
I'm not very proud of the preg_replace and ob_*. If you also have suggestions on how to do it better, I'll take that too.


The addCSRF method is called just before sending the output of an HTML page.
The checkCSRF method is called when the server receives a request.




&lt;?php
// This method checks if the content contains a form and adds a csrf_token hidden field
public static function addCSRF()
{
    $content = ob_get_contents();
    if (strlen($content))
    {
        // Random csrf token
        $randomtoken = base64_encode(openssl_random_pseudo_bytes(32));
        // Add the hidden input to the content if needed
        $content = preg_replace('/(&lt;([^&gt;]*\s)?form(\s[^&gt;]*)?&gt;)/i', '\1&lt;input type="hidden" name="csrf_token" value="'.$randomtoken.'" /&gt;', $content, -1, $count);
        // If at least one input has been added, add the csrf_token value in the $_SESSION and replace the content
        if ($count)
        {
            Session::set('csrf_token', $randomtoken);
            // Echo the new content
            ob_end_clean();
            ob_start();
            echo $content;
        }
    }
    return;
}
// This method checks if a form has been submited and if the csrf token is given and valid
public static function checkCSRF()
{
    // No form submitted
    if (!isset($_POST))
        return;
    // CSRF detected
    if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] != Session::get('csrf_token'))
    {
        // 404 ? 403 ? 200 + error message ?
    }
    Session::forget('csrf_token');
}
While trying to add an easter egg on my framework, I saw this answer : Stack Overflow returning HTTP error code 418 (I'm a teapot)?.

Since it looks like there is no "correct" way to handle CSRF, I thought it could be a fun thing to do. Upon detecting a CSRF attack, my framework now sends a HTTP 418 header with a nice ASCII art of a trolly teapot.

So I mark this question as answered, because there's no real best practice (yet ?) and anything would be OK.