Project Overview
What is CoreAccess-ID?
CoreAccess-ID is a production-grade authentication system I built from scratch to demonstrate enterprise security practices. The architecture uses defense-in-depth with isolated logging to an external IDS for threat detection and monitoring. It's currently running at auth.joshcybsec.work as a fully functional demo.
Key Achievements
- Implemented WebAuthn/FIDO2 passwordless authentication with biometric support
- Built a complete MFA system using TOTP and backup codes
- Designed isolated logging that forwards security events to an external IDS for threat detection
- Security audit identified 20 vulnerabilities (8 critical, 5 high, 7 medium) - all remediated
- Implemented comprehensive audit logging with IP tracking and severity classification
- Added GDPR-compliant data export and account deletion
Implemented Security Features
WebAuthn/Passkeys
Passwordless authentication with FIDO2 security keys, Touch ID, Face ID, and Windows Hello support.
Password Security
Argon2id hashing with AUTH_PEPPER, HaveIBeenPwned breach detection, and 10+ character minimum.
Multi-Factor Auth
TOTP-based 2FA with Google Authenticator, backup codes, and device management.
Rate Limiting
Intelligent rate limiting on login, registration, and API endpoints with exponential backoff.
Secure Sessions
HttpOnly, Secure, SameSite=Lax cookies with device fingerprinting and geolocation tracking.
Audit Logging
Comprehensive logging of all authentication events with IP tracking and severity levels.
CSRF Protection
Timing-attack resistant CSRF tokens using hash_equals() on all state-changing operations.
Account Lockout
Temporary lockout after 10 failed attempts with automatic unlock and secure recovery.
Isolated Logging
Security events forwarded to external IDS device for centralized threat detection and analysis.
Bot Protection
Cloudflare Turnstile CAPTCHA on suspicious login attempts with k-Anonymity privacy.
Email Verification
Secure email verification with time-limited tokens and professional email templates.
API Key Management
Generate and manage API keys for programmatic access with proper hashing.
System Architecture
Interactive System Architecture
Hover over components to learn more
Isolated Logging & IDS Integration
CoreAccess-ID uses a segmented security architecture with external monitoring:
- Security events forward to an isolated IDS on a separate network segment
- Centralized log aggregation enables cross-system correlation and threat intelligence
- Failed logins, MFA challenges, and account lockouts are tracked in real-time
- The external IDS watches for brute force attacks, credential stuffing, and unusual behavior
- Log isolation prevents attackers from tampering with audit trails if the main system is compromised
- The monitoring layer runs independently from the authentication layer for defense-in-depth
Trust Zones
Untrusted Zone (Public Internet)
All incoming traffic is untrusted. No direct access to application servers. All requests filtered through Cloudflare.
Edge Zone (Cloudflare)
DDoS mitigation, TLS termination, WAF rules. Acts as first line of defense before traffic reaches origin.
DMZ (Nginx Reverse Proxy)
Security headers injected, rate limiting enforced, request validation. No direct PHP access from edge.
Application Zone (PHP-FPM)
Business logic execution, session management, authentication decisions. Runs as non-root with minimal privileges.
Data Zone (MariaDB/Redis)
Sensitive data storage. No external network access. Only reachable from application zone via Docker network.
Monitoring Zone (External IDS)
Isolated log aggregation. Separate network segment. Cannot be reached from application zone - only receives logs.
Data Flow Analysis
Credential Flow
Created: Client-side (user input) → Transmitted: TLS 1.3 encrypted → Processed: PHP validates, hashes with Argon2id + pepper → Stored: MariaDB (hash only) → Never: Logged, cached, or stored in plaintext
Session Token Flow
Created: PHP generates 32-byte random token on successful auth → Stored: MariaDB sessions table with device fingerprint → Transmitted: HttpOnly, Secure, SameSite=Lax cookie → Validated: Every request checks token + fingerprint match → Destroyed: Logout, expiry, or revocation
CSRF Token Flow
Created: Per-session, 32 random bytes → Stored: Server-side session → Transmitted: Hidden form field or header → Validated: hash_equals() comparison (timing-attack resistant) → Lifetime: 1 hour, regenerated on sensitive operations
Audit Event Flow
Created: PHP logs event with IP, user agent, geolocation, severity → Stored: MariaDB audit_log table → Forwarded: External IDS via isolated channel → Retention: Indefinite for security analysis → Access: Admin-only interface
Control Mapping
Each security control mapped to the threat it mitigates, where it's enforced, and failure behavior.
Argon2id + Pepper
Mitigates: Credential theft, rainbow tables, DB breach
Enforced: PHP password.php
On failure: Auth fails closed - no fallback hashing
Rate Limiting
Mitigates: Brute force, credential stuffing, DoS
Enforced: Redis sliding window
On failure: Redis down = fail open with degraded protection (logged)
CSRF Tokens
Mitigates: Cross-site request forgery
Enforced: All POST endpoints
On failure: Request rejected with 403
Device Fingerprinting
Mitigates: Session hijacking, token theft
Enforced: Session validation
On failure: Fingerprint mismatch = session invalidated, event logged
MFA (TOTP)
Mitigates: Account takeover, phishing
Enforced: Post-password verification
On failure: Wrong code = attempt logged, lockout after threshold
Account Lockout
Mitigates: Brute force on specific accounts
Enforced: Auth logic
On failure: Exponential backoff (15min → 1hr → 4hr → 24hr)
Failure Mode Analysis
How the system behaves when components fail - critical for understanding resilience.
If Redis Goes Down
- Impact: Rate limiting degrades, session cache unavailable
- Behavior: System continues with DB-only session validation
- Risk: Increased brute force exposure until Redis recovers
- Detection: Health check fails, alert triggered
If MariaDB Goes Down
- Impact: Complete auth failure - no user validation possible
- Behavior: All login attempts fail with error message
- Risk: Denial of service (availability impact, not security)
- Detection: Health check fails, immediate alert
If Cloudflare Is Bypassed
- Impact: Direct exposure to DDoS, no WAF protection
- Behavior: Nginx rate limiting still active, but reduced capacity
- Risk: Higher attack surface, potential resource exhaustion
- Mitigation: Origin IP not publicly known, firewall rules
If External IDS Is Unreachable
- Impact: Security events not forwarded for analysis
- Behavior: Local logging continues, events queued
- Risk: Delayed threat detection (not auth failure)
- Detection: Log forwarding health check
Threat Model
Protected Assets
- User Credentials: Passwords (hashed), MFA secrets, backup codes
- Session Tokens: Authentication state, device bindings
- User Data: Email addresses, account metadata, preferences
- Audit Logs: Security events, access history, IP addresses
- API Keys: Programmatic access credentials
Threat Actors & Mitigations
- Credential Stuffing: Rate limiting + HIBP breach check + account lockout
- Session Hijacking: Device fingerprinting + secure cookies + HTTPS-only
- CSRF Attacks: Per-session tokens + SameSite cookies + timing-safe comparison
- Brute Force: Exponential backoff + CAPTCHA trigger + IP blocking
- Phishing: WebAuthn/passkeys (phishing-resistant) + MFA requirement
- SQL Injection: Prepared statements everywhere + input validation
- Privilege Escalation: Role checks on every request + audit logging
- Log Tampering: External IDS on isolated segment + immutable forwarding
Explicit Non-Goals
- Protection against compromised client devices (out of scope)
- Protection against insider threats with DB access (trust boundary)
- Availability guarantees beyond single-node deployment
- Compliance certifications (SOC2, ISO 27001) - this is a demo system
Security Audit Results
Remediation Summary
Security review conducted January 2026. All findings remediated.
| ID | Severity | Finding | OWASP Category | Status |
|---|---|---|---|---|
| CA-001 | CRITICAL | CSRF token timing attack vulnerability | A01:2025 Broken Access Control | ✓ Fixed |
| CA-002 | CRITICAL | Missing AUTH_PEPPER on password verify | A07:2025 Authentication Failures | ✓ Fixed |
| CA-003 | CRITICAL | Session variable naming inconsistency | A07:2025 Authentication Failures | ✓ Fixed |
| CA-004 | HIGH | Missing CSRF on account deletion | A01:2025 Broken Access Control | ✓ Fixed |
| CA-005 | HIGH | Incorrect audit event types | A09:2025 Logging & Alerting Failures | ✓ Fixed |
| CA-006 | MEDIUM | Hardcoded security whitelists | A02:2025 Security Misconfiguration | ✓ Fixed |
| CA-007 | MEDIUM | Missing password change timestamp | A07:2025 Authentication Failures | ✓ Fixed |
+ 13 additional findings (5 critical, 3 high, 5 medium) - all remediated. Full report available on request.
Remediation Details
- CA-001: Replaced == with hash_equals() for constant-time CSRF comparison, preventing timing oracle attacks
- CA-002: Added AUTH_PEPPER concatenation to all password_verify() calls across 4 endpoints
- CA-003: Standardized $_SESSION['remember_me'] naming, fixing remember-me token persistence bug
- CA-004: Added CSRF token validation to /api/delete-account.php before processing deletion
- CA-005: Corrected audit event types from generic to specific (api_key_created, api_key_deleted)
Technical Highlights
k-Anonymity Privacy Implementation
Why this matters: Checking passwords against breach databases could expose user credentials to third parties. k-Anonymity solves this by ensuring the actual password is never transmitted.
Threat prevented: Man-in-the-middle interception of password during breach check, malicious API provider logging passwords, network traffic analysis revealing credentials.
// HaveIBeenPwned Password Check - Zero Knowledge Protocol 1. Hash password with SHA-1 locally: 21BD12DC183F740EE76F27B78EB39C8AD972A757 2. Send ONLY first 5 chars to API: 21BD1 3. API returns ~800 hash suffixes (cannot reverse to determine which was queried) 4. Check locally if full hash matches any suffix 5. ✓ Password never leaves the client 6. ✓ API cannot determine which password was checked 7. ✓ Network observers see only partial hash (useless without full value)
Data that never leaves CoreID: Plaintext passwords, full password hashes, MFA secrets, session tokens. All sensitive operations happen server-side.
Docker Security Hardening
- All containers run with CPU/memory/PID limits
- Principle of Least Privilege: PHP-FPM runs as non-root user with minimal permissions
- Health checks with automatic recovery
- Isolated Docker network (no external exposure)
- Resource limits prevent DoS attacks
Session Management
- Device fingerprinting (IP + User-Agent hash)
- Geolocation tracking (city/country via ip-api.com)
- Multi-device session tracking with custom naming
- Suspicious activity detection (fingerprint mismatch)
- "Remember me" with 30-day lifetime
- Automatic cleanup of expired sessions
Live Demo
🚀 Live Demo
CoreAccess-ID is running and ready to explore:
- URL: auth.joshcybsec.work
- Create an account or use the demo credentials
- Test WebAuthn with Touch ID, Face ID, or a security key
- Set up MFA with Google Authenticator
- Generate API keys and test programmatic access
⚠️ Security Notice
This is a fully functional demo with real security controls. All activity is logged and monitored. Don't use actual passwords or personal information when testing.
Lessons Learned
Key Takeaways
- Security is iterative: The audit found 20 issues, proving continuous review matters
- Defense in depth: Multiple layers provide redundancy when one fails
- User experience matters: The best security is invisible (WebAuthn, SameSite cookies)
- Documentation is critical: Wrote 10 docs (~2,400 lines) for long-term maintainability
- Privacy-preserving security: k-Anonymity provides security without exposing user data
- Never trust input: Validate, sanitize, and use prepared statements everywhere
- Graceful degradation: API failures shouldn't lock out legitimate users