Skip to main content
Back to Blog
1 November 202514 min read

NEN 7510: Healthcare Information Security in the Netherlands

SecurityComplianceNEN7510HealthcareNetherlands

Implementing NEN 7510 for healthcare organisations. Understanding Dutch healthcare security requirements, integration with ISO 27001, and practical compliance strategies.


NEN 7510: Healthcare Information Security in the Netherlands

NEN 7510 is the Dutch standard for information security in healthcare. For organisations processing health data in the Netherlands, compliance isn't optional—it's a legal requirement under the Wet aanvullende bepalingen verwerking persoonsgegevens in de zorg (Wabvpz).

Understanding NEN 7510

The NEN 7510 Family

NEN 7510 Standards Family:
├── NEN 7510-1:2017
│   └── Information security management systems in healthcare
│       (Based on ISO 27001, healthcare-specific requirements)
│
├── NEN 7510-2:2017
│   └── Controls for healthcare
│       (Based on ISO 27002, healthcare adaptations)
│
├── NEN 7512:2022
│   └── Electronic communication in healthcare
│       (Data exchange, messaging, interoperability)
│
├── NEN 7513:2023
│   └── Logging of patient data access
│       (Audit trails, access monitoring)
│
└── NEN 7516:2021
    └── Remote access to patient data
        (Telehealth, mobile access, home working)

Key Differences from ISO 27001

AspectISO 27001NEN 7510
ScopeGeneral information securityHealthcare-specific
Patient rightsNot addressedCentral requirement
LoggingGeneral requirementDetailed in NEN 7513
Data exchangeGeneralSpecific in NEN 7512
Risk appetiteOrganisation definesLower tolerance for health data
Legal basisInternational standardDutch legal requirement

Legal Context

Dutch Healthcare Law Requirements

# legal-framework.yml wabvpz_requirements: - name: Information Security Obligation article: Article 3 requirement: | Healthcare providers must take appropriate technical and organisational measures to secure health data implementation: NEN 7510 compliance - name: Electronic Data Exchange article: Article 4 requirement: | Electronic exchange of health data must meet security requirements implementation: NEN 7512 compliance - name: Access Logging article: Article 5 requirement: | Access to patient records must be logged implementation: NEN 7513 compliance - name: Patient Rights article: Article 6 requirement: | Patients have right to access logs of who viewed their data implementation: Log access portal, NEN 7513 avg_gdpr_intersection: - Health data as special category (Article 9) - Data protection by design (Article 25) - Security of processing (Article 32) - Data breach notification (Article 33) - Data Protection Impact Assessment (Article 35)

Enforcement and Penalties

Regulatory Oversight:
├── Autoriteit Persoonsgegevens (AP)
│   ├── GDPR/AVG enforcement
│   ├── Data breach investigations
│   └── Fines up to €20M or 4% turnover
│
├── Inspectie Gezondheidszorg en Jeugd (IGJ)
│   ├── Healthcare quality oversight
│   ├── NEN 7510 compliance verification
│   └── Can mandate improvements or close facilities
│
└── NZa (Nederlandse Zorgautoriteit)
    ├── Healthcare market regulation
    └── Can impose administrative measures

NEN 7510 Control Framework

Healthcare-Specific Controls

// nen7510-controls.ts interface HealthcareControl { id: string; isoEquivalent?: string; requirement: string; healthcareContext: string; implementationGuidance: string[]; } const healthcareSpecificControls: HealthcareControl[] = [ { id: 'NEN7510-9.4.1', isoEquivalent: 'ISO27001-A.9.4.1', requirement: 'Information access restriction', healthcareContext: ` Healthcare workers must only access patient data for patients under their direct care. Access must be role-based and time-limited where applicable. `, implementationGuidance: [ 'Implement treatment relationship verification', 'Configure role-based access per department', 'Enable break-the-glass for emergencies', 'Log all access with reason codes' ] }, { id: 'NEN7510-12.4', isoEquivalent: 'ISO27001-A.12.4', requirement: 'Logging and monitoring', healthcareContext: ` All access to patient data must be logged in accordance with NEN 7513. Logs must be retained and patients must be able to request access logs. `, implementationGuidance: [ 'Log who, what, when, why for all access', 'Retain logs for minimum 5 years', 'Implement patient log access portal', 'Enable anomaly detection on access patterns' ] }, { id: 'NEN7510-13.2', isoEquivalent: 'ISO27001-A.13.2', requirement: 'Information transfer', healthcareContext: ` Health data exchange must comply with NEN 7512. Use approved secure messaging standards and verify recipient identity before transmission. `, implementationGuidance: [ 'Use AORTA/LSP for national exchange', 'Implement secure email (ZIVVER/similar)', 'Verify UZI/AGB codes for recipients', 'Encrypt data in transit and at rest' ] }, { id: 'NEN7510-18.1', isoEquivalent: 'ISO27001-A.18.1', requirement: 'Legal compliance', healthcareContext: ` Must comply with Wabvpz, WGBO, AVG/GDPR, and sector-specific regulations. Patient rights must be actively supported. `, implementationGuidance: [ 'Map all applicable regulations', 'Implement patient consent management', 'Enable data portability (Article 20 GDPR)', 'Support right to be forgotten where applicable' ] } ];

Treatment Relationship Model

// treatment-relationship.ts interface TreatmentRelationship { patientId: string; healthcareProviderId: string; providerUZI: string; organisationAGB: string; relationshipType: 'direct_care' | 'consultation' | 'emergency' | 'administrative'; validFrom: Date; validUntil?: Date; accessScope: AccessScope; } interface AccessScope { dataCategories: DataCategory[]; timeRestriction?: { startTime: string; endTime: string; }; locationRestriction?: string[]; } type DataCategory = | 'demographics' | 'medical_history' | 'medications' | 'lab_results' | 'imaging' | 'clinical_notes' | 'mental_health' | 'hiv_status' | 'genetic_data'; const checkAccessAuthorisation = async ( userId: string, patientId: string, requestedData: DataCategory[] ): Promise<AccessDecision> => { // Find active treatment relationship const relationship = await findActiveRelationship(userId, patientId); if (!relationship) { // Check for emergency access (break-the-glass) return { allowed: false, reason: 'no_treatment_relationship', emergencyAccessAvailable: true }; } // Verify requested data is within scope const unauthorisedCategories = requestedData.filter( cat => !relationship.accessScope.dataCategories.includes(cat) ); if (unauthorisedCategories.length > 0) { return { allowed: false, reason: 'data_outside_scope', unauthorisedCategories, emergencyAccessAvailable: true }; } return { allowed: true, relationship, mustLog: true, logReason: 'treatment_relationship' }; };

NEN 7513: Logging Requirements

Comprehensive Access Logging

// nen7513-logging.ts interface PatientDataAccessLog { // Mandatory fields per NEN 7513 logId: string; timestamp: Date; // Who accessed userId: string; userRole: string; userUZI?: string; organisationId: string; organisationAGB: string; // What was accessed patientId: string; patientBSN?: string; resourceType: string; resourceId: string; dataCategories: DataCategory[]; // How accessed action: 'create' | 'read' | 'update' | 'delete' | 'print' | 'export'; accessMethod: 'application' | 'api' | 'direct_db' | 'emergency'; // Why accessed accessReason: AccessReason; reasonDescription?: string; // Context applicationId: string; applicationVersion: string; clientIP?: string; deviceId?: string; } type AccessReason = | 'direct_care' | 'consultation_request' | 'emergency' | 'quality_review' | 'research_anonymised' | 'administrative' | 'patient_request' | 'legal_requirement'; const logPatientDataAccess = async ( access: Omit<PatientDataAccessLog, 'logId' | 'timestamp'> ): Promise<void> => { const log: PatientDataAccessLog = { ...access, logId: generateUUID(), timestamp: new Date() }; // Write to immutable log storage await writeToImmutableLog(log); // Real-time anomaly detection await checkForAnomalies(log); // Update patient access dashboard await updatePatientAccessDashboard(log.patientId, log); }; const writeToImmutableLog = async (log: PatientDataAccessLog): Promise<void> => { // Write to append-only storage with cryptographic integrity const logEntry = { ...log, previousHash: await getLastLogHash(), hash: await calculateLogHash(log) }; await appendOnlyStorage.write(logEntry); // Replicate to secure backup await replicateToBackup(logEntry); };

Patient Access Portal

// patient-access-portal.ts interface PatientAccessView { patientId: string; accessHistory: AccessHistoryEntry[]; totalAccesses: number; uniqueProviders: number; lastAccess: Date; } interface AccessHistoryEntry { date: Date; providerName: string; organisationName: string; action: string; dataAccessed: string; reason: string; } const getPatientAccessHistory = async ( patientId: string, authenticatedPatientBSN: string, options: { from?: Date; to?: Date; limit?: number } ): Promise<PatientAccessView> => { // Verify patient identity if (!await verifyPatientIdentity(patientId, authenticatedPatientBSN)) { throw new UnauthorisedError('Patient identity verification failed'); } // Retrieve access logs const logs = await accessLogStore.query({ patientId, from: options.from || new Date(Date.now() - 365 * 24 * 60 * 60 * 1000), to: options.to || new Date(), limit: options.limit || 100 }); // Transform to patient-friendly view const accessHistory = await Promise.all( logs.map(async log => ({ date: log.timestamp, providerName: await resolveProviderName(log.userId), organisationName: await resolveOrganisationName(log.organisationId), action: translateAction(log.action), dataAccessed: translateDataCategories(log.dataCategories), reason: translateReason(log.accessReason) })) ); return { patientId, accessHistory, totalAccesses: logs.length, uniqueProviders: new Set(logs.map(l => l.userId)).size, lastAccess: logs[0]?.timestamp || null }; };

