Files
gh-tachyon-beep-skillpacks-…/skills/using-technical-writer/security-aware-documentation.md
2025-11-30 08:59:40 +08:00

504 lines
13 KiB
Markdown

# Security-Aware Documentation
## Overview
Document systems without compromising security. Core principle: **Documentation should inform, not expose**.
**Key insight**: Examples with real credentials/PII leak secrets. Obviously fake examples are safe and clear.
## When to Use
Load this skill when:
- Documenting authentication/authorization
- Creating API examples with credentials
- Writing about systems handling PII or classified data
- Documenting security features
**Symptoms you need this**:
- "How do I show API key example without exposing real keys?"
- Writing documentation for healthcare/finance systems
- Creating examples with user data
- Documenting security configurations
**Don't use for**:
- General documentation without security concerns
- Internal-only docs (though still good practice)
## Sanitizing Examples
### Rule 1: Never Use Real Credentials
**WRONG**:
```bash
# Don't mask real secrets
curl -H "Authorization: Bearer sk_live_51Hx***REDACTED***" \
https://api.example.com/users
```
**Problem**: Pattern `sk_live_51Hx...` suggests real Stripe key structure. Reader might think they should unmask it.
**RIGHT**:
```bash
# Generate obviously fake credentials
curl -H "Authorization: Bearer fake_key_abc123_for_docs_only" \
https://api.example.com/users
```
**Better**: Clearly fake, no confusion possible.
### Rule 2: Use Obviously Fake Values
**Fake Credentials Pattern**:
```
fake_[type]_[random]_for_docs_only
```
**Examples**:
- API key: `fake_api_key_abc123_for_docs_only`
- JWT token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.FAKE_TOKEN_FOR_DOCUMENTATION.fake_signature_do_not_use`
- Database password: `fake_password_p@ssw0rd_example_only`
- SSH key: `fake_ssh_key_AAAAB3NzaC1yc2EAAAADAQABAAABAQ... (truncated for docs)`
**Fake PII Pattern**:
```
[common_name]@example.com
000-00-0000 (SSN)
+1-555-0123 (phone - 555 is reserved for fiction)
```
**Examples**:
- Email: `jane.doe@example.com`, `user@example.org`
- SSN: `000-00-0000`, `123-45-6789` (invalid format)
- Phone: `+1-555-0100`, `+1-555-0199`
- Address: `123 Main Street, Anytown, ST 12345`
### Rule 3: Use Reserved Domains
**Reserved for documentation** (RFC 2606):
- `example.com`
- `example.net`
- `example.org`
- `test.com` (not official but commonly accepted)
**WRONG**:
```javascript
const API_URL = 'https://api.acmecorp.com'; // Real company?
```
**RIGHT**:
```javascript
const API_URL = 'https://api.example.com'; // Obviously fake
```
### Rule 4: Complete Fake Examples (Not Partial)
**WRONG**:
```python
# Partial example - reader must guess
api_key = "YOUR_API_KEY_HERE"
client = APIClient(api_key)
```
**Problem**: Reader doesn't know what `YOUR_API_KEY_HERE` should look like.
**RIGHT**:
```python
# Complete fake example - copy-paste-run (with fake backend)
api_key = "fake_api_key_abc123_for_docs_only"
client = APIClient(api_key)
# For real usage:
# 1. Get API key from https://dashboard.example.com/settings
# 2. Replace fake_api_key_abc123_for_docs_only with your real key
# 3. Never commit real keys to git
```
**Better**: Complete example + clear instructions for real usage.
## Threat Disclosure Decisions
### Document: Security Features Users Must Configure
**DO document**:
```markdown
## Security Configuration
### Enable MFA (Required for Production)
Multi-factor authentication prevents unauthorized access even if passwords are compromised.
Enable MFA for all admin accounts:
\```bash
user-admin mfa enable --user admin@example.com --method totp
\```
**Security impact**: Without MFA, stolen passwords grant full access.
```
### Document: Security Best Practices
**DO document**:
```markdown
## Hardening Guide
### Disable Unused Services
**Threat**: Unused services increase attack surface.
Disable SSH if not needed:
\```bash
systemctl disable sshd
systemctl stop sshd
\```
**Verification**: `systemctl status sshd` should show "inactive (dead)"
```
### Don't Document: Specific Vulnerabilities
**DON'T document**:
```markdown
## Known Issues
### CVE-2024-12345: SQL Injection in /api/users Endpoint
Vulnerable code in `user_controller.py:45`:
\```python
query = f"SELECT * FROM users WHERE id = {user_id}" # Vulnerable!
\```
Attacker can inject SQL via: `/api/users?id=1 OR 1=1`
```
**Problem**: Provides exploit guide to attackers.
**DO instead**: Coordinate with security team for disclosure. Document fix after patch released:
```markdown
## Security Updates
### Version 2.1.5 (2024-03-15)
**Security fix**: Resolved input validation issue in user API (CVE-2024-12345).
Upgrade immediately.
For technical details, see our security advisory: [link]
```
### Don't Document: Internal Security Architecture (Unless Necessary)
**DON'T document** (in public docs):
```markdown
## Internal Security Architecture
Our secrets vault runs on ec2-10-0-1-50.internal with:
- Port 8200 (HTTP API)
- Port 8201 (cluster communication)
- Root token stored in S3 bucket: company-secrets-prod
- Unsealing keys split across: admin1@company.com, admin2@company.com, admin3@company.com
```
**Problem**: Reveals infrastructure details aiding attackers (IP addresses, ports, bucket names, key custodians).
**DO instead**: Document what users need, abstract internals:
```markdown
## Secrets Management
Secrets are stored in an encrypted vault. To access secrets:
1. Request access via [access-request-form]
2. Use provided vault token
3. Tokens expire after 8 hours
See [secrets-access-guide] for details.
```
## Compliance Sensitivity
### Rule: Document Controls Without Revealing Weaknesses
**WRONG**:
```markdown
## SOC2 Compliance
### Access Control (CC6.1)
**Control**: Role-based access control (RBAC)
**Current gaps**:
- Admin users can bypass RBAC via debug mode (known issue #245)
- No access reviews conducted (planned for Q3)
- 3 dormant admin accounts still active (cleanup delayed)
```
**Problem**: Audit report publicly reveals control weaknesses.
**RIGHT**:
```markdown
## SOC2 Compliance
### Access Control (CC6.1)
**Control**: Role-based access control (RBAC)
**Implementation**:
- Authentication: MFA required for admin accounts
- Authorization: Permissions enforced at API layer and database layer
- Access reviews: Quarterly review of all privileged accounts
- Account lifecycle: Automated disablement after 30 days inactivity
**Audit evidence**: Available to authorized auditors via [compliance-portal]
```
**Better**: Focus on what exists, keep gaps internal.
## Redaction Patterns
### Logs: Redact Sensitive Data
**WRONG**:
```
[2024-03-15 10:23:45] User login: user=john.smith@acme.com, password=MyP@ssw0rd123, token=eyJhbGci...
[2024-03-15 10:24:12] API call: GET /users/12345, auth_token=sk_live_51HxAbC123...
```
**RIGHT**:
```
[2024-03-15 10:23:45] User login: user=john.smith@acme.com, password=[REDACTED], token=[REDACTED]
[2024-03-15 10:24:12] API call: GET /users/12345, auth_token=[REDACTED]
```
**Even better** (for docs): Use fake data:
```
[2024-03-15 10:23:45] User login: user=jane.doe@example.com, password=[REDACTED], token=[REDACTED]
[2024-03-15 10:24:12] API call: GET /users/67890, auth_token=[REDACTED]
```
### Screenshots: Blur Sensitive Data
**Before sharing screenshot**:
1. Use test account (user@example.com, fake data)
2. Blur any real data (names, emails, IDs)
3. Use browser extensions: "Redact for Screenshot"
**WRONG**: Screenshot with production data visible
**RIGHT**: Screenshot with:
- Fake user names (Jane Doe, John Smith)
- Fake emails (jane@example.com)
- Blurred real data if any leaked
### Diagrams: Anonymize Infrastructure
**WRONG**:
```
[Load Balancer: lb-prod-01.company.com (52.12.34.56)]
[API Servers: api-01.internal (10.0.1.10), api-02.internal (10.0.1.11)]
[Database: postgres-master.internal (10.0.2.50)]
```
**RIGHT**:
```
[Load Balancer: lb.example.com (203.0.113.10)] # RFC 5737 documentation IP
[API Servers: api-01, api-02 (192.168.1.10-11)] # RFC 1918 private IP
[Database: postgres-master (192.168.2.50)]
```
### Database Schemas: Use Synthetic Data
**WRONG**:
```sql
-- Example users table
SELECT * FROM users LIMIT 3;
| id | email | ssn | credit_card |
|----|--------------------------|-------------|------------------|
| 1 | alice@acmecorp.com | 123-45-6789 | 4532-1234-5678-9012 |
| 2 | bob@acmecorp.com | 987-65-4321 | 5105-1051-0510-5100 |
| 3 | charlie@acmecorp.com | 456-78-9123 | 3782-822463-10005 |
```
**RIGHT**:
```sql
-- Example users table (synthetic data)
SELECT * FROM users LIMIT 3;
| id | email | ssn | credit_card |
|----|------------------------|---------------|------------------|
| 1 | alice@example.com | 000-00-0001 | 0000-0000-0000-0001 |
| 2 | bob@example.com | 000-00-0002 | 0000-0000-0000-0002 |
| 3 | charlie@example.com | 000-00-0003 | 0000-0000-0000-0003 |
```
## Security Feature Documentation
### Pattern: Threat + Configuration + Impact
```markdown
## Security Feature: [Name]
### Threat Prevented
[What attack does this prevent?]
### Configuration
[How to enable/configure?]
\```bash
[Example commands]
\```
### Security Impact
**If enabled**: [What protection do you get?]
**If disabled**: [What risk remains?]
### Verification
[How to verify it's working?]
\```bash
[Test commands]
\```
```
### Example: Rate Limiting
```markdown
## Security Feature: API Rate Limiting
### Threat Prevented
**Brute force attacks**: Attacker attempts thousands of login requests to guess passwords.
**DoS attacks**: Attacker overwhelms API with excessive requests.
### Configuration
Enable rate limiting in `config.yaml`:
\```yaml
rate_limiting:
enabled: true
max_requests: 100 # per minute per IP
window: 60 # seconds
block_duration: 300 # 5 minutes
\```
Restart API server:
\```bash
systemctl restart api-server
\```
### Security Impact
**If enabled**:
- Brute force attack limited to 100 attempts/minute (vs unlimited)
- Single IP cannot DoS entire service
- Legitimate users unaffected (typical usage: 10-20 req/min)
**If disabled**:
- Attacker can attempt 1000s of passwords per minute
- Single attacker can exhaust server resources
- No protection against credential stuffing attacks
### Verification
Test rate limit:
\```bash
# Attempt 101 requests in 1 minute
for i in {1..101}; do
curl https://api.example.com/login -d "user=test&pass=fake"
done
# Expected: First 100 succeed, 101st returns:
# HTTP 429 Too Many Requests
# Retry-After: 60
\```
Check logs:
\```bash
grep "rate_limit_exceeded" /var/log/api-server.log
# Should show: [2024-03-15 10:25:45] Rate limit exceeded: IP 203.0.113.10, endpoint /login
\```
```
## Quick Reference: Sanitization Checklist
| Data Type | ❌ Wrong | ✅ Right |
|-----------|---------|---------|
| **API Key** | `sk_live_***REDACTED***` | `fake_api_key_abc123_for_docs_only` |
| **JWT Token** | `eyJhbGci...` (real masked) | `eyJhbGci...FAKE_TOKEN_FOR_DOCUMENTATION...` |
| **Email** | `john.smith@acme.com` | `jane.doe@example.com` |
| **SSN** | `***-**-1234` | `000-00-0000` |
| **Phone** | `(555) ***-1234` | `+1-555-0100` |
| **IP Address** | `52.12.34.56` (real AWS) | `203.0.113.10` (RFC 5737 docs) |
| **Domain** | `api.acme.com` | `api.example.com` |
| **Database Password** | `p@ssw***` | `fake_password_example_only` |
## Common Mistakes
### ❌ Masking Real Secrets
**Wrong**: `sk_live_***REDACTED***` (pattern suggests real key)
**Right**: `fake_api_key_abc123_for_docs_only` (obviously fake)
**Why**: Masked secrets still leak structure. Readers might try to unmask or think it's production data.
### ❌ Using Real Company Names
**Wrong**: `curl https://api.acmecorp.com` (might be real company)
**Right**: `curl https://api.example.com` (reserved for docs)
**Why**: Avoid accidental real company references. Use RFC-designated example domains.
### ❌ Documenting Exploits Before Patch
**Wrong**: Publish CVE details with exploit code before customers patch
**Right**: Coordinate disclosure with security team, publish after patch available
**Why**: Responsible disclosure prevents weaponizing vulnerabilities before users can protect themselves.
### ❌ Incomplete Redaction
**Wrong**: Redact password but leave username + server IP
**Right**: Redact all PII/credentials and use example IPs
**Why**: Partial redaction still enables attacks. Usernames + server IPs = reconnaissance.
## Cross-References
**Use WITH this skill**:
- `muna/technical-writer/clarity-and-style` - Write clear security documentation
- `ordis/security-architect/threat-modeling` - Understand threats documentation might expose
**Use AFTER this skill**:
- `muna/technical-writer/documentation-testing` - Verify examples work (with fake credentials)
## Real-World Impact
**Projects using security-aware documentation**:
- **API Documentation (Healthcare)**: Sanitized all examples with `jane.doe@example.com`, `fake_api_key_...`. Prevented accidental PII exposure in publicly-accessible docs.
- **OAuth Flow Tutorial**: Used complete fake examples (`client_id=fake_client_abc123`) vs placeholders (`YOUR_CLIENT_ID_HERE`). Support tickets reduced 60% ("I don't know what client ID looks like").
- **Database Migration Guide**: Used synthetic data (SSN: 000-00-0000) vs redacted real data (SSN: ***-**-1234). Compliance audit passed with "exemplary PII handling in documentation".
**Key lesson**: **Obviously fake examples are clearer and safer than masked real data. Complete fake examples enable copy-paste-run testing without security risk.**