Profilfoto: Upload nach Inhalt pruefen, Loeschen nur per POST

- Slim::storeCroppedImage() vertraute dem vom Client gemeldeten Typ und
  uebernahm die Endung aus dem Dateinamen; "shell.php" mit Typ image/png
  landete als .php im public-Disk. Jetzt entscheidet
  getimagesizefromstring() ueber die Bytes, die Endung kommt aus dem
  geprueften Typ.
- Foto loeschen war ein GET-Link und liess sich per fremdem <img src>
  ausloesen (CSRF); jetzt POST-Formular mit Token.
- Ohne Konto (users.account_id) bricht Upload/Loeschen mit 404 ab statt
  mit einem Fatal.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin 2026-09-23 15:42:11 +00:00
parent 22dcc0f972
commit e009b11259
5 changed files with 90 additions and 14 deletions

View file

@ -14,9 +14,15 @@
'size' => 120,
])
<br><br>
<a href="{{ route('user_profile_delete_image') }}" class="btn btn-danger"
onclick="return confirm('{{ __('actions.really_delete_picture') }}');"><i class="fa fa-trash"></i>
{{ __('account.profile_image_delete') }}</a>
{{-- Loeschen per POST: als GET-Link liesse sich das Foto ueber ein
fremdes <img src> loeschen (CSRF). --}}
<form method="POST" action="{{ route('user_profile_delete_image') }}" accept-charset="UTF-8"
class="d-inline"
onsubmit="return confirm('{{ __('actions.really_delete_picture') }}');">
@csrf
<button type="submit" class="btn btn-danger"><i class="fa fa-trash"></i>
{{ __('account.profile_image_delete') }}</button>
</form>
</div>
@else
<form method="POST" action="{{ route('user_profile_upload_image') }}" accept-charset="UTF-8" class="avatar"