Some checks are pending
Go Benchmark / Performance Regression Check (push) Waiting to run
Cerberus Integration / Cerberus Security Stack Integration (push) Waiting to run
Upload Coverage to Codecov / Backend Codecov Upload (push) Waiting to run
Upload Coverage to Codecov / Frontend Codecov Upload (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (go) (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Waiting to run
CrowdSec Integration / CrowdSec Bouncer Integration (push) Waiting to run
Docker Build, Publish & Test / build-and-push (push) Waiting to run
Docker Build, Publish & Test / Security Scan PR Image (push) Blocked by required conditions
Quality Checks / Auth Route Protection Contract (push) Waiting to run
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Waiting to run
Quality Checks / Backend (Go) (push) Waiting to run
Quality Checks / Frontend (React) (push) Waiting to run
Rate Limit integration / Rate Limiting Integration (push) Waiting to run
Security Scan (PR) / Trivy Binary Scan (push) Waiting to run
Supply Chain Verification (PR) / Verify Supply Chain (push) Waiting to run
WAF integration / Coraza WAF Integration (push) Waiting to run
592 lines
16 KiB
Markdown
Executable File
592 lines
16 KiB
Markdown
Executable File
# Security Best Practices
|
|
|
|
This document outlines security best practices for developing and maintaining Charon. These guidelines help prevent common vulnerabilities and ensure compliance with industry standards.
|
|
|
|
## Table of Contents
|
|
|
|
- [Secret Management](#secret-management)
|
|
- [Logging Security](#logging-security)
|
|
- [Input Validation](#input-validation)
|
|
- [File System Security](#file-system-security)
|
|
- [Database Security](#database-security)
|
|
- [API Security](#api-security)
|
|
- [Compliance](#compliance)
|
|
- [Security Testing](#security-testing)
|
|
|
|
---
|
|
|
|
## Secret Management
|
|
|
|
### Principles
|
|
|
|
1. **Never commit secrets to version control**
|
|
2. **Use environment variables for production**
|
|
3. **Rotate secrets regularly**
|
|
4. **Mask secrets in logs**
|
|
5. **Encrypt secrets at rest**
|
|
|
|
### API Keys and Tokens
|
|
|
|
#### Storage
|
|
|
|
- **Development**: Store in `.env` file (gitignored)
|
|
- **Production**: Use environment variables or secret management service
|
|
- **File storage**: Use 0600 permissions (owner read/write only)
|
|
|
|
```bash
|
|
# Example: Secure key file creation
|
|
echo "api-key-here" > /data/crowdsec/bouncer.key
|
|
chmod 0600 /data/crowdsec/bouncer.key
|
|
chown charon:charon /data/crowdsec/bouncer.key
|
|
```
|
|
|
|
#### Masking
|
|
|
|
Always mask secrets before logging:
|
|
|
|
```go
|
|
// ✅ GOOD: Masked secret
|
|
logger.Infof("API Key: %s", maskAPIKey(apiKey))
|
|
|
|
// ❌ BAD: Full secret exposed
|
|
logger.Infof("API Key: %s", apiKey)
|
|
```
|
|
|
|
Charon's masking rules:
|
|
|
|
- Empty: `[empty]`
|
|
- Short (< 16 chars): `[REDACTED]`
|
|
- Normal (≥ 16 chars): `abcd...xyz9` (first 4 + last 4)
|
|
|
|
#### Validation
|
|
|
|
Validate secret format before use:
|
|
|
|
```go
|
|
if !validateAPIKeyFormat(apiKey) {
|
|
return fmt.Errorf("invalid API key format")
|
|
}
|
|
```
|
|
|
|
Requirements:
|
|
|
|
- Length: 16-128 characters
|
|
- Charset: Alphanumeric + underscore + hyphen
|
|
- No spaces or special characters
|
|
|
|
#### Rotation
|
|
|
|
Rotate secrets regularly:
|
|
|
|
1. **Schedule**: Every 90 days (recommended)
|
|
2. **Triggers**: After suspected compromise, employee offboarding, security incidents
|
|
3. **Process**:
|
|
- Generate new secret
|
|
- Update configuration
|
|
- Test with new secret
|
|
- Revoke old secret
|
|
- Update documentation
|
|
|
|
### Passwords and Credentials
|
|
|
|
- **Storage**: Hash with bcrypt (cost factor ≥ 12) or Argon2
|
|
- **Transmission**: HTTPS only
|
|
- **Never log**: Full passwords or password hashes
|
|
- **Requirements**: Enforce minimum complexity and length
|
|
|
|
---
|
|
|
|
## Logging Security
|
|
|
|
### What to Log
|
|
|
|
✅ **Safe to log**:
|
|
|
|
- Timestamps
|
|
- User IDs (not usernames if PII)
|
|
- IP addresses (consider GDPR implications)
|
|
- Request paths (sanitize query parameters)
|
|
- Response status codes
|
|
- Error types (generic messages)
|
|
- Performance metrics
|
|
|
|
❌ **Never log**:
|
|
|
|
- Passwords or password hashes
|
|
- API keys or tokens (use masking)
|
|
- Session IDs (full values)
|
|
- Credit card numbers
|
|
- Social security numbers
|
|
- Personal health information (PHI)
|
|
- Any Personally Identifiable Information (PII)
|
|
|
|
### Log Sanitization
|
|
|
|
Before logging user input, sanitize:
|
|
|
|
```go
|
|
// ✅ GOOD: Sanitized logging
|
|
logger.Infof("Login attempt from IP: %s", sanitizeIP(ip))
|
|
|
|
// ❌ BAD: Direct user input
|
|
logger.Infof("Login attempt: username=%s password=%s", username, password)
|
|
```
|
|
|
|
### Log Retention
|
|
|
|
- **Development**: 7 days
|
|
- **Production**: 30-90 days (depends on compliance requirements)
|
|
- **Audit logs**: 1-7 years (depends on regulations)
|
|
|
|
**Important**: Shorter retention reduces exposure risk if logs are compromised.
|
|
|
|
### Log Aggregation
|
|
|
|
If using external log services (CloudWatch, Splunk, Datadog):
|
|
|
|
- Ensure logs are encrypted in transit (TLS)
|
|
- Ensure logs are encrypted at rest
|
|
- Redact sensitive data before shipping
|
|
- Apply same retention policies
|
|
- Audit access controls regularly
|
|
|
|
---
|
|
|
|
## Input Validation
|
|
|
|
### Principles
|
|
|
|
1. **Validate all inputs** (user-provided, file uploads, API requests)
|
|
2. **Whitelist approach**: Define what's allowed, reject everything else
|
|
3. **Fail securely**: Reject invalid input with generic error messages
|
|
4. **Sanitize before use**: Escape/encode for target context
|
|
|
|
### File Uploads
|
|
|
|
```go
|
|
// ✅ GOOD: Comprehensive validation
|
|
func validateUpload(file multipart.File, header *multipart.FileHeader) error {
|
|
// 1. Check file size
|
|
if header.Size > maxFileSize {
|
|
return fmt.Errorf("file too large")
|
|
}
|
|
|
|
// 2. Validate file type (magic bytes, not extension)
|
|
buf := make([]byte, 512)
|
|
file.Read(buf)
|
|
mimeType := http.DetectContentType(buf)
|
|
if !isAllowedMimeType(mimeType) {
|
|
return fmt.Errorf("invalid file type")
|
|
}
|
|
|
|
// 3. Sanitize filename
|
|
safeName := sanitizeFilename(header.Filename)
|
|
|
|
// 4. Check for path traversal
|
|
if containsPathTraversal(safeName) {
|
|
return fmt.Errorf("invalid filename")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
### Path Traversal Prevention
|
|
|
|
```go
|
|
// ✅ GOOD: Secure path handling
|
|
func securePath(baseDir, userPath string) (string, error) {
|
|
// Clean and resolve path
|
|
fullPath := filepath.Join(baseDir, filepath.Clean(userPath))
|
|
|
|
// Ensure result is within baseDir
|
|
if !strings.HasPrefix(fullPath, baseDir) {
|
|
return "", fmt.Errorf("path traversal detected")
|
|
}
|
|
|
|
return fullPath, nil
|
|
}
|
|
|
|
// ❌ BAD: Direct path join (vulnerable)
|
|
fullPath := baseDir + "/" + userPath
|
|
```
|
|
|
|
### SQL Injection Prevention
|
|
|
|
```go
|
|
// ✅ GOOD: Parameterized query
|
|
db.Where("email = ?", email).First(&user)
|
|
|
|
// ❌ BAD: String concatenation (vulnerable)
|
|
db.Raw("SELECT * FROM users WHERE email = '" + email + "'").Scan(&user)
|
|
```
|
|
|
|
### Command Injection Prevention
|
|
|
|
```go
|
|
// ✅ GOOD: Use exec.Command with separate arguments
|
|
cmd := exec.Command("cscli", "bouncers", "list")
|
|
|
|
// ❌ BAD: Shell with user input (vulnerable)
|
|
cmd := exec.Command("sh", "-c", "cscli bouncers list " + userInput)
|
|
```
|
|
|
|
---
|
|
|
|
## File System Security
|
|
|
|
### File Permissions
|
|
|
|
| File Type | Permissions | Owner | Rationale |
|
|
|-----------|-------------|-------|-----------|
|
|
| Secret files (keys, tokens) | 0600 | charon:charon | Owner read/write only |
|
|
| Configuration files | 0640 | charon:charon | Owner read/write, group read |
|
|
| Log files | 0640 | charon:charon | Owner read/write, group read |
|
|
| Executables | 0750 | root:charon | Owner read/write/execute, group read/execute |
|
|
| Data directories | 0750 | charon:charon | Owner full access, group read/execute |
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
/data/charon/
|
|
├── config/ (0750 charon:charon)
|
|
│ ├── config.yaml (0640 charon:charon)
|
|
│ └── secrets/ (0700 charon:charon) - Secret storage
|
|
│ └── api.key (0600 charon:charon)
|
|
├── logs/ (0750 charon:charon)
|
|
│ └── app.log (0640 charon:charon)
|
|
└── data/ (0750 charon:charon)
|
|
```
|
|
|
|
### Temporary Files
|
|
|
|
```go
|
|
// ✅ GOOD: Secure temp file creation
|
|
f, err := os.CreateTemp("", "charon-*.tmp")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer os.Remove(f.Name()) // Clean up
|
|
|
|
// Set secure permissions
|
|
if err := os.Chmod(f.Name(), 0600); err != nil {
|
|
return err
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Database Security
|
|
|
|
### Query Security
|
|
|
|
1. **Always use parameterized queries** (GORM `Where` with `?` placeholders)
|
|
2. **Validate all inputs** before database operations
|
|
3. **Use transactions** for multi-step operations
|
|
4. **Limit query results** (avoid SELECT *)
|
|
5. **Index sensitive columns** sparingly (balance security vs performance)
|
|
|
|
### Sensitive Data
|
|
|
|
| Data Type | Storage Method | Example |
|
|
|-----------|----------------|---------|
|
|
| Passwords | bcrypt hash | `bcrypt.GenerateFromPassword([]byte(password), 12)` |
|
|
| API Keys | Environment variable or encrypted field | `os.Getenv("API_KEY")` |
|
|
| Tokens | Hashed with random salt | `sha256(token + salt)` |
|
|
| PII | Encrypted at rest | AES-256-GCM |
|
|
|
|
### Migrations
|
|
|
|
```go
|
|
// ✅ GOOD: Add sensitive field with proper constraints
|
|
migrator.AutoMigrate(&User{})
|
|
|
|
// ❌ BAD: Store sensitive data in plaintext
|
|
// (Don't add columns like `password_plaintext`)
|
|
```
|
|
|
|
---
|
|
|
|
## API Security
|
|
|
|
### Authentication
|
|
|
|
- **Use JWT tokens** or session cookies with secure flags
|
|
- **Implement rate limiting** (prevent brute force)
|
|
- **Enforce HTTPS** in production
|
|
- **Validate all tokens** before processing requests
|
|
|
|
### Authorization
|
|
|
|
```go
|
|
// ✅ GOOD: Check user permissions
|
|
if !user.HasPermission("crowdsec:manage") {
|
|
return c.JSON(403, gin.H{"error": "forbidden"})
|
|
}
|
|
|
|
// ❌ BAD: Assume user has access
|
|
// (No permission check)
|
|
```
|
|
|
|
### Rate Limiting
|
|
|
|
Protect endpoints from abuse:
|
|
|
|
```go
|
|
// Example: 100 requests per hour per IP
|
|
limiter := rate.NewLimiter(rate.Every(36*time.Second), 100)
|
|
```
|
|
|
|
**Critical endpoints** (require stricter limits):
|
|
|
|
- Login: 5 attempts per 15 minutes
|
|
- Password reset: 3 attempts per hour
|
|
- API key generation: 5 per day
|
|
|
|
### Input Validation
|
|
|
|
```go
|
|
// ✅ GOOD: Validate request body
|
|
type CreateBouncerRequest struct {
|
|
Name string `json:"name" binding:"required,min=3,max=64,alphanum"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
return c.JSON(400, gin.H{"error": "invalid request"})
|
|
}
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
```go
|
|
// ✅ GOOD: Generic error message
|
|
return c.JSON(401, gin.H{"error": "authentication failed"})
|
|
|
|
// ❌ BAD: Reveals authentication details
|
|
return c.JSON(401, gin.H{"error": "invalid API key: abc123"})
|
|
```
|
|
|
|
---
|
|
|
|
## Compliance
|
|
|
|
### GDPR (General Data Protection Regulation)
|
|
|
|
**Applicable if**: Processing data of EU residents
|
|
|
|
**Requirements**:
|
|
|
|
1. **Data minimization**: Collect only necessary data
|
|
2. **Purpose limitation**: Use data only for stated purposes
|
|
3. **Storage limitation**: Delete data when no longer needed
|
|
4. **Security**: Implement appropriate technical measures (encryption, masking)
|
|
5. **Breach notification**: Report breaches within 72 hours
|
|
|
|
**Implementation**:
|
|
|
|
- ✅ Charon masks API keys in logs (prevents exposure of personal data)
|
|
- ✅ Secure file permissions (0600) protect sensitive data
|
|
- ✅ Log retention policies prevent indefinite storage
|
|
- ⚠️ Ensure API keys don't contain personal identifiers
|
|
|
|
**Reference**: [GDPR Article 32 - Security of processing](https://gdpr-info.eu/art-32-gdpr/)
|
|
|
|
---
|
|
|
|
### PCI-DSS (Payment Card Industry Data Security Standard)
|
|
|
|
**Applicable if**: Processing, storing, or transmitting credit card data
|
|
|
|
**Requirements**:
|
|
|
|
1. **Requirement 3.4**: Render PAN unreadable (encryption, masking)
|
|
2. **Requirement 8.2**: Strong authentication
|
|
3. **Requirement 10.2**: Audit trails
|
|
4. **Requirement 10.7**: Retain audit logs for 1 year
|
|
|
|
**Implementation**:
|
|
|
|
- ✅ Charon uses masking for sensitive credentials (same principle for PAN)
|
|
- ✅ Secure file permissions align with access control requirements
|
|
- ⚠️ Charon doesn't handle payment cards directly (delegated to payment processors)
|
|
|
|
**Reference**: [PCI-DSS Quick Reference Guide](https://www.pcisecuritystandards.org/)
|
|
|
|
---
|
|
|
|
### SOC 2 (System and Organization Controls)
|
|
|
|
**Applicable if**: SaaS providers, cloud services
|
|
|
|
**Trust Service Criteria**:
|
|
|
|
1. **CC6.1**: Logical access controls (authentication, authorization)
|
|
2. **CC6.6**: Encryption of data in transit
|
|
3. **CC6.7**: Encryption of data at rest
|
|
4. **CC7.2**: Monitoring and detection (logging, alerting)
|
|
|
|
**Implementation**:
|
|
|
|
- ✅ API key validation ensures strong credentials (CC6.1)
|
|
- ✅ File permissions (0600) protect data at rest (CC6.7)
|
|
- ✅ Masked logging enables monitoring without exposing secrets (CC7.2)
|
|
- ⚠️ Ensure HTTPS enforcement for data in transit (CC6.6)
|
|
|
|
**Reference**: [SOC 2 Trust Services Criteria](https://www.aicpa.org/interestareas/frc/assuranceadvisoryservices/trustdataintegritytaskforce)
|
|
|
|
---
|
|
|
|
### ISO 27001 (Information Security Management)
|
|
|
|
**Applicable to**: Any organization implementing ISMS
|
|
|
|
**Key Controls**:
|
|
|
|
1. **A.9.4.3**: Password management systems
|
|
2. **A.10.1.1**: Cryptographic controls
|
|
3. **A.12.4.1**: Event logging
|
|
4. **A.18.1.5**: Protection of personal data
|
|
|
|
**Implementation**:
|
|
|
|
- ✅ API key format validation (minimum 16 chars, charset restrictions)
|
|
- ✅ Key rotation procedures documented
|
|
- ✅ Secure storage with file permissions (0600)
|
|
- ✅ Masked logging protects sensitive data
|
|
|
|
**Reference**: [ISO 27001:2013 Controls](https://www.iso.org/standard/54534.html)
|
|
|
|
---
|
|
|
|
### Compliance Summary Table
|
|
|
|
| Framework | Key Requirement | Charon Implementation | Status |
|
|
|-----------|----------------|----------------------|--------|
|
|
| **GDPR** | Data protection (Art. 32) | API key masking, secure storage | ✅ Compliant |
|
|
| **PCI-DSS** | Render PAN unreadable (Req. 3.4) | Masking utility (same principle) | ✅ Aligned |
|
|
| **SOC 2** | Logical access controls (CC6.1) | Key validation, file permissions | ✅ Compliant |
|
|
| **ISO 27001** | Password management (A.9.4.3) | Key rotation, validation | ✅ Compliant |
|
|
|
|
---
|
|
|
|
## Security Testing
|
|
|
|
### Static Analysis
|
|
|
|
```bash
|
|
# Run CodeQL security scan
|
|
.github/skills/scripts/skill-runner.sh security-codeql-scan
|
|
|
|
# Expected: 0 CWE-312/315/359 findings
|
|
```
|
|
|
|
### Unit Tests
|
|
|
|
```bash
|
|
# Run security-focused unit tests
|
|
go test ./backend/internal/api/handlers -run TestMaskAPIKey -v
|
|
go test ./backend/internal/api/handlers -run TestValidateAPIKeyFormat -v
|
|
go test ./backend/internal/api/handlers -run TestSaveKeyToFile_SecurePermissions -v
|
|
```
|
|
|
|
### Integration Tests
|
|
|
|
```bash
|
|
# Run Playwright E2E tests
|
|
.github/skills/scripts/skill-runner.sh test-e2e-playwright
|
|
|
|
# Check for exposed secrets in test logs
|
|
grep -i "api[_-]key\|token\|password" playwright-report/index.html
|
|
# Expected: Only masked values (abcd...xyz9) or no matches
|
|
```
|
|
|
|
### Penetration Testing
|
|
|
|
**Recommended schedule**: Annual or after major releases
|
|
|
|
**Focus areas**:
|
|
|
|
1. Authentication bypass
|
|
2. Authorization vulnerabilities
|
|
3. SQL injection
|
|
4. Path traversal
|
|
5. Information disclosure (logs, errors)
|
|
6. Rate limiting effectiveness
|
|
|
|
---
|
|
|
|
## Security Checklist
|
|
|
|
### Before Every Release
|
|
|
|
- [ ] Run CodeQL scan (0 critical findings)
|
|
- [ ] Run unit tests (100% pass)
|
|
- [ ] Run integration tests (100% pass)
|
|
- [ ] Check for hardcoded secrets (TruffleHog, Semgrep)
|
|
- [ ] Review log output for sensitive data exposure
|
|
- [ ] Verify file permissions (secrets: 0600, configs: 0640)
|
|
- [ ] Update dependencies (no known CVEs)
|
|
- [ ] Review security documentation updates
|
|
- [ ] Test secret rotation procedure
|
|
- [ ] Verify HTTPS enforcement in production
|
|
|
|
### During Code Review
|
|
|
|
- [ ] No secrets in environment variables (use .env)
|
|
- [ ] All secrets are masked in logs
|
|
- [ ] Input validation on all user-provided data
|
|
- [ ] Parameterized queries (no string concatenation)
|
|
- [ ] Secure file permissions (0600 for secrets)
|
|
- [ ] Error messages don't reveal sensitive info
|
|
- [ ] No commented-out secrets or debugging code
|
|
- [ ] Security tests added for new features
|
|
|
|
### After Security Incident
|
|
|
|
- [ ] Rotate all affected secrets immediately
|
|
- [ ] Audit access logs for unauthorized use
|
|
- [ ] Purge logs containing exposed secrets
|
|
- [ ] Notify affected users (if PII exposed)
|
|
- [ ] Update incident response procedures
|
|
- [ ] Document lessons learned
|
|
- [ ] Implement additional controls to prevent recurrence
|
|
|
|
---
|
|
|
|
## Resources
|
|
|
|
### Internal Documentation
|
|
|
|
- [API Key Handling Guide](./security/api-key-handling.md)
|
|
- [ARCHITECTURE.md](../ARCHITECTURE.md)
|
|
- [CONTRIBUTING.md](../CONTRIBUTING.md)
|
|
|
|
### External References
|
|
|
|
- [OWASP Top 10](https://owasp.org/Top10/)
|
|
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
|
|
- [CWE Top 25](https://cwe.mitre.org/top25/)
|
|
- [NIST Cybersecurity Framework](https://www.nist.gov/cyberframework)
|
|
- [SANS Top 25 Software Errors](https://www.sans.org/top25-software-errors/)
|
|
|
|
### Security Standards
|
|
|
|
- [GDPR Official Text](https://gdpr-info.eu/)
|
|
- [PCI-DSS Standards](https://www.pcisecuritystandards.org/)
|
|
- [SOC 2 Trust Services](https://www.aicpa.org/)
|
|
- [ISO 27001](https://www.iso.org/standard/54534.html)
|
|
|
|
---
|
|
|
|
## Updates
|
|
|
|
| Date | Change | Author |
|
|
|------|--------|--------|
|
|
| 2026-02-03 | Initial security practices documentation | GitHub Copilot |
|
|
|
|
---
|
|
|
|
**Last Updated**: 2026-02-03
|
|
**Next Review**: 2026-05-03 (Quarterly)
|
|
**Owner**: Security Team / Lead Developer
|