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. 
Current application 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?
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
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