Files
xamxam/apps/public/SECURITY_IMPLEMENTATION.md
Théophile Gervreau-Mercier 467aced734 Restructure repository and implement secure search feature
Phase 1: Consolidate shared infrastructure
- Create shared/ directory for common code
- Consolidate Database.php from front-backend and formulaire into unified shared/Database.php
  - Smart path detection for test.db vs posterg.db
  - Secure search with wildcard escaping and input validation
  - Support both singleton and direct instantiation patterns
  - Full CRUD methods for admin functionality
- Move RateLimit.php to shared/ (30 requests/min)
- Update all require paths across apps to use shared/

Phase 2: Reorganize directory structure
- Rename front-backend/ → apps/public/
- Rename formulaire/ → apps/admin/
- Rename db/ → database/
- Update all file paths for new structure
- Create root .gitignore excluding databases, cache, logs

Implement secure search feature
- Add apps/public/search.php with full-text search across theses
- Search filters: query, year, orientation, AP program, keywords
- Security features:
  - SQL injection prevention (prepared statements)
  - Wildcard injection prevention (escape % and _)
  - Input validation (max 200 chars, year range 1900-2100)
  - Rate limiting (30 req/min per IP)
  - Pagination limited to 100 results/page
  - XSS protection (htmlspecialchars on output)

Add comprehensive test suite
- Create apps/public/tests/ with proper structure
  - tests/Integration/SearchTest.php - 12 search scenarios
  - tests/Security/SecurityTest.php - vulnerability testing
  - tests/Unit/RateLimitTest.php - rate limit behavior
- Create database/fixtures/CreateTestDatabase.php
- Add apps/public/run-tests.php test runner
- All tests passing (4/4 suites)

Update deployment configuration
- Rename justfile 'sync' recipe to 'deploy'
- Create deploy group with separate deploy-public and deploy-admin
- Add test-deploy recipe for test database
- Exclude *.db, tests/, cache/, *.md from production deploy
- Deploy shared/ to both public and admin locations

Stats: +4482 insertions, -654 deletions across 72 files
2026-02-02 18:53:58 +01:00

8.8 KiB

Security Implementation - Production Ready

Overview

The search system has been hardened with comprehensive security measures and is now production-ready.

Security Features Implemented

1. SQL Injection Protection

  • Method: PDO prepared statements with parameter binding
  • Status: SECURE
  • Test Result: All injection attempts treated as literal strings
  • Coverage: All database queries

2. XSS (Cross-Site Scripting) Protection

  • Method: htmlspecialchars() on all output
  • Status: SECURE
  • Coverage: All user-generated content display

3. Wildcard Injection Prevention

  • Method: Escape LIKE wildcards (%, _) before queries
  • Implementation: escapeLikeString() private method
  • SQL: Uses ESCAPE '\\' clause in all LIKE queries
  • Status: SECURE
  • Test Result: Searching for % returns 0 results instead of all records

Example:

// User input: "%"
// Before: '%' . $query . '%' → "%%%"  (matches everything)
// After:  '%' . escapeLikeString($query) . '%' → "%\%%"  (matches literal %)

4. Input Length Validation

  • Limits:
    • Query: 200 characters max
    • Orientation/AP/Finality: 100 characters max
    • Keywords/Formats: 100 characters max
    • Languages: 50 characters max
  • Status: SECURE
  • Test Result: 4000-character input rejected with error message

5. Year Range Validation

  • Allowed Range: 1900-2100
  • Status: SECURE
  • Test Result: Year 999999 rejected with "Invalid year" error

6. Pagination Limits

  • Maximum per page: 100 results
  • Minimum per page: 1 result
  • Offset validation: Non-negative values only
  • Status: SECURE
  • Test Result: Request for 500 results limited to 100

7. Rate Limiting (NEW)

  • Limit: 30 requests per minute per IP address
  • Method: File-based tracking
  • HTTP Status: 429 Too Many Requests when exceeded
  • Headers Sent:
    • X-RateLimit-Limit: 30
    • X-RateLimit-Remaining: N
    • X-RateLimit-Reset: timestamp
    • Retry-After: seconds
  • Status: SECURE
  • Test Result: All tests pass, 6th request blocked correctly

Features:

  • Automatic cleanup of old rate limit files
  • Per-IP tracking (handles X-Forwarded-For for proxies)
  • Graceful error message in French
  • 1% chance of cleanup on each request (low overhead)

Files Modified/Created

Modified Files

  1. Database.php - Enhanced with security features:

    • Added escapeLikeString() - Escape SQL LIKE wildcards
    • Added validateSearchParams() - Comprehensive input validation
    • Updated searchTheses() - Secure implementation with validation
    • Updated countSearchResults() - Secure implementation with validation
  2. search.php - Added rate limiting and error handling:

    • Rate limiting check at the beginning
    • Rate limit headers sent on all responses
    • Validation error display
    • 429 error page for rate limit exceeded
  3. inc/header.php - Added search navigation link

