Get a Pentest and security assessment of your IT network.

Cyber Security

Background Sync & CSRF Protection

TL;DR

This guide shows how to safely use Background Sync in your web app, protecting against Cross-Site Request Forgery (CSRF) attacks. We’ll focus on using a unique token for each sync request and verifying it on the server.

Background Sync & CSRF: The Problem

Background Sync lets users continue working offline; changes are queued and sent when they regain connectivity. However, this introduces a CSRF risk. A malicious site could trigger a sync operation without the user’s knowledge, potentially performing unwanted actions on your server.

Solution: Unique Tokens & Verification

The core idea is to include a unique, unpredictable token in each Background Sync request and verify that token on the server before processing the data. Here’s how:

Step-by-Step Guide

  1. Generate a CSRF Token: On your server, generate a new, random CSRF token for each user session. Don’t reuse tokens! Store this token securely associated with the user’s session.
  2. Include the Token in Your Form/Request: When creating data that you want to sync, include the current CSRF token as a hidden field or header within your request payload. For example:
    <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
  3. Pass Token to Service Worker: When the user submits a form or triggers an action that needs syncing, retrieve the CSRF token from your application and store it in local storage. This is needed by the service worker.
    localStorage.setItem('csrf_token', '{{ csrf_token }}');
  4. Service Worker Registration & Sync Event: Register your service worker as usual. The sync event will be triggered when connectivity returns.
    if ('serviceWorker' in navigator) {n  navigator.serviceWorker.register('/sw.js').then(function(registration) {n    console.log('Service Worker registered!');n  });n}
  5. Retrieve Token in Service Worker: Inside your service worker, retrieve the CSRF token from local storage when handling the sync event.
    self.addEventListener('sync', function(event) {n  const csrfToken = localStorage.getItem('csrf_token');n  // ...
  6. Construct Sync Request with Token: Build your POST request to send the queued data, including the retrieved CSRF token in a header (recommended) or as part of the payload.
    fetch('/sync-endpoint', {n  method: 'POST',n  headers: {n    'Content-Type': 'application/json',n    'X-CSRF-Token': csrfToken // Use a custom headern  },n  body: JSON.stringify(queuedData)n}).then(...);
  7. Server-Side Verification: On your server, always verify the CSRF token received with the sync request against the token stored in the user’s session.
    • If the tokens match, process the data.
    • If the tokens don’t match, reject the request immediately (return a 403 Forbidden error).
  8. Token Rotation: Implement token rotation on your server for added security. Regularly generate new CSRF tokens and invalidate old ones. This limits the window of opportunity for attackers if a token is compromised.

Important Considerations

  • Secure Storage: Ensure that local storage is used securely. While generally safe, avoid storing sensitive information directly in local storage.
  • HTTPS Only: Background Sync requires HTTPS to function correctly and prevent man-in-the-middle attacks.
  • Error Handling: Implement robust error handling in your service worker to gracefully handle failed sync attempts.
  • Session Management: Proper session management on the server is crucial for CSRF protection. Ensure sessions are invalidated when users log out or after a period of inactivity.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation