Blade: Variable definieren und HTML ohne XSS-Lücke ausgeben

Blade: Variable definieren und HTML ohne XSS-Lücke ausgeben
Schnelle Antwort

In einer Blade-View deklarierst du eine Variable mit @php $nom = '…'; @endphp oder übergibst sie aus dem Controller mit view('vue', compact('nom')). Zur Ausgabe escaped {{ $nom }} das HTML, {!! $nom !!} fügt es unverändert ein. Nimm die zweite Form nur bei vertrauenswürdigem Inhalt: Genau dort entstehen XSS-Lücken.

Zwei Bedürfnisse tauchen in einer Blade-View immer wieder auf: dort eine Variable zu deklarieren und zu entscheiden, ob ihr Inhalt escaped oder unverändert ausgegeben wird. Das Zweite ist keine Komfortfrage, sondern genau die Stelle, an der eine XSS-Lücke entsteht.

Erschienen im Themenpfad Webentwicklung. Dieser Leitfaden deckt beides ab: eine Variable in die View bringen, eine direkt vor Ort deklarieren und bewusst zwischen {{ }} und {!! !!} wählen. Die Beispiele liefen auf Laravel 13.30.1 mit PHP 8.4.25.

Eine Variable aus dem Controller übergeben

Das ist der normale Weg und der, den du bevorzugen solltest: Die View zeigt an, der Controller entscheidet. Das zweite Argument von view() ist ein assoziatives Array, dessen Schlüssel jeweils zu einer Variablen werden.

app/Http/Controllers/DashboardController.php
return view('dashboard', ['name' => 'Gekko']);
resources/views/dashboard.blade.php
<p>Bienvenue {{ $name }} !</p>

Wie du ein Datum aus einem Model ausgibst, steht unter Datumsverarbeitung mit Carbon.

Liegen mehrere Werte bereits in PHP-Variablen, erspart dir compact() das Wiederholen der Namen:

php
$name    = 'Gekko';
$reseau  = 'gekkode';

return view('dashboard', compact('name', 'reseau'));

Mit with() hängst du unterwegs noch eine an, praktisch, wenn sich der Wert erst im letzten Moment ergibt:

php
return view('dashboard', compact('name'))->with('extra', 'valeur ajoutée');

Kann eine Variable fehlen, gib ihr in der View einen Fallback-Wert, statt eine Bedingung zu ergänzen:

php
{{ $inconnu ?? 'valeur par défaut' }}

Eine Variable direkt in der View deklarieren

Dient der Wert nur der Anzeige, deklarierst du ihn mit der Direktive @php an Ort und Stelle:

resources/views/dashboard.blade.php
@php
    $nom = 'Gekko';
    $classe = $task->active ? 'is-active' : 'is-done';
@endphp

<p class="{{ $classe }}">Bonjour {{ $nom }}</p>

Die klassischen PHP-Tags funktionieren ebenfalls, aber @php bleibt lesbarer und passt zum Rest des Templates.

Zwei Direktiven decken benachbarte Fälle ab, ganz ohne Variable. @class baut ein Klassenattribut aus Bedingungen:

php
<div @class(['actif' => $task->active, 'masque' => $task->hidden])></div>

<!-- rendu quand active vaut true et hidden false -->
<div class="actif"></div>

Und @once stellt sicher, dass ein Block nur einmal gerendert wird, selbst wenn die View mehrfach in die Seite eingebunden ist:

php
@once
    <script src="/js/carte.js" defer></script>
@endonce
Wo das Vernünftige aufhört

@php passt für einen Anzeigewert. Sobald es um eine Datenbankabfrage, eine fachliche Berechnung oder eine Transformationsschleife geht, gehört der Code in den Controller, in eine Blade-Komponente oder in einen Accessor des Models. Eine View, die die Datenbank abfragt, erzeugt N+1-Abfragen, die vom Controller aus unsichtbar bleiben.

