Skip to content

Security & Compliance

Status: Final Version: 1.0


Purpose

Expand security requirements beyond RBAC to cover encryption, PII handling, threat modeling, access logging, and regulatory compliance (GDPR, SOC 2).


Encryption

At Rest

Database Encryption: - PostgreSQL: Enable Transparent Data Encryption (TDE) or use encrypted EBS volumes - Laravel: Encrypt PII fields using Crypt facade

class MetricSubmission extends Model
{
    protected $casts = [
        'pii_data' => 'encrypted:array', // Laravel 9+ encrypted casting
    ];
}

File Storage Encryption: - S3: Enable Server-Side Encryption (SSE-AES256 or SSE-KMS) - Evidence bucket: ServerSideEncryption: AES256

In Transit

  • TLS 1.2+ required for all HTTPS connections
  • Certificate Management: AWS Certificate Manager or Let's Encrypt
  • HSTS Header: Strict-Transport-Security: max-age=31536000; includeSubDomains

PII Handling (GDPR Compliance)

Identified PII Fields

Field/Metric PII Type Location Handling
Employee names Direct PII Social metrics (diversity, training) Encrypted, access-logged
Email addresses Direct PII users table Encrypted
IP addresses Indirect PII audit_logs.ip_address Anonymized after 90 days

GDPR Rights Implementation

Right to Erasure (Article 17)

class GdprService
{
    public function eraseUserData(User $user)
    {
        DB::transaction(function () use ($user) {
            // Anonymize user record
            $user->update([
                'name' => 'User ' . $user->id . ' (Deleted)',
                'email' => 'deleted_' . $user->id . '@anonymized.local',
                'phone' => null,
            ]);

            // Remove PII from submissions (keep aggregated data)
            $user->submissions()->update([
                'pii_data' => null,
                'metadata->collector_notes' => '[Redacted]',
            ]);

            // Keep audit trail but anonymize actor
            AuditLog::where('actor_user_id', $user->id)
                ->update(['actor_user_id' => null]);

            AuditLog::log('gdpr.erasure_requested', $user, null, 'User data anonymized per GDPR Article 17');
        });
    }
}

Right to Data Portability (Article 20)

public function exportUserData(User $user)
{
    return [
        'user' => $user->only(['name', 'email', 'created_at']),
        'submissions' => $user->submissions()->with('evidence')->get(),
        'audit_log' => AuditLog::where('actor_user_id', $user->id)->get(),
    ];
}

Secrets Management

Never Store in Code/Env Files: - Database passwords - API keys - Encryption keys - AWS credentials

Use AWS Secrets Manager or HashiCorp Vault:

// config/database.php
'pgsql' => [
    'password' => env('DB_PASSWORD') ?: app(SecretsManager::class)->get('db_password'),
],

Access Logging

Requirement: Log all access to PII-containing metrics and evidence files.

class AuditMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // Log if accessing PII
        if ($this->containsPII($request)) {
            AuditLog::create([
                'action' => 'pii.accessed',
                'entity_type' => $request->route()->getName(),
                'actor_user_id' => auth()->id(),
                'ip_address' => $request->ip(),
                'metadata' => [
                    'url' => $request->fullUrl(),
                    'method' => $request->method(),
                ],
            ]);
        }

        return $response;
    }
}

Threat Model

Top 5 Abuse Cases & Mitigations

Threat Attack Vector Mitigation
Data Tampering Attacker modifies approved submissions Immutable submissions, content hashing, audit logs
Fraudulent Evidence Collector uploads fake invoices Virus scanning, manual reviewer checks, cross-reference with external data
Replay Attacks Attacker re-submits old data Idempotency keys (UUID), timestamp validation
Insider Approval Abuse Approver signs off own submissions Segregation of duties (policy enforcement), audit log alerts
Credential Stuffing Brute force login attempts Rate limiting (5 attempts/min), CAPTCHA after 3 failures, account lockout

Additional Threats (vNext)

  • SQL Injection: Laravel Eloquent ORM prevents (parameterized queries)
  • XSS: Laravel Blade auto-escapes output
  • CSRF: Laravel CSRF tokens on all POST/PUT/DELETE
  • Mass Assignment: $fillable whitelists in all models

Least Privilege

Database User Permissions

User Permissions Use Case
app_user SELECT, INSERT, UPDATE (no DELETE) Application runtime
migration_user ALL (DDL + DML) Laravel migrations only
readonly_user SELECT only Reporting, analytics

API Service Accounts

  • Collector API: Can only create submissions, not approve
  • Admin API: Full CRUD, restricted by RBAC policies

Compliance Standards

Standard Requirement Implementation
GDPR Right to erasure, portability, consent PII anonymization, data export API
SOC 2 Type II Access controls, audit logging, encryption RBAC, append-only audit logs, TLS/encryption at rest
ISO 27001 Information security management Documented security policies, risk assessments

Acceptance Criteria

  • Database encryption enabled (TDE or encrypted volumes)
  • Evidence files stored with S3 SSE encryption
  • All HTTPS connections use TLS 1.2+
  • PII fields encrypted using Laravel Crypt
  • GDPR erasure workflow implemented (anonymization)
  • All PII access logged to audit trail
  • Secrets stored in AWS Secrets Manager (not .env)
  • SoD enforced: users cannot approve own submissions
  • Rate limiting prevents brute force (5 req/min on auth endpoints)

Cross-References


Change Log

Version Date Author Changes
1.0 2026-01-03 Senior Product Architect Initial security & compliance specification