mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
Nginx config, working deploy, basic theme, repo cleanup
This commit is contained in:
277
docs/SECURITY_ANALYSIS.md
Normal file
277
docs/SECURITY_ANALYSIS.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Security Analysis - Search Feature
|
||||
|
||||
## Current Security Status
|
||||
|
||||
### ✅ Protections in Place
|
||||
|
||||
1. **SQL Injection Prevention**
|
||||
- ✅ Uses PDO prepared statements
|
||||
- ✅ All parameters bound with `bindValue()`
|
||||
- ✅ No direct concatenation of user input into SQL
|
||||
- ✅ Dynamic WHERE clause built from hardcoded strings only
|
||||
|
||||
2. **XSS (Cross-Site Scripting) Prevention**
|
||||
- ✅ All output uses `htmlspecialchars()`
|
||||
- ✅ Form values escaped when displayed
|
||||
- ✅ Search results escaped before rendering
|
||||
|
||||
3. **Access Control**
|
||||
- ✅ Only published theses searchable (`is_published = 1`)
|
||||
- ✅ Uses read-only view (`v_theses_public`)
|
||||
|
||||
4. **Type Safety**
|
||||
- ✅ Year parameter uses `intval()`
|
||||
- ✅ Boolean values properly cast
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Security Vulnerabilities
|
||||
|
||||
### 1. LIKE Wildcard Injection (Low Severity)
|
||||
|
||||
**Issue:** Users can inject SQL LIKE wildcards (`%`, `_`) to match unintended patterns.
|
||||
|
||||
**Example Attack:**
|
||||
```
|
||||
Search query: "%"
|
||||
Result: Matches ALL theses (bypasses search intent)
|
||||
|
||||
Search query: "a%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%q%r%s%t%u%v%w%x%y%z"
|
||||
Result: Forces inefficient pattern matching, potential DoS
|
||||
```
|
||||
|
||||
**Current Code:**
|
||||
```php
|
||||
$bindings[':query'] = '%' . $params['query'] . '%';
|
||||
```
|
||||
|
||||
**Impact:**
|
||||
- Not SQL injection (still uses prepared statements)
|
||||
- Allows overly broad searches
|
||||
- Performance degradation with complex patterns
|
||||
- Information disclosure through pattern matching
|
||||
|
||||
**Fix:** Escape wildcards before using in LIKE:
|
||||
```php
|
||||
private function escapeLikeString($string) {
|
||||
return str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $string);
|
||||
}
|
||||
|
||||
// In query:
|
||||
$bindings[':query'] = '%' . $this->escapeLikeString($params['query']) . '%';
|
||||
|
||||
// In SQL:
|
||||
"title LIKE :query ESCAPE '\\'"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. No Input Length Validation (Medium Severity)
|
||||
|
||||
**Issue:** No limits on search string length.
|
||||
|
||||
**Example Attack:**
|
||||
```php
|
||||
// 10MB query string
|
||||
$query = str_repeat('a', 10 * 1024 * 1024);
|
||||
```
|
||||
|
||||
**Impact:**
|
||||
- Memory exhaustion
|
||||
- Database query slowdown
|
||||
- Denial of Service (DoS)
|
||||
|
||||
**Fix:** Validate input length:
|
||||
```php
|
||||
if (strlen($params['query']) > 200) {
|
||||
throw new InvalidArgumentException("Search query too long");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. No Rate Limiting (Medium Severity)
|
||||
|
||||
**Issue:** Unlimited search requests allowed.
|
||||
|
||||
**Example Attack:**
|
||||
```bash
|
||||
# Spam 10,000 requests
|
||||
for i in {1..10000}; do
|
||||
curl "http://site.com/search.php?query=test&page=$i" &
|
||||
done
|
||||
```
|
||||
|
||||
**Impact:**
|
||||
- Database overload
|
||||
- Server resource exhaustion
|
||||
- Denial of Service for legitimate users
|
||||
|
||||
**Fix:** Implement rate limiting (see solution below)
|
||||
|
||||
---
|
||||
|
||||
### 4. No Pagination Limits (Low Severity)
|
||||
|
||||
**Issue:** Users can request excessive offset values.
|
||||
|
||||
**Example:**
|
||||
```
|
||||
search.php?page=999999999
|
||||
```
|
||||
|
||||
**Impact:**
|
||||
- Database scans large result sets
|
||||
- Wasted resources on impossible pages
|
||||
|
||||
**Fix:** Validate pagination:
|
||||
```php
|
||||
$limit = max(1, min(100, intval($limit))); // Max 100 per page
|
||||
$offset = max(0, intval($offset));
|
||||
|
||||
// Optionally limit max offset
|
||||
if ($offset > 10000) {
|
||||
throw new InvalidArgumentException("Page too high");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Recommended Security Improvements
|
||||
|
||||
### Priority 1: Apply Input Validation (HIGH)
|
||||
|
||||
Use the enhanced `Database_secure.php` class which includes:
|
||||
- Wildcard escaping
|
||||
- Length validation
|
||||
- Range validation
|
||||
- ESCAPE clause in LIKE queries
|
||||
|
||||
### Priority 2: Implement Rate Limiting (MEDIUM)
|
||||
|
||||
Example using simple file-based rate limiting:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// rate_limit.php - Simple rate limiter
|
||||
|
||||
function checkRateLimit($identifier, $maxRequests = 10, $timeWindow = 60) {
|
||||
$cacheDir = __DIR__ . '/cache/rate_limit';
|
||||
if (!is_dir($cacheDir)) {
|
||||
mkdir($cacheDir, 0755, true);
|
||||
}
|
||||
|
||||
$file = $cacheDir . '/' . md5($identifier) . '.json';
|
||||
|
||||
$data = file_exists($file) ? json_decode(file_get_contents($file), true) : [];
|
||||
|
||||
// Clean old entries
|
||||
$now = time();
|
||||
$data = array_filter($data, function($timestamp) use ($now, $timeWindow) {
|
||||
return ($now - $timestamp) < $timeWindow;
|
||||
});
|
||||
|
||||
// Check if limit exceeded
|
||||
if (count($data) >= $maxRequests) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add new request
|
||||
$data[] = $now;
|
||||
file_put_contents($file, json_encode($data));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// In search.php:
|
||||
$userIP = $_SERVER['REMOTE_ADDR'];
|
||||
if (!checkRateLimit($userIP, 20, 60)) { // 20 requests per minute
|
||||
http_response_code(429);
|
||||
die('Too many requests. Please try again later.');
|
||||
}
|
||||
```
|
||||
|
||||
### Priority 3: Add Content Security Policy (LOW)
|
||||
|
||||
Add to header:
|
||||
```php
|
||||
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' cdn.jsdelivr.net;");
|
||||
header("X-Content-Type-Options: nosniff");
|
||||
header("X-Frame-Options: DENY");
|
||||
header("X-XSS-Protection: 1; mode=block");
|
||||
```
|
||||
|
||||
### Priority 4: Add Query Logging (LOW)
|
||||
|
||||
Log suspicious search patterns:
|
||||
```php
|
||||
// Detect potential attacks
|
||||
if (preg_match('/[%_]{10,}/', $params['query'])) {
|
||||
error_log("Suspicious search pattern from {$_SERVER['REMOTE_ADDR']}: {$params['query']}");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices Checklist
|
||||
|
||||
- [x] Use prepared statements (SQL injection)
|
||||
- [x] Escape output with htmlspecialchars() (XSS)
|
||||
- [ ] Escape LIKE wildcards (wildcard injection)
|
||||
- [ ] Validate input lengths (DoS)
|
||||
- [ ] Implement rate limiting (DoS)
|
||||
- [ ] Validate pagination limits (resource waste)
|
||||
- [x] Restrict to published data only (access control)
|
||||
- [ ] Add security headers (defense in depth)
|
||||
- [ ] Log suspicious activity (monitoring)
|
||||
- [ ] Use HTTPS in production (encryption)
|
||||
|
||||
---
|
||||
|
||||
## Testing Security
|
||||
|
||||
### Test 1: SQL Injection
|
||||
```bash
|
||||
# These should NOT cause errors or expose data
|
||||
curl "search.php?query=' OR 1=1--"
|
||||
curl "search.php?query='; DROP TABLE theses;--"
|
||||
curl "search.php?year=' OR '1'='1"
|
||||
```
|
||||
**Expected:** Treated as literal search strings, no SQL execution
|
||||
|
||||
### Test 2: XSS
|
||||
```bash
|
||||
curl "search.php?query=<script>alert('XSS')</script>"
|
||||
```
|
||||
**Expected:** Script tags displayed as text, not executed
|
||||
|
||||
### Test 3: Wildcard Injection
|
||||
```bash
|
||||
curl "search.php?query=%"
|
||||
```
|
||||
**Current:** Returns all results ❌
|
||||
**After fix:** Searches for literal "%" character ✅
|
||||
|
||||
### Test 4: DoS via Long Input
|
||||
```bash
|
||||
curl "search.php?query=$(python3 -c 'print("a"*100000)')"
|
||||
```
|
||||
**Current:** Processes full string ❌
|
||||
**After fix:** Rejects with error ✅
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Current Status:** The search system has **good baseline security** against SQL injection and XSS, but needs hardening for production use.
|
||||
|
||||
**Recommended Actions:**
|
||||
1. Apply wildcard escaping (use `Database_secure.php`)
|
||||
2. Add input length validation
|
||||
3. Implement rate limiting
|
||||
4. Add security headers
|
||||
5. Monitor for suspicious patterns
|
||||
|
||||
**Risk Level:**
|
||||
- Current: **Medium** (suitable for internal/development use)
|
||||
- After improvements: **Low** (production-ready)
|
||||
Reference in New Issue
Block a user