Protecting Web Application with CSRF Tokens

Oct 7, 2025

Protecting Your Web Application with CSRF Tokens

I recently worked on integrating a third-party certificate audit API service into our existing application. One of our primary concerns, shared by our customers, was ensuring the security of our public website.

We implemented a feature that allows clients to submit their certificate number for verification. The feature was straightforward - users simply enter a text field with a number as an ID, and if it matches our system, we respond with relevant information.
CSRF Token Prevention Flow

Current application flow
Old Flow

The Security Problem

The web application sends a simple POST request to verify the certificate:

POST https://www.company.com/api/check
Content-Type: application/json
{
  "id": "XWG1000FFHH"
}

The Vulnerability

This approach creates several security vulnerabilities:

  • Brute Force Attacks: Attackers can send random requests until they find a valid certificate ID
  • Malicious Injection: Without proper validation, malicious payloads could be injected
  • No Authentication: Anyone can attempt to access certificate information
Security Principle: As developers, we should maintain a security-first mindset. One of our core principles is: "Never trust anything exposed to the public."

The Solution: CSRF Token Protection

To prevent these security flaws and ensure only legitimate users can check their certificates, we implemented CSRF (Cross-Site Request Forgery) token protection - one of the best practices recommended by OWASP.

Legitimate users: User use browser Chrome, Safari

What is a CSRF Token?

CSRF Token Prevention Flow

A CSRF token is a long, randomly generated string created on the server-side. It's generated once per user session or for each request, depending on your security requirements.

CSRF Token Requirements:

  • Unique per user session - Each user gets their own token

  • Secret - Not predictable or guessable by attackers

  • Unpredictable - Large random value generated using secure cryptographic methods

  • Time-limited - Tokens should expire after a reasonable time period

Implementation Example

Here's how we implemented CSRF protection in our form:

<form action="/check.do" method="post">
  <input type="text" name="certificate-id" placeholder="Enter certificate ID" />
  <input type="hidden" name="csrf-token" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZMGYwMGEwOA==" />
  <button type="submit">Verify Certificate</button>
</form>

Now our API request always includes the CSRF token:

payload:
{
  "id": "XWG1000FFHH",
  "_token": "OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZMGYwMGEwOA=="
}

or instead of payload can use header
header:

headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
...(csrfToken && { 'X-CSRF-TOKEN': csrfToken }),
...config.headers
},

Once the request send backend will handle the matching logic. In our case we use Laravel the framework already has csrf builtin
https://laravel.com/docs/12.x/csrf

app/Http/Middleware/VerifyCsrfToken.php

Token from input or request

protected function getTokenFromRequest($request)
{
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');

if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
try {
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
} catch (DecryptException) {
$token = '';
}
}

return $token;
}

Matching token

protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);

return is_string($request->session()->token()) &&
is_string($token) &&
hash_equals($request->session()->token(), $token);
}

New application flow
New Flow

Conclusion

Implementing CSRF token protection is a crucial step in securing web applications.

Area to apply: Consider apply this to contact form, newsletter.

If you're using external third like payment.
It should be consider to exclude its domain because it should be handle by its services

References