escapen van een query string

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Frank Nietbelangrijk

Frank Nietbelangrijk

26/10/2017 16:16:21
Quote Anchor link
In een ander topic is de vraag naar voren gekomen of een query string ook escaped dient te worden. Om dat topic niet helemaal te kapen en omdat deze vraag toch interessant is wil ik hier in dit topic graag verder discussiëren.

De vraag is dus: Kan ik in de output van mijn script het volgende plaatsen zonder (html) escaping:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<a href="index.php?lang=nl&aantal=12">homepage</a>


of is het beter om dit te escapen en dus het volgende als output te genereren:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<a href="index.php?lang=nl&amp;aantal=12">homepage</a>


Daarnaast:

Voor onveilige data moet ik natuurlijk htmlentities() gebruiken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<?php echo $language; ?>
vs
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<?php echo htmlentities($language;)  ?>


Maar als een variabele veilig genoeg is (altijd een nummer of een tekst uit een whitelist) dan lijkt mij dat weer wat overkill.

Reacties zijn welkom :-)
Gewijzigd op 26/10/2017 16:18:11 door Frank Nietbelangrijk
 
PHP hulp

PHP hulp

28/03/2024 11:29:21
 
Rob Doemaarwat

Rob Doemaarwat

26/10/2017 19:19:48
Quote Anchor link
https://validator.w3.org/#validate_by_input

cannot generate system identifier for general entity "aantal"
<a href="index.php?lang=nl&aantal=12">homepage</a>

Kortom: beter om te escapen (maar ik denk dat je met heel wat weg komt voordat een browser d'r echt over struikelt)

Edit: O, ik zie dat ik wat gemist heb in de originele thread; daar wordt hetzelfde al uitgekauwd. Ook hier weer handig om d'r gewoon een functie voor te maken, en nooit meer naar om te kijken.
Gewijzigd op 26/10/2017 19:26:21 door Rob Doemaarwat
 
Frank Nietbelangrijk

Frank Nietbelangrijk

26/10/2017 20:06:20
Quote Anchor link
Als ik dit in de validator plak dan krijg ik geen foutmeldingen.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Mijn titel</title>
    </head>
    <body>
        <a href="index.php?lang=nl&aantal=12">homepage</a>
    </body>
</html>
 
Rob Doemaarwat

Rob Doemaarwat

26/10/2017 21:01:00
Quote Anchor link
Hm, interessant geval. Bij mij stond HTML4.01 standaard aan, en daar kreeg ik die foutmelding.

Blijkt dat het in HTML5 *mag* zolang er maar geen verwarring kan ontstaan: https://www.w3.org/TR/html5/syntax.html#syntax-ambiguous-ampersand . Zolang je key dus geen punt-komma bevat kan het eigenlijk niet fout gaan.

"?lang=nl&aantal;foo=12" (key = "aantal;foo") geeft dus wel een error, en zal dus geschreven moeten worden als "?lang=nl&amp;aantal;foo=12".

Maar gewoon alles door de escape-molen halen kan geen kwaad.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

26/10/2017 21:08:38
Quote Anchor link
Oke dank je Rob.

Meestal verzin je als programmeur zelf de keys en ik zal daar niet snel een ; of iets dergelijks bijhalen maar mocht er ooit met een variabele key gewerkt worden wordt het wel even opletten ;-)
 
Thomas van den Heuvel

Thomas van den Heuvel

27/10/2017 17:35:10
Quote Anchor link
Frank Nietbelangrijk op 26/10/2017 16:16:21:
De vraag is dus: Kan ik in de output van mijn script het volgende plaatsen zonder (html) escaping:

Ja, maar dat is niet aan te raden. Vanwege mogelijke ambiguïteit.

Frank Nietbelangrijk op 26/10/2017 16:16:21:
of is het beter om dit te escapen en dus het volgende als output te genereren:

Ja, dat verdient de voorkeur. Vanwege mogelijke ambiguïteit.

Frank Nietbelangrijk op 26/10/2017 16:16:21:
Voor onveilige data moet ik natuurlijk htmlentities() gebruiken:

Actually, htmlspecialchars() is beter omdat je anders in de knoei komt in sommige situaties (XML en afgeleiden, de bron hiervoor moet ik je schuldig blijven, maar dit was min of meer de uitkomst van mijn htmlentities() vs htmlspecialchars() onderzoekje).