NEN 7512: Secure Data Exchange

Healthcare Messaging Standards

# nen7512-exchange-standards.yml approved_exchange_methods: national_infrastructure: - name: LSP (Landelijk Schakelpunt) use_case: National patient summary exchange authentication: UZI-pas certificate protocol: HL7v3 encryption: TLS 1.2+ - name: AORTA use_case: Medication records, lab results authentication: UZI certificate protocol: HL7 FHIR encryption: TLS 1.3 - name: MedMij use_case: Patient-controlled data exchange authentication: DigiD protocol: FHIR R4 encryption: TLS 1.3 secure_messaging: - name: ZIVVER use_case: Secure email, file transfer authentication: Email + 2FA encryption: End-to-end - name: Siilo use_case: Clinical messaging authentication: Phone verification encryption: End-to-end file_transfer: - name: VECOZO use_case: Healthcare declarations authentication: Certificate protocol: AS2/AS4 encryption: TLS + message-level

Secure Message Exchange Implementation

// secure-healthcare-exchange.ts interface SecureMessage { messageId: string; sender: HealthcareEntity; recipient: HealthcareEntity; patient: PatientReference; content: EncryptedContent; metadata: MessageMetadata; signature: DigitalSignature; } interface HealthcareEntity { type: 'practitioner' | 'organisation'; identifier: string; uziNumber?: string; agbCode?: string; certificateThumbprint: string; } const sendSecureHealthcareMessage = async ( message: UnencryptedMessage, recipientIdentifier: string ): Promise<SendResult> => { // Step 1: Verify recipient const recipient = await verifyHealthcareRecipient(recipientIdentifier); if (!recipient.verified) { throw new RecipientVerificationError( `Cannot verify healthcare provider: ${recipientIdentifier}` ); } // Step 2: Check patient consent if required if (message.patient && !await hasPatientConsent(message.patient.id, recipient)) { throw new ConsentError('Patient consent not recorded for this recipient'); } // Step 3: Encrypt message content const encryptedContent = await encryptForRecipient( message.content, recipient.publicKey ); // Step 4: Sign message const signature = await signMessage({ messageId: message.id, contentHash: await hashContent(message.content), timestamp: new Date(), senderId: getCurrentUserUZI() }); // Step 5: Send via appropriate channel const secureMessage: SecureMessage = { messageId: message.id, sender: await getCurrentSenderEntity(), recipient: recipient.entity, patient: message.patient, content: encryptedContent, metadata: { sent: new Date(), contentType: message.contentType, urgency: message.urgency }, signature }; // Step 6: Log the exchange await logHealthcareExchange(secureMessage); return await transmitSecureMessage(secureMessage); }; const verifyHealthcareRecipient = async ( identifier: string ): Promise<RecipientVerification> => { // Check UZI register const uziVerification = await uziRegister.verify(identifier); if (uziVerification.valid) { return { verified: true, entity: uziVerification.entity, publicKey: uziVerification.certificate.publicKey, verificationMethod: 'UZI' }; } // Check AGB register const agbVerification = await agbRegister.verify(identifier); if (agbVerification.valid) { return { verified: true, entity: agbVerification.entity, publicKey: await retrieveOrganisationKey(agbVerification.agbCode), verificationMethod: 'AGB' }; } return { verified: false }; };

Implementation Roadmap

Phase 1: Assessment and Planning

# phase1-assessment.yml activities: gap_analysis: - Review current security controls against NEN 7510 - Identify healthcare-specific gaps - Assess NEN 7513 logging compliance - Evaluate NEN 7512 exchange mechanisms duration: 4-6 weeks risk_assessment: - Identify healthcare data assets - Assess threats specific to healthcare - Evaluate patient safety impacts - Document risk treatment decisions duration: 3-4 weeks scope_definition: - Define ISMS boundaries - Identify critical healthcare processes - Map patient data flows - Document third-party relationships duration: 2 weeks deliverables: - Gap analysis report - Healthcare-specific risk register - ISMS scope document - Implementation project plan

Phase 2: Core Implementation

