escapen van een query string
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:
of is het beter om dit te escapen en dus het volgende als output te genereren:
Daarnaast:
Voor onveilige data moet ik natuurlijk htmlentities() gebruiken:
vs
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 :-)
In een De vraag is dus: Kan ik in de output van mijn script het volgende plaatsen zonder (html) escaping:
of is het beter om dit te escapen en dus het volgende als output te genereren:
Daarnaast:
Voor onveilige data moet ik natuurlijk htmlentities() gebruiken:
vs
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
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.
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
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&aantal;foo=12".
Maar gewoon alles door de escape-molen halen kan geen kwaad.
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 ;-)
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
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).
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
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()).
@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.
Twig escaped zijn routes ook. Ik had toch nog maar wat testjes gedaan maar gelukkig geen gebreken gevonden.
Twig: Nee. Een doe-het-zelf ding "sinds 2009". Het doet dus precies wat ik wil (maar grofweg vergelijkbaar met Twig).
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)
1
2
3
4
5
6
7
8
9
10
11
12
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>
<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)
1
2
3
4
5
2
3
4
5
{% extends 'layout.html.twig' %}
{% block content %}
<h1>Hi folks</h1>
{% endblock %}
{% block content %}
<h1>Hi folks</h1>
{% endblock %}
Gewijzigd op 28/10/2017 10:27:01 door Frank Nietbelangrijk
Maar de echte snelste template-parser blijft PHP himself. ;-)
- 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 ?
@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 ?
Ter illustratie:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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>
<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))