Adds comprehensive documentation for the core-developer package: - architecture.md: directory structure, boot lifecycle, component patterns - security.md: threat model, authorization layers, data protection Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
269 lines
8.8 KiB
Markdown
269 lines
8.8 KiB
Markdown
---
|
|
title: Security
|
|
description: Security considerations and audit notes for core-developer
|
|
updated: 2026-01-29
|
|
---
|
|
|
|
# Security Considerations
|
|
|
|
The `core-developer` package provides powerful administrative capabilities that require careful security controls. This document outlines the security model, known risks, and mitigation strategies.
|
|
|
|
## Threat Model
|
|
|
|
### Assets Protected
|
|
|
|
1. **Application logs** - May contain tokens, passwords, PII in error messages
|
|
2. **Database access** - Read-only query execution against production data
|
|
3. **SSH keys** - Encrypted private keys for server connections
|
|
4. **Cache data** - Application cache, session data, config cache
|
|
5. **Route information** - Full application route structure
|
|
|
|
### Threat Actors
|
|
|
|
1. **Unauthorized users** - Non-Hades users attempting to access dev tools
|
|
2. **Compromised Hades account** - Attacker with valid Hades credentials
|
|
3. **SSRF/Injection** - Attacker manipulating dev tools to access internal resources
|
|
4. **Data exfiltration** - Extracting sensitive data via dev tools
|
|
|
|
## Authorization Model
|
|
|
|
### Hades Tier Requirement
|
|
|
|
All developer tools require "Hades" access, verified via the `isHades()` method on the User model. This is enforced at multiple layers:
|
|
|
|
| Layer | Implementation | File |
|
|
|-------|----------------|------|
|
|
| Middleware | `RequireHades::handle()` | `src/Middleware/RequireHades.php` |
|
|
| Component | `checkHadesAccess()` in `mount()` | All Livewire components |
|
|
| API | Controller `authorize()` calls | `src/Controllers/DevController.php` |
|
|
| Menu | `admin` flag filtering | `src/Boot.php` |
|
|
|
|
### Defence in Depth
|
|
|
|
The authorization is intentionally redundant:
|
|
- API routes use `RequireHades` middleware
|
|
- Livewire components check in `mount()`
|
|
- Some controller methods call `$this->authorize()`
|
|
|
|
This ensures access is blocked even if one layer fails.
|
|
|
|
### Known Issue: Test Environment
|
|
|
|
Tests currently pass without setting Hades tier on the test user. This suggests authorization may not be properly enforced in the test environment. See TODO.md for remediation.
|
|
|
|
## Data Protection
|
|
|
|
### Log Redaction
|
|
|
|
The `LogReaderService` automatically redacts sensitive patterns before displaying logs:
|
|
|
|
| Pattern | Replacement |
|
|
|---------|-------------|
|
|
| Stripe API keys | `[STRIPE_KEY_REDACTED]` |
|
|
| GitHub tokens | `[GITHUB_TOKEN_REDACTED]` |
|
|
| Bearer tokens | `Bearer [TOKEN_REDACTED]` |
|
|
| API keys/secrets | `[KEY_REDACTED]` / `[REDACTED]` |
|
|
| AWS credentials | `[AWS_KEY_REDACTED]` / `[AWS_SECRET_REDACTED]` |
|
|
| Database URLs | Connection strings with `[USER]:[PASS]` |
|
|
| Email addresses | Partial: `jo***@example.com` |
|
|
| IP addresses | Partial: `192.168.xxx.xxx` |
|
|
| Credit card numbers | `[CARD_REDACTED]` |
|
|
| JWT tokens | `[JWT_REDACTED]` |
|
|
| Private keys | `[PRIVATE_KEY_REDACTED]` |
|
|
|
|
**Limitation**: Patterns are regex-based and may not catch all sensitive data. Custom application secrets with non-standard formats will not be redacted.
|
|
|
|
### SSH Key Storage
|
|
|
|
Server private keys are:
|
|
- Encrypted at rest using Laravel's `encrypted` cast
|
|
- Hidden from serialization (`$hidden` array)
|
|
- Never exposed in API responses or views
|
|
- Stored in `text` column (supports long keys)
|
|
|
|
### Database Query Tool
|
|
|
|
The database query component restricts access to read-only operations:
|
|
|
|
```php
|
|
protected const ALLOWED_STATEMENTS = ['SELECT', 'SHOW', 'DESCRIBE', 'EXPLAIN'];
|
|
```
|
|
|
|
**Known Risk**: The current implementation only checks the first word, which does not prevent:
|
|
- Stacked queries: `SELECT 1; DROP TABLE users`
|
|
- Subqueries with side effects (MySQL stored procedures)
|
|
|
|
**Mitigation**: Use a proper SQL parser or prevent semicolons entirely.
|
|
|
|
### Session Data Exposure
|
|
|
|
The `/hub/api/dev/session` endpoint exposes:
|
|
- Session ID
|
|
- User IP address
|
|
- User agent (truncated to 100 chars)
|
|
- Request method and URL
|
|
|
|
This is intentional for debugging but could be abused for session hijacking if credentials are compromised.
|
|
|
|
## Rate Limiting
|
|
|
|
All API endpoints have rate limits to prevent abuse:
|
|
|
|
| Endpoint | Limit | Rationale |
|
|
|----------|-------|-----------|
|
|
| Cache clear | 10/min | Prevent DoS via rapid cache invalidation |
|
|
| Log reading | 30/min | Limit log scraping |
|
|
| Route listing | 30/min | Prevent enumeration attacks |
|
|
| Session info | 60/min | Higher limit for debugging workflows |
|
|
|
|
Rate limits are per-user (authenticated) or per-IP (unauthenticated).
|
|
|
|
## SSH Connection Security
|
|
|
|
### Key Handling
|
|
|
|
The `testConnection()` method in `Servers.php` creates a temporary key file:
|
|
|
|
```php
|
|
$tempKeyPath = sys_get_temp_dir().'/ssh_test_'.uniqid();
|
|
file_put_contents($tempKeyPath, $server->getDecryptedPrivateKey());
|
|
chmod($tempKeyPath, 0600);
|
|
```
|
|
|
|
**Risk**: Predictable filename pattern and race condition window between write and use.
|
|
|
|
**Recommendation**: Use `tempnam()` for unique filename, write with restrictive umask.
|
|
|
|
### Connection Validation
|
|
|
|
- `StrictHostKeyChecking=no` is used for convenience but prevents MITM detection
|
|
- `BatchMode=yes` prevents interactive prompts
|
|
- `ConnectTimeout=10` limits hanging connections
|
|
|
|
### Workspace Isolation
|
|
|
|
The `RemoteServerManager::connect()` method validates workspace ownership before connecting:
|
|
|
|
```php
|
|
if (! $server->belongsToCurrentWorkspace()) {
|
|
throw new SshConnectionException('Unauthorised access to server.', $server->name);
|
|
}
|
|
```
|
|
|
|
This prevents cross-tenant server access.
|
|
|
|
## Route Testing Security
|
|
|
|
### Environment Restriction
|
|
|
|
Route testing is only available in `local` and `testing` environments:
|
|
|
|
```php
|
|
public function isTestingAllowed(): bool
|
|
{
|
|
return App::environment(['local', 'testing']);
|
|
}
|
|
```
|
|
|
|
This prevents accidental data modification in production.
|
|
|
|
### Destructive Operation Warnings
|
|
|
|
Routes using `DELETE`, `PUT`, `PATCH`, `POST` methods are marked as destructive and show warnings in the UI.
|
|
|
|
### CSRF Consideration
|
|
|
|
Test requests bypass CSRF as they are internal requests. The `X-Requested-With: XMLHttpRequest` header is set by default.
|
|
|
|
## Cookie Security
|
|
|
|
### Hades Cookie
|
|
|
|
The `SetHadesCookie` listener sets a cookie on login:
|
|
|
|
| Attribute | Value | Purpose |
|
|
|-----------|-------|---------|
|
|
| Value | Encrypted token | Validates Hades status |
|
|
| Duration | 1 year | Long-lived for convenience |
|
|
| HttpOnly | true | Prevents XSS access |
|
|
| Secure | true (production) | HTTPS only in production |
|
|
| SameSite | lax | CSRF protection |
|
|
|
|
### Icon Settings Cookie
|
|
|
|
`ApplyIconSettings` middleware reads `icon-style` and `icon-size` cookies set by JavaScript. These are stored in session for Blade component access.
|
|
|
|
**Risk**: Cookie values are user-controlled. Ensure they are properly escaped in views.
|
|
|
|
## Audit Logging
|
|
|
|
### Logged Actions
|
|
|
|
| Action | What's Logged |
|
|
|--------|---------------|
|
|
| Log clear | user_id, email, previous_size_bytes, IP |
|
|
| Database query | user_id, email, query, row_count, execution_time, IP |
|
|
| Blocked query | user_id, email, query (attempted), IP |
|
|
| Route test | user_id, route, method, IP |
|
|
| Server failure | Server ID, failure reason (via activity log) |
|
|
|
|
### Activity Log
|
|
|
|
Server model uses Spatie ActivityLog for tracking changes:
|
|
- Logged fields: name, ip, port, user, status
|
|
- Only dirty attributes logged
|
|
- Empty logs suppressed
|
|
|
|
## Third-Party Security
|
|
|
|
### Telescope
|
|
|
|
- Sensitive headers hidden: `cookie`, `x-csrf-token`, `x-xsrf-token`
|
|
- Sensitive parameters hidden: `_token`
|
|
- Gate restricts to Hades users (production) or all users (local)
|
|
|
|
### Horizon
|
|
|
|
- Gate restricts to Hades users
|
|
- Notifications configured via config (not hardcoded emails)
|
|
|
|
## Security Checklist for New Features
|
|
|
|
When adding new developer tools:
|
|
|
|
- [ ] Enforce Hades authorization in middleware AND component
|
|
- [ ] Add rate limiting for API endpoints
|
|
- [ ] Redact sensitive data in output
|
|
- [ ] Audit destructive operations
|
|
- [ ] Restrict environment (local/testing) for dangerous features
|
|
- [ ] Validate and sanitize all user input
|
|
- [ ] Use prepared statements for database queries
|
|
- [ ] Clean up temporary files/resources
|
|
- [ ] Document security considerations
|
|
|
|
## Incident Response
|
|
|
|
### If Hades credentials are compromised:
|
|
|
|
1. Revoke the user's Hades access
|
|
2. Rotate `HADES_TOKEN` environment variable
|
|
3. Review audit logs for suspicious activity
|
|
4. Check server access logs for SSH activity
|
|
5. Consider rotating SSH keys for connected servers
|
|
|
|
### If SSH key is exposed:
|
|
|
|
1. Delete the server record immediately
|
|
2. Regenerate SSH key on the actual server
|
|
3. Review server logs for unauthorized access
|
|
4. Update the server record with new key
|
|
|
|
## Recommendations for Production
|
|
|
|
1. **Separate Hades token per environment** - Don't use same token across staging/production
|
|
2. **Regular audit log review** - Monitor for unusual access patterns
|
|
3. **Limit Hades users** - Only grant to essential personnel
|
|
4. **Use hardware keys** - For servers, prefer hardware security modules
|
|
5. **Network segmentation** - Restrict admin panel to internal networks
|
|
6. **Two-factor authentication** - Require 2FA for Hades-tier accounts
|
|
7. **Session timeout** - Consider shorter session duration for Hades users
|