🔒 Security Measures · Sandy's Media Hub
Technical Report · 14 September 2025 · Version 1.0
This document explains the five core security measures implemented in the CMS, how they work technically, and how they align with UK GDPR requirements.
| Measure | Protects Against | GDPR Articles |
|---|---|---|
| 1. CSRF Tokens | Cross-site request forgery | Art. 5(1)(f), Art. 32 |
| 2. Login Throttling | Brute force attacks | Art. 5(1)(f), Art. 32 |
| 3. Session Rotation | Session fixation/hijacking | Art. 5(1)(f), Art. 32 |
| 4. Password Hashing (bcrypt) | Credential theft | Art. 5(1)(f), Art. 32 |
| 5. Activity Logging | Unauthorised access, audit trail | Art. 5(2), Art. 24, Art. 30 |
1. CSRF Tokens
GDPR Art. 5(1)(f), Art. 32
What It Is
Cross-Site Request Forgery (CSRF) protection ensures that forms can only be submitted from our own site, not from malicious external sites.
How It Works (from your code)
// On page load:
if (!isset($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(random_bytes(32));
}
$csrf = $_SESSION['csrf'];
// In form:
<input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf) ?>">
// On submission:
$posted_csrf = $_POST['csrf'] ?? '';
if (!hash_equals($csrf, $posted_csrf)) {
$error = 'Security token invalid';
}
Technical Details
random_bytes(32)generates cryptographically secure random tokens (64 hex characters)hash_equals()prevents timing attacks by using constant-time comparison- Token stored in session, tied to the specific user's browser
GDPR Alignment
Article 32 requires "appropriate technical measures" to ensure security. CSRF tokens prevent attackers from using authenticated sessions to modify data without consent.
2. Login Throttling
GDPR Art. 5(1)(f), Art. 32
What It Is
Limits the number of failed login attempts to prevent brute-force password guessing.
How It Works (from your code)
$throttle_key = 'login_attempts';
$throttle_window = 300; // 5 minutes
$max_attempts = 8;
// Clean old attempts
$cutoff = time() - $throttle_window;
$_SESSION[$throttle_key] = array_filter($_SESSION[$throttle_key], fn($ts) => $ts > $cutoff);
// Check throttle
if (count($_SESSION[$throttle_key]) >= $max_attempts) {
$error = 'Too many attempts. Please wait.';
}
// On failed login:
$_SESSION[$throttle_key][] = time();
// On success:
$_SESSION[$throttle_key] = []; // Clear attempts
Technical Details
- 8 attempts maximum per 5-minute window
- Session-based tracking (per browser, not per IP - avoids blocking shared networks)
- Failed attempts automatically expire after window
GDPR Alignment
Prevents unauthorised access to personal data by blocking automated brute-force attacks. The attempt count is stored only temporarily and not linked to other personal data.
3. Session Rotation
GDPR Art. 5(1)(f), Art. 32
What It Is
Regenerates the session ID after successful login to prevent session fixation attacks.
How It Works (from your code)
// After password verification:
session_regenerate_id(true);
Technical Details
- Creates a completely new session ID while preserving session data
trueparameter deletes the old session immediately- Prevents attackers from forcing a user to use a known session ID
GDPR Alignment
Protects session integrity, ensuring that authenticated access to personal data cannot be hijacked using pre-set session IDs.
4. Password Hashing (bcrypt)
GDPR Art. 5(1)(f), Art. 32
What It Is
Passwords are never stored in plain text. They are hashed using bcrypt with automatic salting.
How It Works (from your code)
// Registration:
$hash = password_hash($password, PASSWORD_DEFAULT);
// Login:
if (password_verify($password, $user['password_hash'])) {
// success
}
Technical Details
PASSWORD_DEFAULTcurrently uses bcrypt (PHP default)- Automatic random salt per password (prevents rainbow table attacks)
- bcrypt is deliberately slow (work factor adjustable) to resist brute-force
- Even if database is compromised, passwords cannot be reversed
GDPR Alignment
Article 32 requires pseudonymisation and encryption of personal data where appropriate. Hashed passwords are a form of pseudonymisation - the original password cannot be retrieved, protecting users even in a data breach.
5. Activity Logging
GDPR Art. 5(2), Art. 24, Art. 30
What It Is
Every important action (login success/fail, registration, errors) is logged with metadata for audit trails.
How It Works (from your code)
// On login success:
logActivity('login_success', [
'module' => 'auth',
'status' => 'success',
'details' => ['email' => $email, 'role' => $user['role']]
]);
// On login failure:
logActivity('login_failed', [
'module' => 'auth',
'status' => 'failed',
'details' => ['email' => $email, 'reason' => $msg]
]);
// On registration:
logActivity('register_request', [
'module' => 'auth',
'status' => 'pending',
'details' => ['email' => $email, 'profile_type' => $ptype]
]);
Technical Details
- Logs stored in
activity_logstable - Retained for 365 days (as per Privacy Policy)
- Includes: timestamp, user ID (if logged in), action, module, status, IP address, user agent
- IP addresses are stored but not publicly accessible
GDPR Alignment
Multiple GDPR requirements are satisfied:
- Article 5(2) (Accountability): You can demonstrate compliance by showing who did what and when
- Article 24: Appropriate technical measures are evidenced through logs
- Article 30 (Records of processing): Activity logs form part of your processing records
- Security monitoring: Failed login attempts alert you to potential breaches
Note: Logs are automatically pruned after 365 days, matching our Privacy Policy commitment.
Summary: Security & GDPR Alignment
| Requirement | How Sandy's Media Hub Meets It |
|---|---|
| Art. 5(1)(f) - Integrity & confidentiality | All five measures work together to prevent unauthorised access to personal data |
| Art. 5(2) - Accountability | Activity logging provides full audit trail of who accessed what and when |
| Art. 24 - Responsibility of controller | Technical measures demonstrate appropriate security controls are in place |
| Art. 30 - Records of processing | Activity logs serve as machine-readable records of processing activities |
| Art. 32 - Security of processing | All five measures are explicitly listed as appropriate technical measures |
This technical report is based on the actual codebase of Sandy's Media Hub and aligns with the Privacy Policy effective 14 September 2025.