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