> For the complete documentation index, see [llms.txt](https://docs.pteroca.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.pteroca.com/advanced-topics/security-hardening/csrf-protection.md).

# CSRF Protection

Configure CSRF (Cross-Site Request Forgery) protection and trusted proxies for PteroCA.

## Overview

CSRF protection is a security measure that prevents unauthorized commands from being transmitted from a user that the application trusts. PteroCA uses Symfony's built-in CSRF protection.

## When CSRF Configuration is Needed

You need to configure CSRF settings if:

* **Using Cloudflare** or other CDN in front of your server
* **Behind a reverse proxy** (NGINX proxy, load balancer, etc.)
* **Experiencing "Invalid CSRF token" errors**
* **Need to disable CSRF** for testing/development (not recommended for production)

## CSRF with Cloudflare

If your server is behind Cloudflare, you may encounter "Invalid CSRF token" errors. This happens because Symfony needs to recognize Cloudflare as a trusted proxy.

### Configure Trusted Proxies

#### Step 1: Get Cloudflare IP Ranges

Use the official list of Cloudflare IP ranges from [Cloudflare Documentation](https://www.cloudflare.com/ips/).

Current Cloudflare IPv4 ranges (verify these periodically):

```
173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0/15
104.16.0.0/13
104.24.0.0/14
172.64.0.0/13
131.0.72.0/22
```

#### Step 2: Update .env File

Add the `TRUSTED_PROXIES` variable to your `.env` file:

```bash
# Edit .env file
nano /var/www/pteroca/.env
```

Add this line with Cloudflare IP ranges:

```
TRUSTED_PROXIES=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22
```

For quick testing (less secure), you can use:

```
TRUSTED_PROXIES=0.0.0.0/0
```

**Warning:** Using `0.0.0.0/0` trusts all IPs and should only be used for testing.

#### Step 3: Clear Cache

After updating `.env`, clear the Symfony cache:

```bash
cd /var/www/pteroca
php bin/console cache:clear
```

### Configure Trusted Hosts

To prevent Host header injection attacks, also configure trusted hosts:

```bash
# Add to .env file
TRUSTED_HOSTS=^example\.com$|^www\.example\.com$
```

Use regex to match your domains:

* `^example\.com$` - Exact match for example.com
* `^.*\.example\.com$` - Match all subdomains
* Separate multiple patterns with `|`

Example with multiple domains:

```
TRUSTED_HOSTS=^panel\.example\.com$|^panel\.backup\.com$
```

## Disabling CSRF Protection

### For Development Only

In development or testing environments, you may want to disable CSRF protection temporarily:

```bash
# Add to .env file
DISABLE_CSRF=true
```

After updating, clear cache:

```bash
php bin/console cache:clear
```

### Production Warning

**Never disable CSRF in production!** This creates serious security vulnerabilities:

* Users vulnerable to CSRF attacks
* Attackers can perform unauthorized actions
* Compliance violations (PCI-DSS, GDPR, etc.)

## Reverse Proxy Configuration

If using a reverse proxy (NGINX, Apache, HAProxy, etc.), you need to configure trusted proxies.

### NGINX Reverse Proxy

If PteroCA is behind NGINX reverse proxy:

#### NGINX Configuration

```nginx
location / {
    proxy_pass http://pteroca_backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
```

#### PteroCA Configuration

Add proxy server IP to trusted proxies:

```bash
# If proxy is on same server
TRUSTED_PROXIES=127.0.0.1

# If proxy is on different server
TRUSTED_PROXIES=192.168.1.100

# Multiple proxies
TRUSTED_PROXIES=127.0.0.1,192.168.1.100
```

### Load Balancer

For load balancers, add all load balancer IPs:

```bash
# Multiple load balancer IPs
TRUSTED_PROXIES=10.0.1.10,10.0.1.11,10.0.1.12
```

## Troubleshooting

### "Invalid CSRF Token" Errors

**Symptom:** Forms fail with "Invalid CSRF token" error

**Solutions:**

1. **Check trusted proxies configuration**

   ```bash
   cat .env | grep TRUSTED_PROXIES
   ```
2. **Verify Cloudflare IP ranges are current**
   * Check <https://www.cloudflare.com/ips/>
   * Update .env if ranges changed
3. **Clear cache after changes**

   ```bash
   php bin/console cache:clear
   ```
4. **Check session configuration**

   ```bash
   cat .env | grep SESSION
   ```
5. **Verify cookies are being set**
   * Check browser developer tools → Application → Cookies
   * Look for session cookie

### Sessions Not Persisting

**Symptom:** User logged out frequently, sessions don't persist

**Solutions:**

1. **Check session lifetime**

   ```bash
   # Add to .env
   SESSION_TIMEOUT=3600  # 1 hour in seconds
   ```
2. **Verify session storage**
   * Check `var/sessions/` directory exists and is writable
   * Set proper permissions:

     ```bash
     chmod 755 var/sessions
     chown www-data:www-data var/sessions
     ```
3. **Check cookie domain**

   ```bash
   # Add to .env if needed
   COOKIE_DOMAIN=.example.com  # Note the leading dot for subdomains
   ```

### Trusted Host Errors

**Error:** "Untrusted Host" or "Invalid Host header"

**Solutions:**

1. **Add domain to TRUSTED\_HOSTS**

   ```bash
   TRUSTED_HOSTS=^example\.com$|^www\.example\.com$
   ```
2. **Escape dots in regex**
   * Use `\.` not `.`
   * Example: `example\.com` not `example.com`
3. **Test regex pattern**

   ```bash
   # Use PHP to test
   php -r "preg_match('/^example\.com$/', 'example.com') ? print 'Match' : print 'No match';"
   ```

## Security Best Practices

### Production Environment

1. **Never disable CSRF in production**
2. **Use specific IP ranges for trusted proxies**
3. **Keep Cloudflare IP ranges updated**
4. **Configure trusted hosts**
5. **Enable HTTPS only**
6. **Monitor security logs**

### Regular Maintenance

1. **Update Cloudflare IPs quarterly**
   * Cloudflare occasionally adds new IP ranges
   * Subscribe to Cloudflare announcements
2. **Audit trusted proxies**
   * Review quarterly
   * Remove unused entries
   * Verify all IPs are still valid
3. **Test after updates**
   * Test forms after configuration changes
   * Verify CSRF tokens work
   * Check session persistence

## Advanced Configuration

### Custom CSRF Token TTL

Adjust CSRF token lifetime if needed:

```bash
# config/packages/security.yaml
framework:
    csrf_protection:
        token_ttl: 3600  # 1 hour
```

### Per-Environment Configuration

Use different settings for dev/staging/production:

```bash
# .env.local (not committed to git)
TRUSTED_PROXIES=127.0.0.1
DISABLE_CSRF=true  # Dev only!

# .env.production (production only)
TRUSTED_PROXIES=173.245.48.0/20,...
DISABLE_CSRF=false
```

## Related Guides

* [Trusted Proxies](/advanced-topics/security-hardening/trusted-proxies.md) - Detailed proxy configuration
* [SSL Configuration](/advanced-topics/security-hardening/ssl-configuration.md) - HTTPS setup
* [Web Server Configuration](/installation/installation/web-server-setup.md) - NGINX/Apache setup
* [Troubleshooting](https://github.com/PteroCA-Org/pteroca-homepage/blob/docs/help-and-maintenance/troubleshooting/README.md) - Common issues


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.pteroca.com/advanced-topics/security-hardening/csrf-protection.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
