Application Security

Technical overview of DFIRe's security architecture, including authentication, encryption at rest, and role-based access controls.

Security Overview

DFIRe is designed for handling sensitive forensic and incident response data. The application implements defense-in-depth with multiple security layers.

Feature Implementation
Authentication Session-based with OIDC SSO support
File Encryption AES-256-GCM with three-layer key hierarchy
Credential Storage Fernet encryption (AES-128-CBC + HMAC-SHA256)
Access Control Two-tier RBAC (global + case-scoped)
Session Management Database-backed with O(1) revocation
CSRF Protection Double-submit cookie pattern
Rate Limiting Configurable per-endpoint throttling
Audit Logging Immutable, fail-closed audit trail

Infrastructure Security Responsibility

Important: The security features documented on this page secure the DFIRe application itself. You are solely responsible for securing your underlying infrastructure, including the database, file storage, and network access.

DFIRe is designed as a user interface layer that operates on data you own and control. When deployed for production, DFIRe does not include a database or file storage system - you must provide these yourself. This separation is intentional: database security requirements vary significantly between organizations, and DFIRe allows you to choose the solution that fits your needs - whether that's an on-premise PostgreSQL cluster, a managed Database-as-a-Service, or another configuration.

What DFIRe Secures

  • Application-layer authentication and session management
  • Role-based access control within the application
  • Encryption of file attachments before storage
  • Encryption of stored credentials (API keys, SSO secrets)
  • CSRF protection and rate limiting
  • Audit logging of user actions

What You Must Secure

Component Your Responsibility
PostgreSQL Database Access control, authentication, encryption at rest, backups, replication, network isolation. Case data is stored in plaintext in the database for performance and full-text search capability.
File Storage Access control, redundancy, backups. Files are encrypted by DFIRe before storage, but you control the storage infrastructure.
Network Access Firewall rules, TLS termination, VPN/private network configuration, load balancing, DDoS protection.
Server Infrastructure Operating system security, container runtime security, resource limits, monitoring, patching.
Backup & Recovery Database backups, file storage backups, encryption key backups, disaster recovery procedures.
Compliance Ensuring the data you store complies with applicable regulations (GDPR, HIPAA, etc.) and that your infrastructure meets compliance requirements.

High-Security Environments

For organizations with strict security requirements:

  • Air-gapped deployment: DFIRe supports offline licensing for networks without internet access
  • Network isolation: Deploy DFIRe in a dedicated VLAN or private network segment
  • Database encryption: Enable PostgreSQL's Transparent Data Encryption (TDE) or use encrypted storage volumes
  • Access logging: Configure database audit logging in addition to DFIRe's application-level audit trail
  • Zero-trust architecture: Require VPN or identity-aware proxy for all access to DFIRe

See the End User License Agreement included with DFIRe for the complete terms regarding infrastructure and data security responsibilities.

Authentication

DFIRe uses session-based authentication with support for both local credentials and federated identity via OpenID Connect (OIDC).

Session Management

Sessions are managed using Django's database-backed session framework with additional tracking for security:

  • Session storage: PostgreSQL database (not cookies or file-based)
  • Session tracking: UserSession model tracks active sessions per user
  • Session metadata: IP address and user-agent recorded for each session
  • O(1) revocation: Instant invalidation of all user sessions (e.g., on password change)
  • Cookie security: HttpOnly, SameSite=Lax, Secure flags in production

Local Authentication

For users without SSO, DFIRe provides username/password authentication:

  • Password policy: Minimum 12 characters with complexity requirements
  • Password storage: PBKDF2-SHA256 with per-user salt (Django default)
  • Login rate limiting: 5 attempts per minute per IP
  • Session invalidation: All sessions revoked on password change

OIDC Single Sign-On

DFIRe supports federated authentication via OpenID Connect, allowing integration with enterprise identity providers:

Provider Status
Microsoft Entra ID (Azure AD) Tested
Google Workspace Tested
Okta Supported
Auth0 Tested
Any OIDC-compliant IdP Supported