HTML ausgeben: {{ }} gegen {!! !!}

Blade kompiliert {{ $variable }} zu einem Aufruf der Funktion e(), die Sonderzeichen escaped. Zu sehen ist das in der kompilierten View unter storage/framework/views:

php
<?php echo e($nom); ?>

Die Folge: Enthält die Variable Tags, erscheinen sie ausgeschrieben, statt interpretiert zu werden.

php
@php $html = '<strong>gras</strong>'; @endphp

{{ $html }}     {{-- affiche : &lt;strong&gt;gras&lt;/strong&gt; --}}
{!! $html !!}   {{-- affiche : gras, en gras --}}

Die Syntax {!! !!} fügt den Wert ohne jede Umwandlung ein. Genau das brauchst du, um einen in HTML verfassten Artikeltext auszugeben, und genau das ist auch die Eintrittstür für eine Script-Injection, wenn der Wert von einem Nutzer stammt.

Die Regel, die du nicht umgehst

Setz {!! !!} nur auf HTML ein, dessen Herkunft du kennst oder das vorher bereinigt wurde. Beim Wert <script>alert(1)</script> gibt {{ }} den Text aus, während {!! !!} das Script im Browser des Besuchers ausführt. Beide Verhalten wurden überprüft.

Bei Inhalten aus einem Formular, das du zuvor gegen automatisierte Einsendungen abgesichert hast, bereinigst du vor der Ausgabe. Eine Bibliothek wie HTML Purifier wendet eine Whitelist erlaubter Tags an, andernfalls speicherst du Markdown und wandelst es beim Rendern um, womit du die erzeugten Tags unter Kontrolle behältst.

Die nützlichen Sonderfälle

Um Daten an JavaScript zu übergeben, erzeugt @json ein gültiges, escaptes Literal:

php
<script>
    const config = @json(['id' => $task->id, 'titre' => $task->title]);
</script>

Um geschweifte Klammern auszugeben, ohne dass Blade sie interpretiert, etwa in einem Template für ein JavaScript-Framework, entschärft @verbatim den gesamten Block:

php
@verbatim
    <div id="app">{{ message }}</div>
@endverbatim

Bei einem einzelnen Ausdruck genügt ein vorangestelltes At-Zeichen: @{{ message }}.

Ruf e() nicht in doppelten geschweiften Klammern auf

{{ e($valeur) }} escaped doppelt: <b> wird zu &amp;lt;b&amp;gt; und erscheint wörtlich auf dem Bildschirm. {{ }} erledigt das bereits. Die Funktion e() ist nur außerhalb von Blade sinnvoll, oder innerhalb eines {!! !!} für einen genau abgegrenzten Abschnitt.

Häufige Fehler

{!! !!} auf einem Wert vom Nutzer Der String <script>alert(1)</script> wird im Browser des Besuchers tatsächlich ausgeführt. Bereinige das HTML vorher oder speichere Markdown.
{{ e($valeur) }} escaped doppelt Die doppelten geschweiften Klammern rufen e() bereits auf. Das Ergebnis zeigt die Entities auf dem Bildschirm statt des Texts.
Eine Datenbankabfrage in @php Die View setzt Abfragen ab, die der Controller nicht sieht, und erzeugt so unsichtbare N+1. Verschieb die Logik in den Controller oder in eine Komponente.
Den Fallback bei einer optionalen Variablen vergessen {{ $var ?? 'défaut' }} verhindert einen Fehler, wenn der Controller sie nicht in jedem Fall übergibt.

BladeLaravelPHP

Damien Flandrin Webentwickler seit 2010, Gründer von Gekkode und Email Impact. Jeder Artikel wird vor der Veröffentlichung an einem echten Projekt getestet. Kontakt
Newsletter

Neue Tests, Tutorials und Projekte, per E-Mail.

Reproduzierbare Tests, versionierter Code, datierte Ergebnisse. Niemals Spam.