Frank Nietbelangrijk op 26/10/2017 16:16:21:
Maar als een variabele veilig genoeg is (altijd een nummer of een tekst uit een whitelist) dan lijkt mij dat weer wat overkill.

Ik ga hier herhalen wat ik in de andere thread al zei: het is gewoon makkelijker om regels consequent toe te passen. Als je namelijk een keer escaping weglaat omdat dit niet nodig is dan moet iemand (anders die jouw code bekijkt) nadenken en dingen controleren om na te gaan dat het echt de bedoeling was dat iets niet geescaped diende te worden. Al deze overhead heb je niet als je gewoon overal escaped, of dit nu nodig is of niet. Keep It Simple.

Overkill wellicht, maar dit traint je ook om beducht te zijn op user input / externe data in je applicatie, die altijd aandacht verdient.

En als je dan niet escaped, vermeld dan een expliciete reden waarom dit niet hoeft. Dan stuur je een collega ook niet met een kluitje het riet in. En als het al geescaped was, heb je hier geen omkijken naar.

Rob Doemaarwat op 26/10/2017 19:19:48:
Edit: O, ik zie dat ik wat gemist heb in de originele thread; daar wordt hetzelfde al uitgekauwd.

Voorgekauwd? Uitgekauwd? Meh.

Anyhoo, in een hele simpele optiek moet je het denk ik als volgt zien. Je produceert meestal een HTML document. Daarin zitten dynamische delen afkomstig van een externe bron. Deze delen dienen meestal niet als HTML geïnterpreteerd te worden. Hiervoor zet je escaping-functionaliteit in om dit te garanderen.

Daarnaast heb je in wat verder ontwikkelde applicaties een interne navigatie. Om je applicatie vrij verplaatsbaar te houden zouden alle interne links dynamisch gegenereerd moeten worden. Op basis van servervariabelen, configuratie-instellingen et cetera. Idealiter introduceer je hiervoor een soort van linkfunctie.

Het is echter niet de taak van deze functie om aannames te doen in welke context deze gebruikt gaat worden. Deze linkfunctie zou namelijk ook in JavaScript ingezet kunnen worden en dan gelden er andere regels. Voor het escapen is een functie natuurlijk ook handig. Dit omdat je dan centraal -ook weer op grond van een serverinstelling of configuratie-variabele- bijvoorbeeld een character encoding kunt regelen maar misschien nog belangrijker (in beide gevallen): je voorkomt hardcoding.

Het niet uitschrijven van interne links maar het variabel houden hiervan middels een functie zorgt ervoor dat je applicatie niet verandert in een baksteen. Het escapen van output via een functie stelt je in staat om dit mogelijk aan extra regels te onderwerpen of dingen centraal aan te passen. Maar elk van deze functies heeft een eigen, en enkele verantwoordelijkheid: de een is bedoeld voor het (in welke context dan ook) genereren van links, het ander is (specifiek) bedoeld voor het escapen van (het ontdoen van enige speciale betekenis van) DATA in HTML.

En dan zijn er nog aparte regels voor de key-value paren van querystringparameters (voor de duidelijkheid: we hebben het hier over hyperlinks in <a href="..."> tags). Deze dienen (eigenlijk) beide ge-urlencode() te worden zodat, wederom, deze data wordt ontdaan van enige speciale betekenis binnen de URL. Vaak kies je de keys zelf zodat dit om te beginnen niet voor problemen zorgt met interpretatie (toch?) maar better safe than sorry wellicht. Dit alles kun je opnemen in de eerdergenoemde linkfunctie waaraan je een $args (array van key-value paren) argument ofzo toevoegt.

Vervolgens is deze gebakken link... weer DATA die van buitenaf afkomstig is en niet als HTML geïnterpreteerd dient te worden, dus hier gooi je, als je deze in een <a href="..."> tag gebruikt weer de escaping-functie over, dit verschilt verder niet van andere externe data in je applicatie en deze behandel je dus ook gewoon weer precies hetzelfde.

Ik heb nu een heel relaas geschreven om te onderbouwen waarom ik doe wat ik doe. Het is simpel, het is veilig, het is consistent. Deze aanpak zou ik niet zondermeer opvolgen, maar ook niet op voorhand afschrijven omdat je niet dezelfde weg hebt afgelegd als ik. Misschien is de enige manier om tot deze conclusies te komen zelf deze weg te bewandelen. Ook ben ik zeer benieuwd of er ook echt andere aanpakken zijn die hetzelfde bereiken, maar dan ben ik vooral geïnteresseerd in het waarom, en niet zozeer in de vorm.

Dit klinkt misschien arrogant, maar zo is het niet bedoeld. We bevinden ons allen in hetzelfde landschap, maar afhankelijk van waar je staat zie je mogelijk andere dingen. Of zie je dezelfde dingen vanuit een andere hoek.
Gewijzigd op 27/10/2017 17:40:50 door Thomas van den Heuvel
 
Rob Doemaarwat

Rob Doemaarwat

27/10/2017 20:05:34
Quote Anchor link
Ik gebruik een templating systeem waarbij elke input (een "tag" in het template) automatisch ge-escaped wordt (je moet bewust aangeven als iets *niet* ge-escaped moet worden). Over die stap hoef ik dus eigenlijk niet na te denken.

Ter info/hetzelfde: Interne links (die ik dus via een tag invoeg) komen uit de (reverse) router, en die werkt standaard met urlencode() en http_build_query() (maar dus nog wel een bewuste actie; ik zou 'm ook gewoon uit kunnen schrijven).
 
Thomas van den Heuvel

Thomas van den Heuvel

27/10/2017 20:31:41
Quote Anchor link
Rob Doemaarwat op 27/10/2017 20:05:34:
automatisch ge-escaped

Uhh, maar dat is dan escape-on-input? Vaak is het handiger om escaping zo lang mogelijk uit te stellen, tot net voor het weergeven, en dit dan expliciet doen, zodat je dit dus ook kunt zien dat het gebeurt (anders heb je weer het eerdergenoemde probleem dat je dit dus niet (zeker) weet. En wat als je het daar vergeet te doen?). Tenzij dit templating systeem enkel voor HTML (maar in één context) wordt gebruikt? Maar dan nog. escape-on-input lijkt mij alleen zinvol/handig in enkele uitzonderlijke gevallen. Ik zou nooit op voorhand escapen (voordat het de database in gaat bijvooorbeeld). En altijd expliciet. Of ik moet je verkeerd begrijpen.
Gewijzigd op 27/10/2017 20:32:35 door Thomas van den Heuvel
 
Rob Doemaarwat

Rob Doemaarwat

27/10/2017 20:51:07
Quote Anchor link
Met "input" bedoelde ik de input naar het templating systeem toe. Ik geef de ruwe, originele waarden dus mee aan de template functie, en het resultaat daarvan is een stuk HTML waarin de data ge-escaped is.

En dit is dus inderdaad alleen voor HTML. Bij een JSON response wordt er niks ge-escaped (json_encode() doet dat wel ,amar aan de andere komt komt het weer op dezelfde manier uit). Dan moet je er dus zelf aan denken als je het bijvoorbeeld in een javascript context gaat gebruiken (bijvoorbeeld jQuery's .text() vs .html()).
 
Frank Nietbelangrijk

Frank Nietbelangrijk

27/10/2017 20:57:52
Quote Anchor link
@Thomas, Dank voor je uitgebreide antwoord.
@Rob, Gebruik je net als ik Twig?

Wat Rob zegt dat doe ik ook. Ik gebruik (voor het echte werk) eigenlijk altijd een template parser. Deze zal alle variabelen escapen tenzij ik dat expliciet anders aangeef. Ik durf echter niet te zeggen of dat ook geldt voor de interne links (routes) die opgebouwd worden. Ondanks dat de template parser voor mij escaped vind ik het belangrijk om mijn kennis hierin te verruimen of anders up to date te houden.

Een lekke HTML pagina kan vervelende gevolgen hebben voor de gebruiker. Ik moet eerlijk bekennen dat ik daar meestal weinig aandacht aan besteedt. Maar data dat van buitenaf mijn applicatie in komt daar ben ik wel altijd zo secuur mogelijk in geweest.

Edit:

Twig escaped zijn routes ook. Ik had toch nog maar wat testjes gedaan maar gelukkig geen gebreken gevonden.
 
Rob Doemaarwat

Rob Doemaarwat

27/10/2017 22:13:06
Quote Anchor link
Twig: Nee. Een doe-het-zelf ding "sinds 2009". Het doet dus precies wat ik wil (maar grofweg vergelijkbaar met Twig).
 
Frank Nietbelangrijk

Frank Nietbelangrijk

28/10/2017 09:57:45
Quote Anchor link
Hmm ik weet natuurlijk niet hoe goed jouw doehetzelf ding is maar ben dan toch geneigd te vragen om twig eens te proberen. Twig maakt cache bestanden aan waardoor het razendsnel wordt en wat ik persoonlijk ook erg fijn vindt aan Twig is dat je zelf twig functies kunt maken. Zo kun je bijvoorbeeld een bedrag() functie maken die een bedrag altijd netjes toont zoals je dat met number_format doet maar dan zonder al die parameters telkens.
Daarnaast zijn het gebruik van layouts en blokken in Twig echt geweldig. Maak 1x een complete html template met header, een lege content en footer en op alle andere pagina's include je die template en vervang je gewoon het blok content voor een nieuw blok met inhoud.

layout:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE>
<html>
<head>
        <meta charset="UTF-8">
        <title>{% block title %}Welkom{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
</head>
<body>
        {% block content %}{% endblock %}
        {% block javascript %}{% endblock %}
</body>
</html>


homepage:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
{% extends 'layout.html.twig' %}

{% block content %}
    <h1>Hi folks</h1>
{% endblock %}
Gewijzigd op 28/10/2017 10:27:01 door Frank Nietbelangrijk
 
- Ariën  -
Beheerder

- Ariën -

28/10/2017 10:04:52
Quote Anchor link
Naast Twig bestaat er overigens ook nog Smarty die dezelfde capaciteiten heeft. Het processed de templates in PHP-bestanden voor snellere uitvoer via caching, maar kan ook bepaalde data op de manier zoals de developer wilt gaan cachen.

Maar de echte snelste template-parser blijft PHP himself. ;-)
 
Frank Nietbelangrijk

Frank Nietbelangrijk

28/10/2017 10:14:51
Quote Anchor link
Zoals Ariën al aangeeft zijn er een aantal template engines. Een Laravel gebruiker zal waarschijnlijk weer Blade roepen als template engine. Ik heb zelf alleen ervaring met Twig en ben daar enthousiast over. Hetzelfde geldt voor Ariën met Smarty denk ik.

- Ariën - op 28/10/2017 10:04:52:
Maar de echte snelste template-parser blijft PHP himself. ;-)


Maar dat gaat dan wel weer ten koste van automatic escaping waardoor we uiteindelijk op template engines uit kwamen ;-)

