Skip to main content

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​