Audit Logging
Audit logging is a critical component of HIPAA compliance and healthcare data security. SecureHealth implements comprehensive audit logging that tracks every access to Protected Health Information (PHI) and system activities.
What is Audit Logging?
Audit logging in SecureHealth captures:
- Who accessed the data (user identity)
- What data was accessed (resource and fields)
- When the access occurred (timestamp)
- Where the access originated (IP address, location)
- Why the access was made (action context)
- How the access was performed (method, device)
Audit Log Structure
Core Audit Log Fields
{
"id": "audit_12345",
"timestamp": "2024-01-15T10:30:00Z",
"user": {
"id": "user_456",
"email": "doctor@securehealth.dev",
"role": "ROLE_DOCTOR",
"department": "Cardiology"
},
"action": "VIEW_PATIENT",
"resource": {
"type": "Patient",
"id": "patient_789",
"patientId": "PAT-12345",
"fields": ["firstName", "lastName", "medicalHistory"]
},
"request": {
"method": "GET",
"url": "/api/patients/PAT-12345",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"sessionId": "session_abc123"
},
"result": {
"status": "SUCCESS",
"httpCode": 200,
"responseTime": 150
},
"compliance": {
"hipaaCompliant": true,
"auditRequired": true,
"retentionPeriod": "7_years"
},
"metadata": {
"encryptionStatus": "ENCRYPTED",
"dataClassification": "PHI",
"accessReason": "Patient care"
}
}
Types of Audit Events
1. Authentication Events
{
"action": "LOGIN",
"details": {
"loginMethod": "PASSWORD",
"success": true,
"failureReason": null
}
}
{
"action": "LOGIN_FAILED",
"details": {
"loginMethod": "PASSWORD",
"success": false,
"failureReason": "INVALID_CREDENTIALS",
"attemptCount": 3
}
}
2. Data Access Events
{
"action": "VIEW_PATIENT",
"resource": {
"type": "Patient",
"id": "patient_789",
"fields": ["firstName", "lastName", "dateOfBirth"]
}
}
{
"action": "SEARCH_PATIENTS",
"resource": {
"type": "Patient",
"searchCriteria": {
"firstName": "John",
"lastName": "Doe"
},
"resultCount": 5
}
}
3. Data Modification Events
{
"action": "UPDATE_PATIENT",
"resource": {
"type": "Patient",
"id": "patient_789",
"fields": ["medicalHistory", "prescriptions"]
},
"changes": {
"medicalHistory": {
"old": "Previous medical history...",
"new": "Updated medical history..."
}
}
}
4. Administrative Events
{
"action": "CREATE_USER",
"resource": {
"type": "User",
"id": "user_new",
"email": "newuser@securehealth.dev",
"role": "ROLE_NURSE"
}
}
{
"action": "CHANGE_PERMISSIONS",
"resource": {
"type": "User",
"id": "user_456",
"oldRole": "ROLE_NURSE",
"newRole": "ROLE_DOCTOR"
}
}
Implementation in SecureHealth
Audit Logger Service
<?php
namespace App\Service;
use App\Entity\AuditLog;
use App\Entity\User;
use Symfony\Component\HttpFoundation\Request;
class AuditLogger
{
private $auditRepository;
private $encryptionService;
public function logAccess(User $user, string $action, $resource, Request $request, array $details = []): void
{
$auditLog = new AuditLog();
// Basic information
$auditLog->setUser($user);
$auditLog->setAction($action);
$auditLog->setTimestamp(new DateTime());
// Resource information
if ($resource) {
$auditLog->setResourceType(get_class($resource));
$auditLog->setResourceId($resource->getId());
if (method_exists($resource, 'getPatientId')) {
$auditLog->setPatientId($resource->getPatientId());
}
}
// Request information
$auditLog->setIpAddress($request->getClientIp());
$auditLog->setUserAgent($request->headers->get('User-Agent'));
$auditLog->setRequestMethod($request->getMethod());
$auditLog->setRequestUrl($request->getUri());
$auditLog->setSessionId($request->getSession()->getId());
// Additional details
$auditLog->setDetails($details);
// Compliance information
$auditLog->setHipaaCompliant(true);
$auditLog->setAuditRequired(true);
$auditLog->setRetentionPeriod('7_years');
// Encrypt sensitive audit data
$this->encryptAuditLog($auditLog);
$this->auditRepository->save($auditLog);
}
public function logAuthentication(User $user, string $action, Request $request, bool $success, string $failureReason = null): void
{
$auditLog = new AuditLog();
$auditLog->setUser($user);
$auditLog->setAction($action);
$auditLog->setTimestamp(new DateTime());
$auditLog->setIpAddress($request->getClientIp());
$auditLog->setUserAgent($request->headers->get('User-Agent'));
$auditLog->setResult($success ? 'SUCCESS' : 'FAILURE');
$details = [
'success' => $success,
'failureReason' => $failureReason,
'loginMethod' => 'PASSWORD'
];
$auditLog->setDetails($details);
$auditLog->setHipaaCompliant(true);
$auditLog->setAuditRequired(true);
$this->auditRepository->save($auditLog);
}
private function encryptAuditLog(AuditLog $auditLog): void
{
// Encrypt sensitive fields in audit log
if ($auditLog->getDetails()) {
$encryptedDetails = $this->encryptionService->encrypt(json_encode($auditLog->getDetails()));
$auditLog->setEncryptedDetails($encryptedDetails);
$auditLog->setDetails(null); // Remove unencrypted data
}
}
}
Event Listeners
<?php
namespace App\EventListener;
use App\Service\AuditLogger;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
class AuditEventListener
{
private $auditLogger;
public function __construct(AuditLogger $auditLogger)
{
$this->auditLogger = $auditLogger;
}
public function onAuthenticationSuccess(AuthenticationEvent $event): void
{
$user = $event->getAuthenticationToken()->getUser();
$request = $this->getCurrentRequest();
if ($request) {
$this->auditLogger->logAuthentication($user, 'LOGIN', $request, true);
}
}
public function onAuthenticationFailure(AuthenticationFailureEvent $event): void
{
$token = $event->getAuthenticationToken();
$user = $token->getUser();
$request = $this->getCurrentRequest();
if ($request && $user) {
$this->auditLogger->logAuthentication($user, 'LOGIN_FAILED', $request, false, 'INVALID_CREDENTIALS');
}
}
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
// Log API requests
if (str_starts_with($request->getPathInfo(), '/api/')) {
$this->logApiRequest($request);
}
}
private function logApiRequest(Request $request): void
{
$user = $this->getCurrentUser();
if (!$user) {
return;
}
$action = $this->determineAction($request);
$resource = $this->extractResource($request);
$this->auditLogger->logAccess($user, $action, $resource, $request);
}
private function determineAction(Request $request): string
{
$method = $request->getMethod();
$path = $request->getPathInfo();
if (str_contains($path, '/patients')) {
return match($method) {
'GET' => 'VIEW_PATIENT',
'POST' => 'CREATE_PATIENT',
'PUT', 'PATCH' => 'UPDATE_PATIENT',
'DELETE' => 'DELETE_PATIENT',
default => 'UNKNOWN_ACTION'
};
}
return 'UNKNOWN_ACTION';
}
}
Audit Log Storage
MongoDB Document Structure
// Audit log document in MongoDB
{
"_id": ObjectId("..."),
"timestamp": ISODate("2024-01-15T10:30:00Z"),
"user": {
"id": "user_456",
"email": "doctor@securehealth.dev",
"role": "ROLE_DOCTOR"
},
"action": "VIEW_PATIENT",
"resource": {
"type": "Patient",
"id": "patient_789",
"patientId": "PAT-12345"
},
"request": {
"method": "GET",
"url": "/api/patients/PAT-12345",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"sessionId": "session_abc123"
},
"result": {
"status": "SUCCESS",
"httpCode": 200,
"responseTime": 150
},
"compliance": {
"hipaaCompliant": true,
"auditRequired": true,
"retentionPeriod": "7_years"
},
"encryptedDetails": "encrypted_data_here",
"createdAt": ISODate("2024-01-15T10:30:00Z")
}
Indexing Strategy
// Create indexes for efficient audit log queries
db.audit_logs.createIndex({ "timestamp": 1 })
db.audit_logs.createIndex({ "user.id": 1, "timestamp": 1 })
db.audit_logs.createIndex({ "action": 1, "timestamp": 1 })
db.audit_logs.createIndex({ "resource.patientId": 1, "timestamp": 1 })
db.audit_logs.createIndex({ "request.ipAddress": 1, "timestamp": 1 })
db.audit_logs.createIndex({ "result.status": 1, "timestamp": 1 })
Compliance Reporting
Automated Reports
<?php
namespace App\Service;
class ComplianceReporter
{
public function generateAccessReport(DateTime $startDate, DateTime $endDate): array
{
$auditLogs = $this->auditRepository->findByDateRange($startDate, $endDate);
$report = [
'period' => [
'start' => $startDate,
'end' => $endDate
],
'summary' => [
'totalAccesses' => count($auditLogs),
'uniqueUsers' => $this->countUniqueUsers($auditLogs),
'uniquePatients' => $this->countUniquePatients($auditLogs),
'failedAccesses' => $this->countFailedAccesses($auditLogs)
],
'byUser' => $this->groupByUser($auditLogs),
'byPatient' => $this->groupByPatient($auditLogs),
'byAction' => $this->groupByAction($auditLogs),
'securityIncidents' => $this->identifySecurityIncidents($auditLogs)
];
return $report;
}
public function generateBreachReport(array $incidentIds): array
{
$incidents = $this->auditRepository->findByIds($incidentIds);
$report = [
'incidentSummary' => [
'totalIncidents' => count($incidents),
'affectedPatients' => $this->countAffectedPatients($incidents),
'incidentTypes' => $this->categorizeIncidents($incidents)
],
'detailedIncidents' => $incidents,
'recommendations' => $this->generateRecommendations($incidents)
];
return $report;
}
}
Real-time Monitoring
Security Alerts
<?php
namespace App\Service;
class SecurityMonitor
{
public function monitorAccessPatterns(): void
{
$recentLogs = $this->auditRepository->findRecent(3600); // Last hour
$this->checkForSuspiciousActivity($recentLogs);
$this->checkForPrivilegeEscalation($recentLogs);
$this->checkForDataExfiltration($recentLogs);
}
private function checkForSuspiciousActivity(array $logs): void
{
$userAccessCounts = [];
foreach ($logs as $log) {
$userId = $log->getUser()->getId();
$userAccessCounts[$userId] = ($userAccessCounts[$userId] ?? 0) + 1;
}
// Alert if user has excessive access
foreach ($userAccessCounts as $userId => $count) {
if ($count > 100) { // Threshold
$this->sendSecurityAlert('EXCESSIVE_ACCESS', [
'userId' => $userId,
'accessCount' => $count,
'timeframe' => '1_hour'
]);
}
}
}
private function checkForPrivilegeEscalation(array $logs): void
{
foreach ($logs as $log) {
if ($log->getAction() === 'CHANGE_PERMISSIONS') {
$this->sendSecurityAlert('PRIVILEGE_ESCALATION', [
'userId' => $log->getUser()->getId(),
'action' => $log->getAction(),
'details' => $log->getDetails()
]);
}
}
}
private function sendSecurityAlert(string $type, array $details): void
{
$alert = new SecurityAlert();
$alert->setType($type);
$alert->setDetails($details);
$alert->setTimestamp(new DateTime());
$alert->setStatus('ACTIVE');
$this->alertRepository->save($alert);
// Send notification to security team
$this->notificationService->sendSecurityAlert($alert);
}
}
Audit Log Retention
Retention Policies
<?php
namespace App\Service;
class AuditRetentionManager
{
public function enforceRetentionPolicies(): void
{
$policies = [
'PHI_ACCESS' => '7_years',
'AUTHENTICATION' => '1_year',
'ADMIN_ACTIONS' => '7_years',
'SYSTEM_EVENTS' => '1_year'
];
foreach ($policies as $logType => $retentionPeriod) {
$this->archiveOldLogs($logType, $retentionPeriod);
}
}
private function archiveOldLogs(string $logType, string $retentionPeriod): void
{
$cutoffDate = $this->calculateCutoffDate($retentionPeriod);
$oldLogs = $this->auditRepository->findOlderThan($logType, $cutoffDate);
foreach ($oldLogs as $log) {
$this->archiveLog($log);
$this->auditRepository->delete($log);
}
}
private function archiveLog(AuditLog $log): void
{
$archivedLog = new ArchivedAuditLog();
$archivedLog->setOriginalId($log->getId());
$archivedLog->setTimestamp($log->getTimestamp());
$archivedLog->setAction($log->getAction());
$archivedLog->setEncryptedData($this->encryptForArchive($log));
$archivedLog->setArchivedAt(new DateTime());
$this->archiveRepository->save($archivedLog);
}
}
Best Practices
1. Comprehensive Logging
- Log all access to PHI
- Include sufficient context for investigations
- Capture both successful and failed access attempts
2. Data Protection
- Encrypt sensitive audit log data
- Implement proper access controls for audit logs
- Use secure storage for audit data
3. Performance Optimization
- Use appropriate indexing strategies
- Implement log rotation and archival
- Monitor audit log performance
4. Compliance
- Meet HIPAA audit requirements
- Implement proper retention policies
- Generate compliance reports
Next Steps
- Security Architecture - Overall security design
- User Guides - Role-specific documentation
- Tutorials - Step-by-step implementation guides
- Reference - Common issues and solutions