10 KiB
Issue #365: Additional Security Enhancements - Implementation Specification
Status: Planning Complete
Created: 2025-12-21
Issue: https://github.com/Wikid82/Charon/issues/365
Branch: feature/issue-365-additional-security
PRs: #436 (targets development), #437 (targets main)
Executive Summary
This specification details the implementation plan for Issue #365, which addresses six security enhancement areas. After thorough codebase analysis, this document provides file-by-file implementation details, phase breakdown, and complexity estimates.
Scope Summary
| Requirement | Status | Complexity | Phase |
|---|---|---|---|
| Supply Chain - SBOM Generation | ❌ TODO | Medium | 2 |
| DNS Hijacking - Documentation | ❌ TODO | Low | 1 |
| TLS Downgrade - Documentation | ✅ Partial | Low | 1 |
| Privilege Escalation - Container Hardening | ⚠️ Partial | Medium | 2 |
| Session Hijacking - Cookie/CSP Audit | ✅ Implemented | Low | 1 |
| Timing Attacks - Constant-Time Comparison | ❌ TODO | Medium | 2 |
| SIRP Documentation | ❌ TODO | Low | 1 |
| Security Update Notifications Doc | ❌ TODO | Low | 1 |
Codebase Research Findings
1. Cookie/Session Implementation
Location: backend/internal/api/handlers/auth_handler.go
Current Implementation (lines 52-73):
func setSecureCookie(c *gin.Context, name, value string, maxAge int) {
scheme := requestScheme(c)
secure := isProduction() && scheme == "https"
sameSite := http.SameSiteStrictMode
if scheme != "https" {
sameSite = http.SameSiteLaxMode
}
c.SetSameSite(sameSite)
c.SetCookie(name, value, maxAge, "/", "", secure, true) // HttpOnly: true ✅
}
Assessment: ✅ SECURE - All cookie security attributes properly configured:
HttpOnly: true- Prevents XSS accessSecure: true(production + HTTPS)SameSite: Strict(HTTPS) /Lax(HTTP dev)
2. Security Headers Implementation
Location: backend/internal/api/middleware/security.go
Current Headers Set:
- ✅ Content-Security-Policy (CSP)
- ✅ Strict-Transport-Security (HSTS) with preload
- ✅ X-Frame-Options: DENY
- ✅ X-Content-Type-Options: nosniff
- ✅ X-XSS-Protection: 1; mode=block
- ✅ Referrer-Policy: strict-origin-when-cross-origin
- ✅ Permissions-Policy (restricts camera, mic, etc.)
- ✅ Cross-Origin-Opener-Policy: same-origin
- ✅ Cross-Origin-Resource-Policy: same-origin
Assessment: ✅ COMPREHENSIVE - All major security headers present.
3. Token Comparison Methods
Locations Analyzed:
| File | Function | Method | Status |
|---|---|---|---|
| models/user.go#L62 | CheckPassword |
bcrypt.CompareHashAndPassword |
✅ Constant-time |
| services/security_service.go#L151 | VerifyBreakGlassToken |
bcrypt.CompareHashAndPassword |
✅ Constant-time |
| services/auth_service.go#L128 | ValidateToken |
JWT library | ✅ Handled by library |
Potential Issue Found: Invite token validation uses database lookup which could leak timing:
- Location:
backend/internal/api/handlers/user_handler.go(AcceptInvite) - Risk: Low (requires network timing analysis)
- Recommendation: Add constant-time wrapper for token comparison after DB lookup
4. Current Security Documentation
Location: docs/security.md
Current Coverage:
- ✅ Cerberus security suite (CrowdSec, WAF, ACL)
- ✅ Access Lists configuration
- ✅ Certificate management
- ✅ Break-glass token
- ✅ Zero-day protection explanation
- ❌ TLS version enforcement (not documented)
- ❌ DNS security (not documented)
- ❌ SIRP (not documented)
- ❌ Container hardening (not documented)
5. CI/CD Pipeline Analysis
Location: .github/workflows/docker-build.yml
Current State:
- ✅ Trivy vulnerability scanning (SARIF + table output)
- ✅ Weekly security rebuilds (separate workflow)
- ✅ Caddy security patches verification
- ❌ SBOM generation (not implemented)
- ❌ SBOM attestation (not implemented)
Best Integration Point: After build-and-push step, before Trivy scan (around line 130)
6. Dockerfile Security Analysis
Location: Dockerfile
Current Security Features:
- ✅ Non-root user (
charon:charon, UID 1000) - ✅ Healthcheck configured
- ✅ Minimal base image (Alpine)
- ✅ Multi-stage build (reduces attack surface)
- ⚠️ Root filesystem writable (can be improved)
- ⚠️ All capabilities retained (can drop unnecessary ones)
Phase 1: Documentation Enhancements (Estimated: 1-2 hours)
1.1 TLS Downgrade Attack Documentation
File: docs/security.md
Add Section:
## TLS Security
### TLS Version Enforcement
Charon (via Caddy) enforces a minimum TLS version of 1.2 by default. This prevents TLS downgrade attacks that attempt to force connections to use vulnerable TLS 1.0 or 1.1.
**What's Protected:**
- ✅ TLS 1.0/1.1 downgrade attacks
- ✅ BEAST, POODLE, and similar protocol-level attacks
- ✅ Weak cipher suite negotiation
**HSTS (HTTP Strict Transport Security):**
Charon sets HSTS headers with:
- `max-age=31536000` (1 year)
- `includeSubDomains`
- `preload` (for browser preload lists)
Complexity: Low | Dependencies: None
1.2 DNS Hijacking Documentation
File: docs/security.md
Add Section:
## DNS Security
### Protecting Against DNS Hijacking
Configure your upstream resolver to use DNS-over-HTTPS (DoH) or DNS-over-TLS (DoT):
**Docker Host Configuration:**
```bash
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com
DNSOverTLS=yes
Additional Protections:
- DNSSEC: Ensure your domain registrar supports DNSSEC
- CAA Records: Restrict which CAs can issue certs for your domain
**Complexity**: Low | **Dependencies**: None
---
### 1.3 Security Incident Response Plan
**New File**: `docs/security-incident-response.md`
**Content**: Incident classification, detection, containment, recovery procedures
**Complexity**: Low | **Dependencies**: None
---
### 1.4 Security Update Notifications
**Files**: `docs/getting-started.md`, `docs/security.md`
**Add**: GitHub Watch instructions, Watchtower/Diun configuration examples
**Complexity**: Low | **Dependencies**: None
---
## Phase 2: Code Changes (Estimated: 4-6 hours)
### 2.1 SBOM Generation
**File**: `.github/workflows/docker-build.yml`
**Changes** (add after build-and-push step):
```yaml
- name: Generate SBOM (CycloneDX)
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
format: cyclonedx-json
output-file: sbom.cyclonedx.json
- name: Attest SBOM to Image
if: github.event_name != 'pull_request'
uses: actions/attest-sbom@v2
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build-and-push.outputs.digest }}
sbom-path: sbom.cyclonedx.json
Additional Files:
.gitignore: Addsbom*.json.dockerignore: Addsbom*.json
Complexity: Medium | Dependencies: None
2.2 Container Hardening Documentation
File: docs/security.md
Add Example:
services:
charon:
image: ghcr.io/wikid82/charon:latest
read_only: true
tmpfs:
- /tmp:size=100M
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
Complexity: Medium | Dependencies: Testing with read-only FS
2.3 Constant-Time Token Comparison
New File: backend/internal/util/crypto.go
package util
import "crypto/subtle"
// ConstantTimeCompare compares two strings in constant time.
func ConstantTimeCompare(a, b string) bool {
return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}
New Test File: backend/internal/util/crypto_test.go
Modify: backend/internal/api/handlers/user_handler.go - Use constant-time comparison in AcceptInvite
Complexity: Medium | Dependencies: None
Phase 3: Testing & Validation (Estimated: 2-3 hours)
Required Tests
| File | Purpose |
|---|---|
backend/internal/util/crypto_test.go |
Constant-time comparison tests + benchmarks |
| Integration test additions | Security header verification |
Coverage Requirements
- All new code must achieve 85% coverage
- Run:
scripts/go-test-coverage.sh
File Change Summary
Files to Create
| File | Purpose |
|---|---|
backend/internal/util/crypto.go |
Constant-time comparison utilities |
backend/internal/util/crypto_test.go |
Tests for crypto utilities |
docs/security-incident-response.md |
SIRP documentation |
Files to Modify
| File | Changes |
|---|---|
docs/security.md |
TLS, DNS, container hardening sections |
docs/getting-started.md |
Security update notification section |
.github/workflows/docker-build.yml |
SBOM generation steps |
.gitignore |
Add sbom*.json |
.dockerignore |
Add sbom*.json |
backend/internal/api/handlers/user_handler.go |
Constant-time token comparison |
Files Verified Secure (No Changes)
| File | Reason |
|---|---|
backend/internal/api/handlers/auth_handler.go |
Cookie security correct |
backend/internal/api/middleware/security.go |
Headers comprehensive |
backend/internal/models/user.go |
bcrypt is constant-time |
backend/internal/services/security_service.go |
bcrypt is constant-time |
Dockerfile |
Non-root user configured |
Out of Scope (Future Issues)
Per Issue #365:
- ❌ Certificate Transparency Log Monitoring
- ❌ MFA via Authentik
- ❌ SSO for Charon admin
- ❌ Audit logging for GDPR/SOC2
Acceptance Criteria
- Documentation sections added to
docs/security.md - SIRP document created
- SBOM generation in CI (CycloneDX format)
- Constant-time utility with tests
- Container hardening documented
- 85%+ test coverage
- Pre-commit hooks pass
Analysis Date: 2025-12-21 Analyzed By: GitHub Copilot Status: Ready for Implementation