Skip to content

Fix: no-auth publicDownload, path traversal и приватизация лог-каналов - #1

Merged
jazz-max merged 1 commit into
mainfrom
fix/security-hardening
Jul 6, 2026
Merged

jazz-max merged 1 commit into
mainfrom
fix/security-hardening

Conversation

@jazz-max

@jazz-max jazz-max commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Три независимых улучшения безопасности, не меняющих поведение UI.

1. Удалён публичный no-auth роут publicDownload

GET /public/files/{userId}/{servlet}/{file} отдавал файлы пользователей без авторизации (изоляция только по userId в URL — угадывается перебором). Во фронтенде не используется (grep files.public пуст) → роут и метод удалены.

2. Path traversal в download()

Роут servlet/{name}/download/{file} ловит {file} через where('file', '.*'), а путь строился конкатенацией без санитайза. Добавлен safePath() с realpath-containment: путь принимается только если не выходит за пределы out/ сервлета (в т.ч. защита от ../ и симлинков). Легитимные файлы во вложенных папках out/ продолжают работать.

3. Приватизация лог-каналов

Каналы servlet.{userId}.{name} были публичными (routes/channels.php пуст) — любой аутентифицированный пользователь, зная userId + ключ сервлета, мог подписаться на чужой лог-стрим.

  • события ServletStarted/Log/Finished → PrivateChannel;
  • routes/channels.php: авторизация по владельцу ((int) $user->id === $userId);
  • фронт: Echo.channel() → Echo.private() (Show.vue, LogViewer.vue);
  • добавлен <meta name="csrf-token"> в app.blade.php — laravel-echo использует его для авторизации приватного канала (POST /broadcasting/auth).

Тесты

tests/Feature/SecurityHardeningTest.php: удаление публичного роута, отдача своего файла, блокировка traversal, PrivateChannel + корректное имя канала.

⚠️ Замечания для мержа

  • Тесты написаны, но не прогонялись локально (хост-PHP 8.3, проект требует 8.4) — прогнать composer test в 8.4-окружении / положиться на CI.
  • Приватные каналы стоит проверить вживую (Reverb + логин): подписка на свой канал работает, на чужой — 403.

🤖 Generated with Claude Code

… лог-каналы

- удалить публичный роут /public/files/* (FileController::publicDownload):
  отдавал файлы пользователей без авторизации; во фронте не используется.
- download(): защита от path traversal (safePath с realpath-containment),
  т.к. роут ловит {file} через where('.*').
- лог-события (ServletStarted/Log/Finished) → PrivateChannel; в routes/channels.php
  авторизация servlet.{userId}.{name} по владельцу — раньше каналы были
  публичными и изолировались лишь userId в имени.
- фронт: Echo.channel() → Echo.private(); добавлен <meta csrf-token> для
  авторизации приватных каналов (POST /broadcasting/auth).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jazz-max
jazz-max merged commit 7a68d84 into main Jul 6, 2026
1 check passed
@jazz-max
jazz-max deleted the fix/security-hardening branch July 6, 2026 19:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant