mirror of
https://github.com/zadam/trilium.git
synced 2025-11-03 03:46:37 +01:00
feat(docs): completely redo documentation
This commit is contained in:
593
docs/Security/Protected-Notes-Encryption-Guide.md
vendored
Normal file
593
docs/Security/Protected-Notes-Encryption-Guide.md
vendored
Normal file
@@ -0,0 +1,593 @@
|
||||
# Protected Notes and Encryption System
|
||||
|
||||
Trilium's Protected Notes system provides robust, selective encryption for sensitive content using industry-standard AES encryption with scrypt-based key derivation. This guide covers setup, usage, and security considerations.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Encryption Stack
|
||||
|
||||
- **Cipher**: AES-128-CBC (Advanced Encryption Standard, Cipher Block Chaining mode)
|
||||
- **Key Derivation**: Scrypt (N=16384, r=8, p=1) with random salt
|
||||
- **Integrity Protection**: SHA-1 digest verification
|
||||
- **Encoding**: Base64 for storage and transmission
|
||||
|
||||
### Key Hierarchy
|
||||
|
||||
```
|
||||
Master Password (User Input)
|
||||
↓
|
||||
Password-Derived Key (Scrypt + Salt)
|
||||
↓
|
||||
Encrypted Data Key (AES-128-CBC)
|
||||
↓
|
||||
Session Data Key (In Memory)
|
||||
↓
|
||||
Protected Content (AES-128-CBC)
|
||||
```
|
||||
|
||||
## Setting Up Protected Notes
|
||||
|
||||
### Initial Configuration
|
||||
|
||||
1. **Set Master Password**
|
||||
- Access via Options → Security → Password
|
||||
- Minimum 8 characters (recommend 12+)
|
||||
- Use unique, complex password
|
||||
|
||||
2. **Configure Session Settings**
|
||||
- Session timeout (default: 10 minutes)
|
||||
- Auto-logout on inactivity
|
||||
- Multi-client session handling
|
||||
|
||||
3. **Security Options**
|
||||
- Password strength requirements
|
||||
- Session notification preferences
|
||||
- Audit logging settings
|
||||
|
||||
### Creating Protected Notes
|
||||
|
||||
#### Method 1: Right-Click Menu
|
||||
1. Right-click any note in the tree
|
||||
2. Select "Toggle Protected Status"
|
||||
3. Confirm protection in dialog
|
||||
|
||||
#### Method 2: Note Actions Menu
|
||||
1. Open note editor
|
||||
2. Click Actions button (⚙️)
|
||||
3. Select "Protect this note"
|
||||
|
||||
#### Method 3: Keyboard Shortcut
|
||||
1. Select note
|
||||
2. Press `Ctrl+Shift+U` (toggle protection)
|
||||
|
||||
### Bulk Protection
|
||||
|
||||
Protect multiple notes simultaneously:
|
||||
|
||||
1. **Subtree Protection**
|
||||
- Right-click parent note
|
||||
- Select "Protect subtree"
|
||||
- All child notes become protected
|
||||
|
||||
2. **Batch Selection**
|
||||
- Use Ctrl+click to select multiple notes
|
||||
- Right-click → "Protect selected notes"
|
||||
|
||||
## Protected Sessions
|
||||
|
||||
### Session Lifecycle
|
||||
|
||||
#### Entering Protected Session
|
||||
|
||||
**Method 1: Manual Entry**
|
||||
```
|
||||
1. Click shield icon in toolbar
|
||||
2. Enter master password
|
||||
3. Session activates (shield turns green)
|
||||
```
|
||||
|
||||
**Method 2: Automatic Prompt**
|
||||
```
|
||||
1. Access protected note
|
||||
2. Password dialog appears
|
||||
3. Enter credentials to continue
|
||||
```
|
||||
|
||||
**Method 3: Keyboard Shortcut**
|
||||
```
|
||||
Press Ctrl+Shift+P to enter protected session
|
||||
```
|
||||
|
||||
#### Session Management
|
||||
|
||||
- **Active Session**: Shield icon green, protected content accessible
|
||||
- **Session Timeout**: Configurable (60-3600 seconds)
|
||||
- **Activity Tracking**: Timeout resets with each protected note access
|
||||
- **Multi-Client**: Independent sessions per browser/client
|
||||
|
||||
#### Leaving Protected Session
|
||||
|
||||
**Manual Logout**:
|
||||
- Click green shield icon
|
||||
- Select "Leave protected session"
|
||||
|
||||
**Automatic Logout**:
|
||||
- Inactivity timeout
|
||||
- Browser/application close
|
||||
- Security state changes
|
||||
|
||||
### Session Security Features
|
||||
|
||||
#### Timeout Configuration
|
||||
|
||||
```typescript
|
||||
// Access via Options → Protected Session
|
||||
protectedSessionTimeout: number // seconds (default: 600)
|
||||
protectedSessionWarning: boolean // show timeout warnings
|
||||
```
|
||||
|
||||
#### Security Events
|
||||
|
||||
- Session entry/exit logged
|
||||
- Failed authentication attempts tracked
|
||||
- Unusual access patterns detected
|
||||
- Audit trail maintained
|
||||
|
||||
## Encryption Technical Details
|
||||
|
||||
### Encryption Process Flow
|
||||
|
||||
```
|
||||
Plaintext Data
|
||||
↓
|
||||
1. Compute SHA-1 digest (integrity check)
|
||||
↓
|
||||
2. Prepend digest (4 bytes) to plaintext
|
||||
↓
|
||||
3. Generate random IV (16 bytes)
|
||||
↓
|
||||
4. Encrypt with AES-128-CBC (data key + IV)
|
||||
↓
|
||||
5. Prepend IV to encrypted data
|
||||
↓
|
||||
6. Encode as Base64
|
||||
↓
|
||||
Stored Ciphertext
|
||||
```
|
||||
|
||||
### Decryption Process Flow
|
||||
|
||||
```
|
||||
Base64 Ciphertext
|
||||
↓
|
||||
1. Decode from Base64
|
||||
↓
|
||||
2. Extract IV (first 16 bytes)
|
||||
↓
|
||||
3. Extract encrypted data (remaining bytes)
|
||||
↓
|
||||
4. Decrypt with AES-128-CBC (data key + IV)
|
||||
↓
|
||||
5. Extract digest (first 4 bytes) and plaintext
|
||||
↓
|
||||
6. Verify digest matches computed SHA-1
|
||||
↓
|
||||
Verified Plaintext Data
|
||||
```
|
||||
|
||||
### Key Derivation Details
|
||||
|
||||
#### Scrypt Parameters
|
||||
|
||||
```typescript
|
||||
const scryptParams = {
|
||||
N: 16384, // CPU/memory cost (2^14)
|
||||
r: 8, // Block size parameter
|
||||
p: 1, // Parallelization parameter
|
||||
dkLen: 32 // Derived key length (bytes)
|
||||
};
|
||||
```
|
||||
|
||||
#### Salt Generation
|
||||
|
||||
- **Password Salt**: 32-byte random salt for password verification
|
||||
- **Data Key Salt**: 32-byte random salt for data key encryption
|
||||
- **Cryptographic Quality**: Node.js crypto.randomBytes()
|
||||
|
||||
#### Key Storage
|
||||
|
||||
```sql
|
||||
-- Options table entries
|
||||
INSERT INTO options VALUES
|
||||
('passwordVerificationSalt', '<32-byte-salt>'),
|
||||
('passwordDerivedKeySalt', '<32-byte-salt>'),
|
||||
('passwordVerificationHash', '<scrypt-hash>'),
|
||||
('encryptedDataKey', '<encrypted-key>');
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Threat Model
|
||||
|
||||
#### Protected Against
|
||||
|
||||
✅ **Database Theft**: Encrypted content unreadable without password
|
||||
✅ **Backup Compromise**: Encrypted backups maintain protection
|
||||
✅ **Network Interception**: Data encrypted at rest and in transit
|
||||
✅ **Server Breach**: Server never stores plaintext of protected content
|
||||
✅ **Physical Storage Access**: Database files encrypted
|
||||
|
||||
#### Not Protected Against
|
||||
|
||||
❌ **Keyloggers**: Malware capturing password input
|
||||
❌ **Memory Dumps**: Active sessions store keys in memory
|
||||
❌ **Screen Capture**: Displayed content vulnerable
|
||||
❌ **Social Engineering**: User convinced to reveal password
|
||||
❌ **Endpoint Compromise**: Malware on user device
|
||||
|
||||
### Security Limitations
|
||||
|
||||
#### Metadata Exposure
|
||||
|
||||
- **Note Structure**: Tree hierarchy visible
|
||||
- **Timestamps**: Creation/modification dates unencrypted
|
||||
- **Note IDs**: Internal identifiers exposed
|
||||
- **Attributes**: Some metadata may be unencrypted
|
||||
|
||||
#### Search Limitations
|
||||
|
||||
- **Full-text Search**: Protected content excluded from search index
|
||||
- **Cross-references**: Links to protected notes may be limited
|
||||
- **Content Analysis**: Automated analysis features disabled
|
||||
|
||||
### Best Practices
|
||||
|
||||
#### Password Management
|
||||
|
||||
1. **Strong Passwords**
|
||||
- Minimum 12 characters
|
||||
- Mix of letters, numbers, symbols
|
||||
- Avoid common patterns
|
||||
|
||||
2. **Password Storage**
|
||||
- Use reputable password manager
|
||||
- Store recovery information securely
|
||||
- Don't reuse passwords
|
||||
|
||||
3. **Regular Updates**
|
||||
- Change password periodically
|
||||
- Update after suspected compromise
|
||||
- Coordinate with team members
|
||||
|
||||
#### Session Management
|
||||
|
||||
1. **Timeout Configuration**
|
||||
- Set appropriate timeout for usage pattern
|
||||
- Shorter timeouts for sensitive environments
|
||||
- Balance security with usability
|
||||
|
||||
2. **Access Control**
|
||||
- Lock workstation when away
|
||||
- Use screen savers with password
|
||||
- Log out of shared computers
|
||||
|
||||
3. **Multi-Device Usage**
|
||||
- Use consistent passwords across devices
|
||||
- Monitor active sessions
|
||||
- Revoke compromised device access
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Decryption Failures
|
||||
|
||||
**Error**: "Could not decrypt string"
|
||||
|
||||
**Causes**:
|
||||
- Incorrect password
|
||||
- Corrupted encrypted data
|
||||
- Database schema issues
|
||||
- Memory corruption
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Check database integrity
|
||||
sqlite3 document.db "PRAGMA integrity_check;"
|
||||
|
||||
# Verify options table
|
||||
sqlite3 document.db "SELECT name, length(value) FROM options WHERE name LIKE 'password%';"
|
||||
|
||||
# Test password verification
|
||||
# (In protected session troubleshooting)
|
||||
```
|
||||
|
||||
#### Session Problems
|
||||
|
||||
**Error**: Protected session won't start
|
||||
|
||||
**Diagnostic Steps**:
|
||||
1. Check browser console for JavaScript errors
|
||||
2. Verify network connectivity
|
||||
3. Review server logs for authentication errors
|
||||
4. Test with fresh browser session
|
||||
|
||||
**Solutions**:
|
||||
```bash
|
||||
# Clear browser data
|
||||
# Restart Trilium server
|
||||
# Check file permissions on database
|
||||
# Verify encryption keys in options table
|
||||
```
|
||||
|
||||
#### Performance Issues
|
||||
|
||||
**Symptoms**: Slow password verification, high CPU usage
|
||||
|
||||
**Optimization**:
|
||||
```typescript
|
||||
// Advanced users only - modify scrypt parameters
|
||||
const optimizedParams = {
|
||||
N: 8192, // Reduce for faster verification
|
||||
r: 8, // Keep default
|
||||
p: 1 // Keep default
|
||||
};
|
||||
```
|
||||
|
||||
**Hardware Recommendations**:
|
||||
- Minimum 4GB RAM for scrypt operations
|
||||
- Modern CPU with AES-NI support
|
||||
- SSD storage for database files
|
||||
|
||||
### Recovery Procedures
|
||||
|
||||
#### Forgotten Password
|
||||
|
||||
**No Built-in Recovery**: Trilium cannot recover forgotten passwords
|
||||
|
||||
**Options**:
|
||||
1. **Restore from Backup**: Use backup with known password
|
||||
2. **Partial Recovery**: Export unprotected content
|
||||
3. **Complete Reset**: Lose all protected content
|
||||
|
||||
```bash
|
||||
# Reset password (loses all protected content)
|
||||
sqlite3 document.db "
|
||||
UPDATE options SET value = '' WHERE name IN (
|
||||
'passwordVerificationSalt',
|
||||
'passwordDerivedKeySalt',
|
||||
'passwordVerificationHash',
|
||||
'encryptedDataKey'
|
||||
);
|
||||
"
|
||||
```
|
||||
|
||||
#### Data Corruption
|
||||
|
||||
**Corruption Detection**:
|
||||
- Decryption failures
|
||||
- Database integrity errors
|
||||
- Inconsistent note content
|
||||
|
||||
**Recovery Steps**:
|
||||
1. Stop Trilium application
|
||||
2. Create backup of current database
|
||||
3. Run database integrity check
|
||||
4. Restore from known good backup
|
||||
5. Compare and merge changes if needed
|
||||
|
||||
```bash
|
||||
# Database integrity check
|
||||
sqlite3 document.db "PRAGMA integrity_check;"
|
||||
|
||||
# Quick corruption check
|
||||
sqlite3 document.db "SELECT COUNT(*) FROM notes WHERE isProtected = 1;"
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### System Requirements
|
||||
|
||||
#### Minimum Requirements
|
||||
- **CPU**: 1GHz processor with AES support
|
||||
- **RAM**: 2GB available memory
|
||||
- **Storage**: 100MB free disk space
|
||||
- **Network**: Stable connection for sync
|
||||
|
||||
#### Recommended Configuration
|
||||
- **CPU**: Multi-core processor with AES-NI
|
||||
- **RAM**: 8GB+ for large datasets
|
||||
- **Storage**: SSD for database files
|
||||
- **Network**: Broadband for sync operations
|
||||
|
||||
### Performance Tuning
|
||||
|
||||
#### Database Optimization
|
||||
|
||||
```sql
|
||||
-- Optimize database performance
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = NORMAL;
|
||||
PRAGMA cache_size = 10000;
|
||||
PRAGMA temp_store = MEMORY;
|
||||
```
|
||||
|
||||
#### Memory Management
|
||||
|
||||
- **Session Caching**: Keep frequently accessed protected notes in memory
|
||||
- **Garbage Collection**: Clear old session data regularly
|
||||
- **Resource Monitoring**: Monitor memory usage patterns
|
||||
|
||||
#### Network Optimization
|
||||
|
||||
- **Compression**: Enable content compression
|
||||
- **Caching**: Use appropriate cache headers
|
||||
- **Connection Pooling**: Optimize database connections
|
||||
|
||||
## Compliance and Auditing
|
||||
|
||||
### Encryption Standards
|
||||
|
||||
#### Algorithm Compliance
|
||||
- **AES-128**: NIST approved, FIPS 140-2 Level 1
|
||||
- **Scrypt**: RFC 7914 standard
|
||||
- **SHA-1**: NIST standard (integrity only)
|
||||
|
||||
#### Key Management
|
||||
- **Generation**: Cryptographically secure random number generator
|
||||
- **Storage**: Encrypted at rest
|
||||
- **Transmission**: Never transmitted in plaintext
|
||||
- **Destruction**: Securely cleared from memory
|
||||
|
||||
### Audit Requirements
|
||||
|
||||
#### Logging Events
|
||||
```typescript
|
||||
// Security events logged
|
||||
enum AuditEvents {
|
||||
PROTECTED_SESSION_START = 'protected_session_start',
|
||||
PROTECTED_SESSION_END = 'protected_session_end',
|
||||
PROTECTED_NOTE_ACCESS = 'protected_note_access',
|
||||
ENCRYPTION_FAILURE = 'encryption_failure',
|
||||
DECRYPTION_FAILURE = 'decryption_failure',
|
||||
PASSWORD_CHANGE = 'password_change'
|
||||
}
|
||||
```
|
||||
|
||||
#### Compliance Reports
|
||||
- Authentication success/failure rates
|
||||
- Protected content access patterns
|
||||
- Security event timelines
|
||||
- Performance metrics
|
||||
|
||||
### Regulatory Considerations
|
||||
|
||||
#### GDPR Compliance
|
||||
- **Data Protection**: AES encryption provides technical safeguards
|
||||
- **Right to Erasure**: Secure deletion of encryption keys
|
||||
- **Data Portability**: Export capabilities for protected content
|
||||
- **Privacy by Design**: Encryption built into architecture
|
||||
|
||||
#### HIPAA Requirements
|
||||
- **Administrative Safeguards**: Access controls and audit trails
|
||||
- **Physical Safeguards**: Workstation security recommendations
|
||||
- **Technical Safeguards**: AES encryption meets requirements
|
||||
|
||||
#### Industry Standards
|
||||
- **ISO 27001**: Information security management
|
||||
- **SOC 2**: Security and availability controls
|
||||
- **PCI DSS**: Data protection requirements
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Encryption Parameters
|
||||
|
||||
**Warning**: Modifying encryption parameters requires expert knowledge and may break compatibility with future versions.
|
||||
|
||||
```typescript
|
||||
// File: apps/server/src/services/encryption/my_scrypt.ts
|
||||
const customScryptParams = {
|
||||
N: 32768, // Higher security (slower)
|
||||
r: 8, // Block size
|
||||
p: 2 // Parallel processing
|
||||
};
|
||||
```
|
||||
|
||||
### Integration Examples
|
||||
|
||||
#### Backend Script Access
|
||||
|
||||
```javascript
|
||||
// Accessing protected notes in backend scripts
|
||||
const protectedNote = api.getNote(noteId);
|
||||
|
||||
if (protectedNote.isProtected) {
|
||||
// Content is encrypted unless in protected session
|
||||
if (api.isProtectedSessionAvailable()) {
|
||||
const content = protectedNote.getContent();
|
||||
// Process decrypted content
|
||||
} else {
|
||||
// Request protected session
|
||||
throw new Error('Protected session required');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### API Integration
|
||||
|
||||
```typescript
|
||||
// External API access to protected content
|
||||
const etapiToken = 'your-etapi-token';
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${etapiToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
// Note: ETAPI cannot access protected content
|
||||
// Protected session must be established in web interface
|
||||
```
|
||||
|
||||
## Backup and Migration
|
||||
|
||||
### Backup Strategies
|
||||
|
||||
#### Complete Database Backup
|
||||
```bash
|
||||
# Stop Trilium first
|
||||
sqlite3 document.db ".backup backup-$(date +%Y%m%d).db"
|
||||
|
||||
# Compressed backup
|
||||
tar czf trilium-backup-$(date +%Y%m%d).tar.gz \
|
||||
document.db session_secret.txt config.ini
|
||||
```
|
||||
|
||||
#### Encrypted Backup
|
||||
```bash
|
||||
# GPG encrypted backup
|
||||
tar czf - trilium-data/ | \
|
||||
gpg --cipher-algo AES256 --compress-algo 1 --symmetric \
|
||||
--output trilium-backup-$(date +%Y%m%d).tar.gz.gpg
|
||||
```
|
||||
|
||||
#### Protected Content Export
|
||||
```javascript
|
||||
// Export during protected session
|
||||
const protectedNotes = api.getNotesByLabel('#protected');
|
||||
protectedNotes.forEach(note => {
|
||||
if (note.isProtected) {
|
||||
const exportData = {
|
||||
title: note.title,
|
||||
content: note.getContent(),
|
||||
attributes: note.getAttributes()
|
||||
};
|
||||
// Save to secure location
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Migration Procedures
|
||||
|
||||
#### Same-Password Migration
|
||||
1. Export data from source installation
|
||||
2. Create fresh installation
|
||||
3. Set same master password
|
||||
4. Import exported data
|
||||
5. Verify protected content access
|
||||
|
||||
#### Password Change Migration
|
||||
1. Enter protected session in source
|
||||
2. Export all protected content unencrypted
|
||||
3. Create new installation with new password
|
||||
4. Import content (will be re-encrypted)
|
||||
5. Verify all content accessible
|
||||
|
||||
#### Cross-Platform Migration
|
||||
```bash
|
||||
# Export from source platform
|
||||
trilium-server --export=/path/to/export.zip
|
||||
|
||||
# Import to target platform
|
||||
trilium-server --import=/path/to/export.zip
|
||||
```
|
||||
|
||||
Remember: The security of your protected notes depends on maintaining good password practices and following security best practices for your overall system environment.
|
||||
Reference in New Issue
Block a user