OIDC Flow

  1. User selects SSO provider on login page
  2. Browser redirects to identity provider's authorization endpoint
  3. User authenticates with the identity provider
  4. IdP redirects back with authorization code
  5. DFIRe exchanges code for tokens via back-channel
  6. Claims extracted from ID token (email, name, phone, picture)
  7. User matched by (provider_id, subject) or email fallback
  8. Session created and user redirected to dashboard

User Provisioning

When a user first authenticates via OIDC:

  • Account is automatically created from OIDC claims
  • Default group assigned based on provider configuration
  • Profile picture downloaded if provided by IdP
  • OIDC identity (provider + subject) stored for future logins

See Single Sign-On for configuration instructions.

Encryption at Rest

DFIRe encrypts all sensitive data at rest using a three-layer key hierarchy. This design ensures that data compromise requires access to multiple keys, and deletion of any key renders associated data permanently unreadable.

Key Hierarchy

Tenant Master Key (32-byte, generated once)
    └── Entity Key (per Case or Evidence Item)
            └── File Key (derived per attachment)
Layer Storage Purpose
Tenant Master Key Database (Tenant.encryption_key) Root key for all tenant data
Entity Key Database (Case/Item.encryption_key) Per-case/item isolation
File Key Derived at runtime Unique per attachment

File Key Derivation

Each attachment has a unique encryption key derived using HKDF-SHA256:

1. intermediate = HKDF(salt=tenant_key, ikm=entity_key, info="dfire-entity-derivation")
2. file_key = HKDF(salt=file_salt, ikm=intermediate, info="dfire-file-encryption")

The file_salt is a random 16-byte value generated for each attachment and stored alongside the encrypted file. This ensures every file has a unique key even within the same case.

File Encryption (Attachments & Photos)

All file attachments and photos are encrypted using AES-256-GCM:

Property Value
Algorithm AES-256-GCM (authenticated encryption)
Chunk size 8MB plaintext per chunk
Nonce 12 bytes, derived from chunk index
Auth tag 16 bytes per chunk
Streaming Yes - supports files of any size

The chunked design enables:

  • Streaming encryption/decryption without buffering entire files in memory
  • Compatibility with S3 multipart uploads
  • Resumable uploads (same key derivation produces same key)
  • Parallel chunk processing

Data Deletion: Deleting a tenant, case, or evidence item permanently destroys the associated encryption key. All attachments encrypted with that key become unreadable with no recovery mechanism. This is by design for secure data disposal.

Credential Encryption

Stored credentials (API keys, webhook secrets, SSO client secrets) are encrypted using a separate key:

Property Value
Algorithm Fernet (AES-128-CBC + HMAC-SHA256)
Key source CREDENTIAL_ENCRYPTION_KEY environment variable
Field types EncryptedCharField, EncryptedJSONField

Encrypted database fields include:

  • OIDC client secrets
  • Slack bot tokens and signing secrets
  • Webhook signing keys
  • License server credentials
  • S3/SMB storage credentials

Key Separation: The CREDENTIAL_ENCRYPTION_KEY is separate from the tenant's file encryption keys. This means database credential encryption is independent of file storage encryption.

Role-Based Access Control (RBAC)

DFIRe implements a two-tier RBAC model: global permissions control what actions a user can perform, while case-scoped access controls which cases they can access.

Permission Architecture

Can user X perform operation Y on case Z?
│
├─ Is user a superuser?
│  └─ YES → Allow (bypasses all checks)
│
├─ Does user have the atomic permission for Y?
│  └─ NO → Deny
│
├─ Does user have global override (view_all/edit_all)?
│  └─ YES → Allow
│
├─ Is user assigned to case Z?
│  ├─ Lead Investigator → Allow
│  ├─ Investigator → Allow (write operations)
│  └─ Viewer → Allow (read-only operations)
│
└─ NO → Deny (no access to this case)

User Types

