285 lines
7.7 KiB
Markdown
285 lines
7.7 KiB
Markdown
# Security Implementation Guide
|
|
|
|
This document outlines the security measures implemented in Notely.
|
|
|
|
## 🔐 Authentication Security
|
|
|
|
### Password Hashing
|
|
|
|
- **Algorithm**: Argon2id (memory-hard, resistant to GPU attacks)
|
|
- **Configuration**:
|
|
- Memory: 64 MB
|
|
- Time: 1 iteration
|
|
- Parallelism: 4 threads
|
|
- Salt: 16 random bytes (cryptographically secure)
|
|
|
|
```go
|
|
// Generated hash format:
|
|
$argon2id$v=19$m=65536,t=1,p=4$salt_hex$hash_hex
|
|
```
|
|
|
|
### JWT Tokens
|
|
|
|
- **Algorithm**: HS256 (HMAC-SHA256)
|
|
- **Access Token TTL**: 1 hour
|
|
- **Refresh Token TTL**: 7 days (HTTP-only secure cookie)
|
|
- **Claims**:
|
|
- `user_id`: User's MongoDB ObjectID
|
|
- `email`: User's email address
|
|
- `username`: User's username
|
|
- `iat`: Issued at timestamp
|
|
- `exp`: Expiration timestamp
|
|
- `iss`: Issuer (verified against hardcoded value)
|
|
|
|
### Brute-Force Protection
|
|
|
|
- Track failed login attempts in `login_attempts` collection
|
|
- Rate limit: Max 5 failed attempts per IP per 15 minutes
|
|
- Account lockout: 15 minutes after 5 consecutive failures
|
|
- Cleanup: Expired records auto-deleted via TTL index
|
|
|
|
## 🛡️ Authorization Security
|
|
|
|
### Role-Based Access Control (RBAC)
|
|
|
|
```
|
|
Space Roles:
|
|
├── Owner (all permissions)
|
|
├── Editor (create/edit/delete notes)
|
|
└── Viewer (read-only)
|
|
```
|
|
|
|
### Space-Level Data Isolation
|
|
|
|
**ALL queries include mandatory `space_id` filter**
|
|
|
|
```go
|
|
// Correct query pattern:
|
|
db.notes.find({ space_id: spaceID, ... })
|
|
|
|
// Never allow:
|
|
db.notes.find({ user_id: userID }) // ❌ Cross-space leak possible
|
|
```
|
|
|
|
### Middleware Authorization Flow
|
|
|
|
```
|
|
1. Extract JWT token → Verify signature & expiration
|
|
2. Load user credentials → Verify user is active
|
|
3. Check space membership → Verify user_id + space_id + role
|
|
4. Execute request → With space_id context
|
|
```
|
|
|
|
## 🔑 Data Encryption
|
|
|
|
### At Rest
|
|
|
|
- OAuth client secrets encrypted with AES-256-GCM
|
|
- Stored in MongoDB with encryption key in environment variables
|
|
- Decryption happens only when reading from database
|
|
|
|
```go
|
|
plaintext, err := encryptor.Encrypt(clientSecret) // Stores encrypted blob
|
|
recovered, err := encryptor.Decrypt(plaintext) // Decrypts on retrieval
|
|
```
|
|
|
|
### In Transit
|
|
|
|
- HTTPS/TLS required in production (enforced via Nginx)
|
|
- Secure cookies: `Secure`, `HttpOnly`, `SameSite=Lax` flags
|
|
- All sensitive data transmitted over encrypted channels
|
|
|
|
## 🚨 Input Validation
|
|
|
|
### Backend Validation (MANDATORY)
|
|
|
|
Every endpoint validates:
|
|
|
|
1. **Type validation** - JSON schema validation
|
|
2. **Length limits** - min/max string lengths
|
|
3. **Format validation** - email, ObjectID, URL formats
|
|
4. **Range validation** - pagination limits
|
|
|
|
```go
|
|
type CreateNoteRequest struct {
|
|
Title string `validate:"required,min=1,max=255"`
|
|
Content string `validate:"max=50000"`
|
|
Tags []string `validate:"max=100,dive,max=50"`
|
|
}
|
|
```
|
|
|
|
### Frontend Validation
|
|
|
|
- **Input sanitization** - trim whitespace
|
|
- **Format validation** - regex patterns
|
|
- **Debounced searches** - prevent query spam
|
|
- **Client-side feedback** - improve UX
|
|
|
|
### Output Sanitization
|
|
|
|
Markdown → HTML conversion sanitized with DOMPurify:
|
|
|
|
```javascript
|
|
// XSS prevention
|
|
const dirty = marked.parse(userMarkdown);
|
|
const clean = DOMPurify.sanitize(dirty);
|
|
|
|
// Blocks: scripts, event handlers, dangerous attributes
|
|
```
|
|
|
|
## 🌐 Web Security Headers
|
|
|
|
Implemented via Nginx and Go middleware:
|
|
|
|
| Header | Value | Purpose |
|
|
| --------------------------- | --------------------------------- | ------------------------------- |
|
|
| `Strict-Transport-Security` | `max-age=31536000` | Force HTTPS |
|
|
| `X-Content-Type-Options` | `nosniff` | Prevent MIME sniffing |
|
|
| `X-Frame-Options` | `DENY` | Prevent clickjacking |
|
|
| `X-XSS-Protection` | `1; mode=block` | XSS protection (older browsers) |
|
|
| `Content-Security-Policy` | Restrictive policy | Prevent XSS attacks |
|
|
| `Referrer-Policy` | `strict-origin-when-cross-origin` | Referrer control |
|
|
|
|
**CSP Policy:**
|
|
|
|
```
|
|
default-src 'self'
|
|
script-src 'self' 'unsafe-inline' (for development only)
|
|
style-src 'self' 'unsafe-inline'
|
|
img-src 'self' data: https:
|
|
font-src 'self'
|
|
connect-src 'self'
|
|
frame-ancestors 'none'
|
|
```
|
|
|
|
## 🍪 Cookie Security
|
|
|
|
### Access Token (via Authorization header)
|
|
|
|
- Stored in **memory** (not localStorage)
|
|
- Passed via `Authorization: Bearer {token}`
|
|
|
|
### Refresh Token (HTTP-only cookie)
|
|
|
|
```go
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "refresh_token",
|
|
Value: token,
|
|
Path: "/",
|
|
MaxAge: 7 * 24 * 60 * 60, // 7 days
|
|
HttpOnly: true, // ✅ Cannot access from JavaScript
|
|
Secure: true, // ✅ HTTPS only
|
|
SameSite: http.SameSiteLaxMode, // ✅ CSRF protection
|
|
})
|
|
```
|
|
|
|
## 🔄 Rate Limiting
|
|
|
|
### API Rate Limiting
|
|
|
|
- **General**: 50 requests / second per IP
|
|
- **Login**: 10 requests / second per IP
|
|
- **Burst allowance**: 20 additional requests
|
|
|
|
```nginx
|
|
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
|
limit_req zone=api_limit burst=20 nodelay;
|
|
```
|
|
|
|
### Login Attempt Tracking
|
|
|
|
- Track per email + IP combination
|
|
- Maximum 5 attempts per 15 minutes
|
|
- Exponential backoff on repeated failures
|
|
|
|
## 🔒 Database Security
|
|
|
|
### MongoDB
|
|
|
|
- **Authentication**: Username/password with role-based access
|
|
- **Network**: Runs in secure Docker network (not exposed)
|
|
- **Admin credentials**: Stored in Kubernetes Secrets (not in code)
|
|
- **Backups**: TBD - use MongoDB Atlas or encrypted backups
|
|
|
|
### Connection String
|
|
|
|
```
|
|
mongodb://admin:password@mongodb:27017/dbname?authSource=admin
|
|
```
|
|
|
|
## 🚨 Logging & Monitoring
|
|
|
|
### Security Events Logged
|
|
|
|
- ✅ User registration attempts
|
|
- ✅ Login attempts (success/failure)
|
|
- ✅ Authorization failures
|
|
- ✅ Permission denied events
|
|
- ✅ Sensitive data access
|
|
|
|
### Data NOT logged
|
|
|
|
- ❌ Passwords/hashes
|
|
- ❌ JWT tokens
|
|
- ❌ Encryption keys
|
|
- ❌ OAuth secrets
|
|
|
|
## 🧪 Security Testing
|
|
|
|
### What to Test
|
|
|
|
1. **Authentication**: Register, login, token refresh, logout
|
|
2. **Authorization**: RBAC enforcement, space isolation
|
|
3. **Input validation**: Invalid data rejection
|
|
4. **XSS prevention**: Markdown sanitization
|
|
5. **CSRF protection**: Token validation
|
|
6. **Rate limiting**: Too many requests blocked
|
|
7. **SQL Injection**: MongoDB-specific (parameterized queries safe)
|
|
|
|
### Manual Testing Commands
|
|
|
|
```bash
|
|
# Test invalid input
|
|
curl -X POST http://localhost:8080/api/v1/auth/login \
|
|
-d '{"email":"not-an-email","password":""}'
|
|
|
|
# Test expired token
|
|
curl -H "Authorization: Bearer expired.token.here" \
|
|
http://localhost:8080/api/v1/spaces
|
|
|
|
# Test rate limiting
|
|
for i in {1..100}; do
|
|
curl http://localhost:8080/api/v1/auth/login &
|
|
done
|
|
```
|
|
|
|
## 🛠️ Production Checklist
|
|
|
|
- [ ] Change default JWT_SECRET (min 32 characters)
|
|
- [ ] Change default ENCRYPTION_KEY (32 bytes)
|
|
- [ ] Generate TLS certificates (Let's Encrypt recommended)
|
|
- [ ] Configure Nginx SSL/TLS
|
|
- [ ] Enable HTTPS redirect
|
|
- [ ] Set up database backups
|
|
- [ ] Configure logging & monitoring
|
|
- [ ] Implement CORS whitelist (specific domains)
|
|
- [ ] Set up rate limiting (tuned to your traffic)
|
|
- [ ] Enable database authentication
|
|
- [ ] Use Kubernetes Network Policies
|
|
- [ ] Set up Pod Security Policies
|
|
- [ ] Enable audit logging
|
|
- [ ] Configure Secrets encryption at rest
|
|
|
|
## 📚 References
|
|
|
|
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
- [MongoDB Security](https://docs.mongodb.com/manual/security/)
|
|
- [JWT Best Practices](https://tools.ietf.org/html/rfc8949)
|
|
- [Argon2 Specification](https://github.com/P-H-C/phc-winner-argon2)
|
|
- [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
|
|
|
|
---
|
|
|
|
**Last Updated**: March 2026
|
|
**Security Level**: Production-Grade
|