Ga naar hoofdinhoud

HTML van een bezoeker: in je eigen project

Je weet nu waar tekst van een bezoeker HTML kan worden: in een f-string in een HTMLResponse, ook als de tekst uit de URL komt, in een template met |safe of met een andere extensie dan .html, en in JavaScript met innerHTML. Loop je gastenboek, of een eigen project dat je bouwde, langs op die plekken.

tip

Werk in je eigen project, niet in de map veiligheid-xss. Test daarna met je eigen server op 127.0.0.1.

Zoeken en testen​

Zoek in je main.py naar HTMLResponse(f, in je templates naar |safe, en in je JavaScript naar innerHTML. Een {{ }} in een .html-template is al veilig. Wat je vindt, maak je veilig zoals in de lessen hiervoor: escape() in een f-string, |safe weg, en textContent in plaats van innerHTML.

Start daarna je eigen server, en schrijf in je eigen gastenboek een bericht <b>vet</b>.

Controlevraag
In je eigen lijst staat het vette woord met de haakjes erbij. Is je hele project daarmee veilig voor HTML van een bezoeker?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Er gaat iets mis​

NameError: name 'escape' is not defined​

Na het versturen verschijnt er niets onder het formulier, maar je bericht staat wel in de lijst. In het tabblad Netwerk heeft POST /gastenboek een 500, en in de terminal van je server eindigt de foutmelding met:

NameError: name 'escape' is not defined

Oorzaak: je zette escape(…) in de return, maar from html import escape staat niet bovenaan main.py. Het bericht is dan al opgeslagen; pas de return gaat mis. htmx zet een 500 niet in de pagina.

Oplossing: zet from html import escape bij je andere imports.

&lt;b&gt; op je pagina​

In je lijst staat letterlijk &lt;b&gt;vet&lt;/b&gt;, met de codes in plaats van de haakjes.

Oorzaak: je zette escape() om een waarde die je aan een template geeft. Jinja escapet die dan nog een keer, en van de & in &lt; maakt hij &amp;.

Oplossing: geef het template de tekst zoals hij is; het template escapet zelf. escape() hoort alleen in een f-string.

Meer uitleg: Templates escapen vanzelf

Opdrachten​

Opdracht 1: Make - In je eigen project​

Zoek in je eigen project elke plek waar tekst van een bezoeker in HTML komt, en zorg dat die overal tekst blijft.

Tip

Na de basis en de uitbreidingen staat er meestal maar één f-string met HTML in je main.py: de return van je POST /gastenboek als je het htmx-formulier gebruikt. Begin daar.

Antwoord

Loop deze lijst af:

  • Een template dat op .html eindigt, escapet alles tussen {{ }}. Daar hoef je niets te doen.
  • Staat er |safe achter tekst van een bezoeker, haal het weg.
  • Staat er een parameter van je endpoint in een HTMLResponse(f"…"), zet er escape() omheen, of gebruik een template. Dat geldt ook voor een query-parameter zoals ?term=, die niets opslaat.
  • Zet je JavaScript tekst uit een veld of uit de URL in de pagina, gebruik dan textContent en niet innerHTML. De tekenteller uit JavaScript erbij doet dat al goed.
  • Heb je het recept Een formulier versturen uit het htmx-overzicht overgenomen, kijk dan of daar escape(naam) staat; dat is later aan het recept toegevoegd. Na Sessies komt de naam uit de sessie: dan is het escape(mijn["naam"]).
  • Ook een naam bij /registreer komt van een bezoeker. Wie zich registreert als <b>Sara</b>, staat zo in je lijst en op je detailpagina; in een .html-template blijft dat tekst.

Gebruik je in je gastenboek het htmx-formulier, dan is dat de return van je POST /gastenboek. Zet from html import escape bij je imports, en laat de return zo eindigen:

return HTMLResponse(f"Bedankt, {escape(mijn['naam'])}. Je bericht staat in het gastenboek.")

Heb je de sessies niet gebouwd, dan staat er escape(naam).

Stuurt je POST /gastenboek nog door met een RedirectResponse, dan zet hij geen tekst in HTML, en hoeft er niets bij. Je lijst, je detailpagina en berichten.html zijn templates op .html; ook daar komt niets bij.

Test het door in je eigen formulier <b>vet</b> in te vullen: je moet de haakjes zien, en niets vetgedrukt.

Door naar les 10: in de praktijk.