Ik ben van mening dat je een template engine moet gebruiken. Redenen zijn:
- automatic escaping
- separation of concerns
- makkelijk te hanteren voor front-developers
- makkelijker werken met layouts
- toegevoegde template functies


Toevoeging op 28/10/2017 10:20:00:

Edit:

@Ariën: Klopt het dat Smarty niet automatisch escaped? Dat zou toch een behoorlijk nadeel zijn ...

Ik las dat je {$var | escape} moet schrijven in Smarty alvoor je output escaped wordt ?
 
Rob Doemaarwat

Rob Doemaarwat

28/10/2017 11:58:02
Quote Anchor link
De voornaamste reden dat ik aan m'n doe-het-zelf ding vasthoud is ivm het switchen tussen talen (vertalingen). Meestal heb ik een template (de HTML kapstok) die voor alle talen gelijk is. De invulling (de tekst) is taalspecifiek (en soms ook nog weer klant/gebruiker specifiek = CMS, uit database). Binnen zo'n taal moet je echter ook weer naar een stukje template kunnen verwijzen, of naar andere talen (soms is een obscuur stukje content bijvoorbeeld (nog) niet beschikbaar in de gekozen taal, en dan verwijs ik van daaruit weer naar de default taal).

Ter illustratie:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//template (taal neutraal)
<div>##header##</div>
[@content] //hier wordt de taalspecifieke content ingevoegd
</div>##footer##</div>

//content (in taal gebruiker)
Hallo [naam],
[@meerContent.en] //verwijs naar meerContent in het Engels
[@banner.__] //voeg banner template in
Het is vandaag [datum|date()], enz.

//banner (taal neutraal)
<div id='banner'>
[@bannerContent] //banner tekst in taal gebruiker, enz
</div>

(de [@content] verwijzing is nu fixed, maar uiteraard kun je die ook flexibel maken (template extenden ala Twig))
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.