// implementation-checklist.ts interface ImplementationPhase { name: string; controls: ControlImplementation[]; dependencies: string[]; duration: string; } const phase2Implementation: ImplementationPhase = { name: 'Core Security Controls', duration: '3-4 months', dependencies: ['phase1_completed'], controls: [ { control: 'Access Control', tasks: [ 'Implement role-based access control', 'Configure treatment relationship checks', 'Deploy break-the-glass procedures', 'Enable UZI authentication where required' ], priority: 'critical' }, { control: 'NEN 7513 Logging', tasks: [ 'Deploy centralised logging infrastructure', 'Configure all applications for NEN 7513 compliance', 'Implement log integrity protection', 'Build patient access portal' ], priority: 'critical' }, { control: 'Data Protection', tasks: [ 'Implement encryption at rest (AES-256)', 'Enable TLS 1.3 for all connections', 'Deploy data loss prevention', 'Configure secure backup procedures' ], priority: 'high' }, { control: 'NEN 7512 Exchange', tasks: [ 'Connect to national healthcare infrastructure', 'Implement secure messaging solution', 'Configure recipient verification', 'Enable patient consent management' ], priority: 'high' } ] };

Phase 3: Monitoring and Improvement

# phase3-monitoring.yml continuous_monitoring: access_monitoring: - Real-time anomaly detection on patient data access - Alerts for unusual access patterns - Monthly access pattern reports - Quarterly access reviews security_monitoring: - SIEM integration for security events - Vulnerability scanning (weekly) - Penetration testing (annual) - Incident response drills (quarterly) compliance_monitoring: - Automated NEN 7513 log completeness checks - NEN 7512 exchange verification - Patient consent tracking - Regulatory change monitoring key_performance_indicators: - Percentage of accesses with valid treatment relationship - Time to detect unauthorised access attempts - Log completeness rate (target: 100%) - Patient access request response time - Security incident response time

Common Challenges and Solutions

Challenge 1: Legacy System Integration

// legacy-integration.ts interface LegacyIntegrationStrategy { system: string; challenges: string[]; solutions: Solution[]; } const legacyIntegrationStrategies: LegacyIntegrationStrategy[] = [ { system: 'Legacy EPD/EHR without NEN 7513 logging', challenges: [ 'No built-in access logging', 'Limited API capabilities', 'Vendor no longer supported' ], solutions: [ { approach: 'Database-level logging', implementation: ` Deploy database triggers to capture all SELECT/UPDATE operations on patient tables. Forward to central log system. `, limitations: ['Cannot capture application-level context'] }, { approach: 'Application proxy', implementation: ` Route all application traffic through logging proxy that captures access patterns and enriches with context. `, limitations: ['Additional latency', 'Complex configuration'] }, { approach: 'Gradual migration', implementation: ` Plan migration to compliant system. Document compensating controls for interim period. `, timeline: '12-24 months' } ] } ];

Challenge 2: Emergency Access (Break-the-Glass)

// break-the-glass.ts interface EmergencyAccess { accessId: string; requestor: string; patient: string; reason: EmergencyReason; justification: string; approver?: string; timestamp: Date; expiresAt: Date; accessedData: string[]; } type EmergencyReason = | 'medical_emergency' | 'patient_unconscious' | 'urgent_consultation' | 'disaster_response'; const requestEmergencyAccess = async ( patientId: string, reason: EmergencyReason, justification: string ): Promise<EmergencyAccess> => { const accessId = generateUUID(); const requestor = getCurrentUser(); // Log the emergency access request const emergencyAccess: EmergencyAccess = { accessId, requestor: requestor.id, patient: patientId, reason, justification, timestamp: new Date(), expiresAt: new Date(Date.now() + 4 * 60 * 60 * 1000), // 4 hours accessedData: [] }; // Store and alert await storeEmergencyAccess(emergencyAccess); await alertSecurityTeam(emergencyAccess); await alertPrivacyOfficer(emergencyAccess); // Schedule mandatory review await scheduleEmergencyAccessReview(emergencyAccess); return emergencyAccess; }; const reviewEmergencyAccess = async ( accessId: string, reviewer: string, decision: 'justified' | 'unjustified' | 'needs_investigation' ): Promise<void> => { const access = await getEmergencyAccess(accessId); await updateEmergencyAccess(accessId, { reviewed: true, reviewer, reviewDecision: decision, reviewDate: new Date() }); if (decision === 'unjustified') { await initiateInvestigation(access); await notifyDataProtectionOfficer(access); } };

Key Takeaways

  1. Legal requirement: NEN 7510 compliance is mandatory for Dutch healthcare organisations

  2. Patient-centric: Patient rights and access transparency are fundamental requirements

  3. Comprehensive logging: NEN 7513 requires detailed logging of all patient data access

  4. Secure exchange: Use approved methods (LSP, AORTA, MedMij) for health data exchange

  5. Treatment relationship: Access should be based on verified care relationships

  6. Emergency procedures: Implement break-the-glass with mandatory review

  7. Integration with ISO 27001: NEN 7510 builds on ISO 27001 with healthcare specifics

  8. Continuous monitoring: Real-time detection of unusual access patterns is essential

NEN 7510 compliance protects both patients and healthcare organisations. A well-implemented information security management system ensures patient trust while meeting legal obligations.

Share this article