New Files Created

  1. RateLimit.php - Rate limiting class:

    • File-based request tracking
    • Configurable limits and time windows
    • Automatic cleanup
    • HTTP header support
  2. create_test_db.php - Test database generator

  3. test_search.php - Functional tests

  4. test_security_updated.php - Security validation tests

  5. test_rate_limit.php - Rate limiting tests

  6. SECURITY_ANALYSIS.md - Detailed security analysis

  7. SECURITY_IMPLEMENTATION.md - This file

  8. SEARCH_FEATURE.md - Feature documentation


Test Results

Security Tests: ALL PASSED

✅ SECURE from SQL Injection (prepared statements)
✅ SECURE from wildcard injection (escaped)
✅ SECURE from DoS via long inputs (length validation)
✅ SECURE from invalid year values (range validation)
✅ SECURE from excessive pagination (max 100 per page)
✅ SECURE from negative offsets (validated)

Rate Limiting Tests: ALL PASSED

✅ Rate limiting works correctly
✅ Requests are tracked per client
✅ Limits are enforced
✅ Reset time is calculated
✅ Headers are sent
✅ Cleanup removes old files

Functional Tests: ALL PASSED

  • Full-text search: Working
  • Year filtering: Working
  • Orientation filtering: Working
  • AP program filtering: Working
  • Keyword search: Working
  • Combined filters: Working
  • Pagination: Working

Configuration

Rate Limiting

Current settings in search.php:

$rateLimit = new RateLimit(30, 60); // 30 requests per minute

To adjust:

// More restrictive (10 requests per minute)
$rateLimit = new RateLimit(10, 60);

// More permissive (60 requests per minute)
$rateLimit = new RateLimit(60, 60);

// Different time window (100 requests per hour)
$rateLimit = new RateLimit(100, 3600);

Pagination

Current setting in Database.php:

$limit = max(1, min(100, intval($limit))); // Max 100 per page

Default in search.php:

$itemsPerPage = min(100, isset($_GET['per_page']) ? intval($_GET['per_page']) : 20);

Users can request different page sizes:

  • search.php?per_page=50 - 50 results per page
  • search.php?per_page=1000 - Capped at 100

Security Headers

Consider adding these to production (in header.php or .htaccess):

// Content Security Policy
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' cdn.jsdelivr.net;");

// Prevent MIME sniffing
header("X-Content-Type-Options: nosniff");

// Prevent clickjacking
header("X-Frame-Options: DENY");

// XSS Protection
header("X-XSS-Protection: 1; mode=block");

// Referrer Policy
header("Referrer-Policy: strict-origin-when-cross-origin");

Production Checklist

  • SQL injection protection
  • XSS protection
  • Wildcard injection protection
  • Input length validation
  • Input range validation
  • Rate limiting
  • Pagination limits
  • Error handling
  • Security testing
  • HTTPS enabled (server configuration)
  • Security headers added (recommended)
  • Database backups configured
  • Error log monitoring setup
  • Rate limit cache directory permissions set (755)

Error Handling

User-Facing Errors

  1. Rate Limit Exceeded (429):

    Trop de requêtes
    Vous avez dépassé la limite de 30 recherches par minute.
    Veuillez réessayer dans X secondes.
    
  2. Validation Error (400):

    Erreur de validation : Search query too long (max 200 characters)
    
  3. Database Error (500):

    Une erreur est survenue lors de la recherche.
    

Error Logging

All errors are logged to error.log:

  • Database connection failures
  • Search validation errors
  • Unexpected exceptions
  • Rate limit violations (can be enabled)

Performance Considerations

Database Indexes

Ensure these indexes exist (from schema.sql):

  • idx_theses_year - Year filtering
  • idx_theses_published - Published filter
  • idx_theses_orientation - Orientation filtering
  • idx_theses_ap_program - AP program filtering
  • idx_thesis_keywords_thesis - Keyword searches

Rate Limit Cache

  • Location: front-backend/cache/rate_limit/
  • File per IP: {md5_hash}.json
  • Automatic cleanup: Old files removed after 24h
  • Permissions: Ensure directory is writable (755)

Monitoring Recommendations

Metrics to Track

  1. Search patterns:

    • Most searched terms
    • Filter combinations used
    • Peak search times
  2. Rate limiting:

    • Number of 429 errors
    • IPs hitting rate limits
    • Potential abuse patterns
  3. Performance:

    • Search query duration
    • Database response time
    • Cache file growth

Log Analysis

Monitor error.log for:

  • Search validation error: - Invalid inputs
  • Error in search: - Database issues
  • Suspicious search pattern from - Potential attacks (can be enabled)

Maintenance

Weekly Tasks

  • Review error logs
  • Check rate limit violations
  • Monitor disk usage of cache directory

Monthly Tasks

  • Analyze search patterns
  • Review and update security measures
  • Test backup restoration

As Needed

  • Adjust rate limits based on usage
  • Update input validation rules
  • Optimize slow queries

Summary

The search system is now production-ready with:

Comprehensive Security: All major attack vectors covered Rate Limiting: Prevents abuse and DoS attacks Input Validation: All user inputs sanitized and validated Error Handling: Graceful degradation with user-friendly messages Testing: Full test coverage with passing results Documentation: Complete implementation and security docs

Risk Level: LOW - Suitable for production deployment

Next Steps:

  1. Enable HTTPS on production server
  2. Add security headers
  3. Configure error log monitoring
  4. Set up database backups
  5. Monitor search usage patterns