Type Description
Superuser Bypasses all permission checks. Has access to system-critical settings (Tenant, Storage, SSO, Collaboration). Should be limited to system administrators.
Regular User Permissions determined by assigned Django permissions (typically via groups). Case access determined by assignment.

Case Roles

Role Capabilities
Lead Investigator Full control: edit case, manage team, delete case, close case
Investigator Edit access: add/edit evidence, notes, attachments, timeline events
Viewer Read-only access to case and all its contents

Global Override Permissions

Permission Effect
core.view_all_cases View any case regardless of assignment
core.edit_all_cases Edit any case regardless of assignment
core.view_archived_cases View archived cases (required in addition to other access)

Settings Access

Access to System Settings is controlled by user type and specific permissions:

Superuser-Only Settings

  • Tenant Configuration
  • Storage Backend
  • SSO/OIDC Configuration
  • Collaboration (Slack)
  • Configuration Import/Export

Delegatable Settings

Accessible to users with core.change_tenant plus the relevant atomic permission:

  • Webhooks
  • User Accounts
  • Case Types & Evidence Types
  • Workflow Steps & Incident Phases
  • Compliance Timers
  • Flags

Write Protection

Closed and archived cases are write-protected:

  • Closed: Case is read-only, can be reopened by Lead Investigator
  • Archived: Case is permanently read-only, requires view_archived_cases permission to view

Additional Security Controls

CSRF Protection

Cross-Site Request Forgery protection uses the double-submit cookie pattern:

  • CSRF token set in cookie (csrftoken)
  • Token must be included in X-CSRFToken header for mutations
  • Token validated on all POST, PUT, PATCH, DELETE requests

Rate Limiting

Endpoint Limit
Login 5 requests/minute
API (authenticated) 1500 requests/minute
Slack webhooks 60 requests/minute

Secure Cookies

Flag Value
HttpOnly Yes (session cookie not accessible to JavaScript)
SameSite Lax (prevents CSRF from external sites)
Secure Yes in production (HTTPS only)

WebSocket Authentication

Real-time WebSocket connections:

  • Authenticate using the same session cookie as HTTP requests
  • Re-validate permissions on each ping
  • Scoped to specific resources (case, item, dashboard)
  • Anonymous connections rejected

Audit Logging

All security-sensitive operations are logged to an immutable audit trail:

  • Immutable: Audit records cannot be modified or deleted
  • Fail-closed: Operations fail if audit logging fails
  • Comprehensive: Logs user, action, object, changes, timestamp, IP
  • Searchable: Full-text search across audit records

Logged operations include:

  • Authentication events (login, logout, failed attempts)
  • Case and evidence CRUD operations
  • Team assignment changes
  • Configuration changes
  • Attachment uploads and downloads

Preconfigured Permission Groups

DFIRe comes with four preconfigured permission groups. These use atomic permissions (not group name checks) and can be customized as needed:

DFIRe Admin

Full administrative access for managing the entire system:

  • core.change_tenant - access to System Settings
  • core.view_all_cases, core.edit_all_cases - global case access
  • core.view_archived_cases, core.view_statistics
  • auth.add_user, auth.change_user - user management
  • All case, item, attachment, note permissions
  • Webhook, compliance timer, case type, and evidence type management

Team Lead

Oversight role with full case visibility but no system settings access:

  • core.view_all_cases, core.edit_all_cases - global case access
  • core.view_archived_cases, core.view_statistics
  • core.manage_team - can manage case assignments
  • All case, item, attachment, note, timeline permissions
  • Report template management
  • No change_tenant - cannot access System Settings

Standard User

Regular investigator working on assigned cases:

  • core.add_case, core.change_case, core.delete_case
  • core.manage_team - can manage team on cases they lead
  • All item, attachment, note, timeline permissions
  • No global case access - only sees assigned cases

View Only

Read-only access for auditors or external reviewers:

  • core.view_case, core.view_item, core.view_attachment
  • View-only permissions for all case content
  • Cannot create, modify, or delete anything
  • Access limited to assigned cases only