You've already forked Atomcms-edit
Security: admin radio routes now require auth+admin.security, CORS default no longer wildcard, README security section
This commit is contained in:
@@ -274,6 +274,53 @@ yarn format # Format code
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
AtomCMS is built with security as a priority. Below is what's in place and what you need to configure.
|
||||
|
||||
### ✅ Already locked down
|
||||
|
||||
| Measure | Details |
|
||||
|---------|---------|
|
||||
| **Mass assignment protection** | User model restricted to 21 fillable fields (sensitive fields like `rank`, `credits`, `online` require explicit `forceFill`) |
|
||||
| **API authentication** | Sanctum tokens, Bearer-only (no query-string API keys accepted) |
|
||||
| **PayPal credentials** | Loaded from `env()`, never hardcoded |
|
||||
| **CORS** | Must be explicitly set via `CORS_ALLOWED_ORIGINS` env (no wildcard default) |
|
||||
| **Debug mode** | `APP_DEBUG=false` by default |
|
||||
| **PHP debugging** | No `dd()`, `dump()`, or `var_dump()` in production code |
|
||||
| **Password flashing** | Exception handler excludes passwords from session flash |
|
||||
| **File uploads** | MIME validation (Laravel `image` rule + `finfo` on logos) |
|
||||
| **2FA** | Two-factor authentication available |
|
||||
| **SQL injection** | All queries use parameterized binding or Eloquent ORM |
|
||||
| **Command injection** | All `exec()`/`shell_exec()` calls use `escapeshellarg()` or hardcoded values |
|
||||
| **CSRF** | Sanctum CSRF protection on all stateful routes |
|
||||
| **Insecure deserialization** | No `unserialize()` calls exist |
|
||||
|
||||
### ⚠️ You must configure
|
||||
|
||||
| Item | What to do |
|
||||
|------|------------|
|
||||
| **`.env` file** | Restrict file permissions (`chmod 600 .env`), ensure Nginx blocks access (already in the provided config) |
|
||||
| **`CORS_ALLOWED_ORIGINS`** | Set to your exact frontend domain(s) in `.env` (included in the example files) |
|
||||
| **Database password** | Use a strong, unique password (not `your_db_password`) |
|
||||
| **APP_KEY** | Run `php artisan key:generate` after cloning |
|
||||
| **Session domain** | Set `SESSION_DOMAIN` to your hotel domain in `.env` |
|
||||
| **SSL** | Required for production — use the Certbot instructions above |
|
||||
| **Admin accounts** | Only grant high-rank access to trusted users |
|
||||
| **Log retention** | Check `LOG_MAX_FILES` in `.env` (default 14 days) |
|
||||
|
||||
### 🔒 Sudoers safety
|
||||
|
||||
The `sudoers.d/www-data` configuration grants passwordless `systemctl` and `chown` to `www-data`. This is **safe by design**:
|
||||
|
||||
- Each command is pinned to a specific binary path (`/usr/bin/systemctl`, `/usr/bin/chown`)
|
||||
- `chown` is restricted to `/var/www/*`
|
||||
- No shell (`/bin/sh`, `/bin/bash`) is granted
|
||||
- No arbitrary binaries can be executed
|
||||
- In a worst-case web compromise, the attacker still cannot read `/etc/shadow`, install packages, or run arbitrary commands
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
- **Discord:** [Join our server](https://discord.gg/pP6HyZedAj)
|
||||
|
||||
+2
-2
@@ -21,11 +21,11 @@ return [
|
||||
|
||||
'allowed_methods' => array_filter(array_map(trim(...), explode(',', (string) env('CORS_ALLOWED_METHODS', 'GET,POST,PUT,PATCH,DELETE,OPTIONS'))), fn ($v) => $v !== ''),
|
||||
|
||||
'allowed_origins' => array_filter(array_map(trim(...), explode(',', (string) env('CORS_ALLOWED_ORIGINS', '*'))), fn ($v) => $v !== ''),
|
||||
'allowed_origins' => array_filter(array_map(trim(...), explode(',', (string) env('CORS_ALLOWED_ORIGINS', ''))), fn ($v) => $v !== ''),
|
||||
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
'allowed_headers' => array_filter(array_map(trim(...), explode(',', (string) env('CORS_ALLOWED_HEADERS', '*'))), fn ($v) => $v !== ''),
|
||||
'allowed_headers' => array_filter(array_map(trim(...), explode(',', (string) env('CORS_ALLOWED_HEADERS', 'Content-Type,Authorization,X-Requested-With'))), fn ($v) => $v !== ''),
|
||||
|
||||
'exposed_headers' => [],
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ use App\Http\Controllers\Api\FurniEditorController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
// Admin radio setup
|
||||
Route::prefix('admin')->group(function () {
|
||||
Route::prefix('admin')->middleware(['auth', 'admin.security'])->group(function () {
|
||||
Route::get('/radio/setup', [RadioSetupController::class, 'index'])->name('admin.radio.setup');
|
||||
Route::post('/radio/setup', [RadioSetupController::class, 'setup'])->name('admin.radio.setup.post');
|
||||
Route::post('/radio/setup/do', [RadioSetupController::class, 'doSetup'])->name('admin.radio.setup.do');
|
||||
|
||||
Reference in New Issue
Block a user