HIGH cross site request forgeryjwt tokens

Cross Site Request Forgery with Jwt Tokens

How Cross Site Request Forgery Manifests in Jwt Tokens

Cross Site Request Forgery (CSRF) in JWT-based APIs exploits the stateless nature of JWT tokens. Unlike traditional session cookies that browsers automatically include in requests to the same origin, JWT tokens are typically stored in HTTP-only cookies or local storage. When stored in cookies, JWTs can be vulnerable to CSRF if the API doesn't implement proper anti-CSRF measures.

The attack works because browsers automatically send cookies to the domain that set them, regardless of whether the request originated from your site or a malicious one. An attacker can craft a form or JavaScript that makes a POST request to your API endpoint, and the victim's browser will include their JWT cookie without their knowledge. Since JWTs often grant broad permissions and don't expire immediately, this allows attackers to perform actions on behalf of the user.

<!-- Malicious CSRF form -->
<form action="https://api.example.com/transfer" method="POST" id="csrf-form" style="display:none">
  <input type="hidden" name="amount" value="1000" />
  <input type="hidden" name="to" value="attacker@example.com" />
</form>
<script>
  document.getElementById('csrf-form').submit();
</script>

In JWT-based APIs, this becomes particularly dangerous because the token often contains user identity and permissions. Without CSRF protection, an attacker can trigger any action the user is authorized to perform, from changing email addresses to transferring funds.

Another JWT-specific CSRF variant involves double-submit cookies. Some developers store JWTs in HTTP-only cookies for security but also send them in Authorization headers for API calls. This creates a situation where the cookie is automatically sent (vulnerable to CSRF), while the header version is not. Attackers can exploit this inconsistency to bypass security measures.

State-changing operations are the primary target: POST, PUT, PATCH, and DELETE requests. GET requests for data retrieval are less concerning since they don't modify state, though they can still leak information through CSRF if the API doesn't implement proper access controls.

Jwt Tokens-Specific Detection

Detecting JWT CSRF vulnerabilities requires examining both the token storage mechanism and the API's anti-CSRF implementation. The first indicator is how JWTs are stored and transmitted. If JWTs are stored in HTTP-only cookies without additional CSRF protection, this is a red flag.

middleBrick's scanning engine specifically tests for JWT CSRF by attempting to trigger state-changing operations without including any anti-CSRF tokens. The scanner submits POST requests to endpoints identified in your OpenAPI spec and analyzes the responses. If the API processes the request and performs the action using only the JWT cookie, this indicates a CSRF vulnerability.

Key detection patterns include:

  • State-changing endpoints that accept JWTs in cookies without CSRF tokens
  • Missing SameSite cookie attributes on JWT cookies
  • API endpoints that don't verify anti-CSRF tokens for non-GET requests
  • Inconsistent token handling between cookie and header-based JWT transmission
  • Missing or improperly implemented double-submit cookie patterns

middleBrick's JWT-specific checks examine the OpenAPI specification to identify which endpoints accept JWTs and what HTTP methods they support. The scanner then tests each state-changing endpoint with crafted requests to determine if CSRF protection is properly implemented.

During scanning, middleBrick also checks for common JWT CSRF anti-patterns like storing JWTs in localStorage or sessionStorage without any CSRF protection, which while preventing automatic cookie transmission, introduces other security risks like XSS vulnerabilities.

Jwt Tokens-Specific Remediation

Securing JWT-based APIs against CSRF requires implementing proper anti-CSRF mechanisms. The most effective approach combines SameSite cookie attributes with CSRF tokens.

// Set JWT cookie with SameSite and Secure flags
const jwt = generateJwtToken(user);
res.cookie('jwt', jwt, {
  httpOnly: true,
  secure: true,      // HTTPS only
  sameSite: 'strict', // Most secure option
  maxAge: 3600000
});

The SameSite='strict' attribute prevents the cookie from being sent in cross-site requests, which blocks the most common CSRF attack vector. For APIs that need to support third-party integrations, SameSite='lax' provides a balance, though 'strict' is recommended for maximum security.

For additional protection, implement double-submit cookie pattern or CSRF tokens:

// Generate CSRF token and store in cookie
function generateCsrfToken() {
  return crypto.randomBytes(32).toString('base64');
}

// Middleware to set CSRF cookie
app.use((req, res, next) => {
  if (!req.cookies.csrfToken) {
    res.cookie('csrfToken', generateCsrfToken(), {
      httpOnly: false, // Must be readable by client
      secure: true,
      sameSite: 'strict'
    });
  }
  next();
});

On the client side, include the CSRF token in request headers:

// React example with fetch
const response = await fetch('/api/protected-endpoint', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': Cookies.get('csrfToken')
  },
  body: JSON.stringify(data)
});

Server-side validation must verify that the CSRF token matches the one in the cookie:

// Express middleware for CSRF validation
function csrfValidation(req, res, next) {
  const csrfToken = req.headers['x-csrf-token'];
  const cookieCsrf = req.cookies.csrfToken;
  
  if (!csrfToken || csrfToken !== cookieCsrf) {
    return res.status(403).json({ error: 'CSRF token mismatch' });
  }
  next();
}

// Apply to state-changing routes
app.post('/api/transfer', csrfValidation, transferFunds);

For APIs that must support both browser and non-browser clients, implement a dual strategy: use SameSite cookies for browser clients and require Authorization headers for API clients. This provides defense in depth while maintaining compatibility.

middleBrick's remediation guidance includes specific code examples for your tech stack and identifies which endpoints need immediate attention based on the severity of the CSRF vulnerability detected.

Frequently Asked Questions

Can JWTs stored in localStorage be vulnerable to CSRF?
JWTs in localStorage are not automatically sent by browsers, so they're not vulnerable to traditional CSRF. However, they're susceptible to XSS attacks where malicious scripts can read the token. The trade-off is between CSRF (cookie storage) and XSS (localStorage) vulnerabilities. For most applications, HTTP-only cookies with SameSite attributes provide better overall security.
How does middleBrick detect CSRF vulnerabilities in JWT APIs?
middleBrick tests state-changing endpoints by submitting requests without anti-CSRF tokens. If the API processes the request and performs the action using only the JWT cookie, it indicates a CSRF vulnerability. The scanner examines your OpenAPI spec to identify endpoints, tests POST/PUT/DELETE methods, and provides specific findings with severity levels and remediation guidance.