Security & Rate Limiting¶
This guide covers security features, rate limiting, and hardening recommendations for the RAG Chatbot.
Security Overview¶
The RAG Chatbot includes multiple security layers:
| Layer | Protection |
|---|---|
| Input Validation | XSS, SQL injection, prompt injection |
| File Upload | Path traversal, malicious files, code injection |
| URL Validation | SSRF attacks, internal network access |
| Rate Limiting | DoS attacks, brute force |
| Authentication | API keys, HTTP Basic Auth |
Rate Limiting¶
How It Works¶
Rate limiting uses a sliding window algorithm:
- Each request is timestamped
- Old timestamps (outside the window) are pruned
- If remaining requests > 0, the request proceeds
- Otherwise, HTTP 429 is returned with
Retry-Afterheader
Endpoint Limits¶
| Endpoint | Limit | Window | Identifier |
|---|---|---|---|
/chat | 30 requests | 60 seconds | Session ID + IP |
/upload.php | 10 requests | 60 seconds | IP address |
/api-debug/logs | 5 auth attempts | 60 seconds | IP address |
Response Headers¶
All rate-limited endpoints return these headers:
When the limit is exceeded:
HTTP/1.1 429 Too Many Requests
Retry-After: 45
Content-Type: application/json
{"error": "Rate limit exceeded", "retry_after": 45}
Customizing Limits¶
To adjust rate limits, modify the constants in the controller files:
Chat endpoint (src/Http/ChatController.php):
private const MAX_REQUESTS_PER_MINUTE = 30;
private const RATE_LIMIT_WINDOW = 60;
private const MAX_MESSAGE_LENGTH = 10000;
Upload endpoint (public/upload.php):
Authentication¶
Upload API Key¶
Protect the upload endpoint with an API key:
- Set the key in
.env:
- Include the key in requests:
curl -X POST https://your-domain.com/chatbot/public/upload.php \
-H "X-API-Key: your-random-secret-key" \
-F "file=@document.pdf"
Generate a secure key:
Debug Endpoint Authentication¶
The API debug endpoint uses HTTP Basic Authentication:
- Configure in
.env:
- Access with credentials:
IP Whitelist¶
Restrict debug access to specific IPs:
# Single IP
API_DEBUG_IP_WHITELIST=192.168.1.100
# Multiple IPs
API_DEBUG_IP_WHITELIST=192.168.1.100,10.0.0.50
# CIDR notation
API_DEBUG_IP_WHITELIST=192.168.1.0/24,10.0.0.0/8
Lockout Protection¶
After 10 failed authentication attempts, the IP is locked out for 5 minutes:
Input Validation¶
Message Sanitization¶
User messages are sanitized to prevent prompt injection:
- Suspicious patterns are wrapped in
[TEXT: ...]markers - LLM is instructed to treat context as data, not commands
- Context is separated with clear delimiters
Detected patterns include:
- "Ignore previous instructions"
- "System prompt" references
- Role-playing attempts ("You are now...")
- Code injection attempts
File Upload Validation¶
Uploaded files are validated for:
| Check | Protection |
|---|---|
| Extension whitelist | Block executable files |
| Magic byte verification | Detect disguised files |
| PHP code detection | Prevent code execution |
| Path traversal | Block ../ in filenames |
| Null byte injection | Block %00 attacks |
| Size limits | Prevent DoS via large files |
File Size Limit Implementation:
The maximum upload size is controlled by the MAX_UPLOAD_SIZE_MB environment variable (default: 100 MB).
- Configuration: Set in
.envfile asMAX_UPLOAD_SIZE_MB=100 - Read in:
public/upload.php:615- converts MB to bytes - Enforced by:
src/Services/FileUploadValidator.php:88- rejects oversized files
// upload.php - Line 615
$maxSize = (int) ($_ENV['MAX_UPLOAD_SIZE_MB'] ?? 100) * 1024 * 1024;
// FileUploadValidator.php - Line 88
if ($file['size'] > $maxSizeBytes) {
return ['valid' => false, 'error' => 'File size exceeds limit'];
}
PHP Configuration
Also ensure your PHP settings allow large uploads:
Blocked extensions:
URL Validation (SSRF Protection)¶
Media URLs are validated to prevent SSRF attacks:
| Check | Protection |
|---|---|
| Protocol whitelist | Only HTTP/HTTPS allowed |
| Private IP blocking | No 10.x, 172.16.x, 192.168.x |
| Localhost blocking | No 127.x or localhost |
| Cloud metadata blocking | No 169.254.169.254 |
| DNS rebinding protection | Verify resolved IP |
| Port restrictions | Block sensitive ports |
Security Headers¶
All responses include security headers:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
The X-Powered-By header is removed to hide PHP version.
Adding More Headers¶
For additional protection, add headers in Apache:
# In httpd.conf or .htaccess
Header always set Content-Security-Policy "default-src 'self'"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
Or in Nginx:
add_header Content-Security-Policy "default-src 'self'";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
Conversation Limits¶
To prevent DoS through resource exhaustion:
| Limit | Value | Purpose |
|---|---|---|
| Message length | 10,000 chars | Prevent oversized requests |
| Total messages | 500 per session | Limit database growth |
| Summary length | 8,000 chars | Cap memory usage |
When limits are reached, users are prompted to start a new conversation.
Production Hardening¶
Disable Debug Features¶
In production, always disable:
Use HTTPS¶
Always use TLS in production:
# Install certbot
sudo dnf install certbot python3-certbot-apache
# Obtain certificate
sudo certbot --apache -d your-domain.com
# Auto-renewal
sudo systemctl enable certbot-renew.timer
Database Security¶
- Use strong passwords - Generate with
openssl rand -base64 32 - Restrict access - Only allow connections from web server
- Encrypt connections - Enable SSL in PostgreSQL
# In postgresql.conf
ssl = on
ssl_cert_file = '/path/to/server.crt'
ssl_key_file = '/path/to/server.key'
File Permissions¶
# Secure .env file
chmod 600 /var/www/chatbot/.env
# Restrict log directory
chmod 750 /var/www/chatbot/logs
chown apache:apache /var/www/chatbot/logs
# Make application files read-only
find /var/www/chatbot -type f -exec chmod 644 {} \;
find /var/www/chatbot -type d -exec chmod 755 {} \;
SELinux (RHEL/AlmaLinux)¶
Keep SELinux enabled and configure properly:
# Allow network connections
setsebool -P httpd_can_network_connect 1
setsebool -P httpd_can_network_connect_db 1
# Set proper contexts
semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/chatbot/logs(/.*)?"
restorecon -Rv /var/www/chatbot/logs
Firewall Rules¶
Only expose necessary ports:
# AlmaLinux/RHEL (firewalld)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
# Ubuntu (ufw)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
# CSF (ConfigServer Firewall)
# Edit /etc/csf/csf.conf and ensure 80,443 are in TCP_IN:
sudo nano /etc/csf/csf.conf
# TCP_IN = "20,21,22,25,53,80,110,143,443,465,587,993,995"
# Restart CSF to apply changes
sudo csf -r
# Verify ports are open
sudo csf -p
Monitoring & Logging¶
Application Logs¶
Errors are logged to:
- PHP error log:
/var/log/php-fpm/www-error.log - Apache error log:
/var/log/httpd/chatbot-error.log - Application logs:
/var/www/chatbot/logs/
Security Monitoring¶
Monitor for:
- Rate limit triggers - Excessive 429 responses
- Failed auth attempts - Watch API debug auth logs
- Unusual file uploads - Large files or unusual types
- Error spikes - May indicate attack attempts
Log Rotation¶
Configure logrotate for application logs:
# /etc/logrotate.d/chatbot
/var/www/chatbot/logs/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 644 apache apache
}
Security Checklist¶
Before going to production:
- [ ] HTTPS enabled with valid certificate
- [ ] Strong database password set
- [ ]
API_DEBUG_LOGGING_ENABLED=false - [ ]
UPLOAD_API_KEYset if uploads should be restricted - [ ] SELinux enabled and configured
- [ ] Firewall configured
- [ ] File permissions restricted
- [ ]
.envfile secured (chmod 600) - [ ] Security headers configured
- [ ] Log rotation configured
- [ ] Monitoring in place
Reporting Vulnerabilities¶
If you discover a security vulnerability:
- Do not open a public issue
- Email security@your-organization.com
- Include steps to reproduce
- Allow time for a fix before disclosure