URL ontleden

Plak een adres en bekijk het zoals een browser het ziet: schema, host, poort, pad, query en fragment, plus elke parameter op een eigen regel. Het ontleden gebeurt met de `URL`-parser die de browser aan boord heeft — dezelfde die bepaalt waar een klik werkelijk heen gaat — en niet met een reguliere expressie, die juist in de randgevallen anders zou oordelen.

Resultaat

Het antwoord verschijnt hier terwijl je typt.

  • Waar het draait

    Er wordt niets geüpload, want er is geen bestand — het wordt in deze pagina uitgerekend.

  • Geen wachtrij, geen account

    Het antwoordt zo snel als je machine kan, en vraagt nooit wie je bent.

  • Zo vaak als je wilt

    Er wordt niets geteld en niets begrensd — nog eens antwoorden kost ons niets.

Hoe het werkt

  1. Plak het adres. Ontbreekt het schema, dan wordt https aangenomen.
  2. Lees de onderdelen apart, met de parameters uit de query string erbij.
  3. Er is niets geüpload, en er is ook niets bezocht.

Dezelfde parser die je browser gebruikt

Het ontleden komt van de ingebouwde `URL`-interface en niet van een met de hand geschreven reguliere expressie. Dat is het punt waarop de hulpmiddelen in dit genre uiteenlopen: de specificatie van de WHATWG staat vol regels die je niet vermoedt als je het zelf bouwt, en in die regels wonen de interessante fouten.

Een voorbeeld is de normalisatie van de host: het hoofdlettergebruik wordt gelijkgetrokken, een punt aan het eind valt weg en geïnternationaliseerde namen worden naar Punycode omgezet. Een reguliere expressie laat dat allemaal staan en meldt dan een verschil tussen twee adressen die voor elke browser hetzelfde zijn.

De host is waar dit serieus wordt

In `https://[email protected]/` is de host `kwaadaardig.example` en niet `voorbeeld.nl`: alles vóór het apenstaartje zijn inloggegevens. Dat is volgens de norm en het is de basis van een van de oudste phishingtrucs die er zijn, want het oog blijft hangen bij de eerste bekende naam.

Daarom krijgt de host hier een eigen regel. Wie een verdacht adres nakijkt, hoeft niet te tellen maar leest waar het werkelijk heen wijst. En in hetzelfde pakket: een naam als `voorbeeld.nl.kwaadaardig.example` is óók een adres op `kwaadaardig.example`, want wat telt is het laatste paar labels.

Hier wordt niets bezocht

Het adres wordt ontleed, niet geopend. Er is geen verzoek naar de host, geen voorbeeldweergave en geen doorstuurketen die wordt gevolgd, en dat is een besluit en geen ontbrekende functie: wie een verdachte URL onderzoekt, is de laatste die wil dat het hulpmiddel hem opvraagt.

Opvragen zou bovendien iets verraden. Het verzoek zou van een server komen, het IP-adres en het tijdstip zouden in het logboek aan de andere kant belanden, en bij een adres voor eenmalig gebruik — een bevestiging, een wachtwoordherstel — zou het hem onderweg opmaken. Ontleden is de ongevaarlijke bewerking, en het is de enige die hier gebeurt.

Waarom het pad korter uitkomt dan je het schreef

Een `..` in het pad wordt bij het ontleden opgelost: `/docs/a/../b` wordt `/docs/b`. Dat hoort bij de normalisatie en is niet iets dat dit hulpmiddel toevoegt — elke browser doet het voordat hij het verzoek verstuurt, en een server ziet de oorspronkelijke vorm nooit.

Het telt in alles wat paden vergelijkt of er rechten op baseert. Wie een toegangsregel toetst tegen de ruwe tekst in plaats van tegen het genormaliseerde pad, toetst iets anders dan wat er straks wordt opgevraagd — het gat dat al decennia path traversal heet.

Het fragment reist in geen enkel verzoek

Alles achter `#` blijft in de browser. Het komt in geen enkel verzoek voor, bereikt geen server en staat in geen enkel toegangslogboek. Het is een eigenschap van HTTP en geen privacyfunctie, en het snijdt naar twee kanten.

Het is bruikbaar omdat een waarde daar de server niet bereikt — historisch de reden dat OAuth-tokens er reisden. Het is ongemakkelijk omdat het toch in de geschiedenis blijft, in de referrer-keten van sommige scripts en in elke gedeelde link. «Bereikt de server niet» betekent niet «is privé».

De poort die niet verschijnt

Is de poort de gebruikelijke van het schema — 443 bij https, 80 bij http — dan laat de parser hem weg, want hij is overbodig. `https://voorbeeld.nl:443/` en `https://voorbeeld.nl/` zijn hetzelfde adres, en de normalisatie maakt dat zichtbaar.

Dat is de gewone verklaring waarom een vergelijking tussen twee URL-teksten faalt terwijl ze hetzelfde betekenen. Wie adressen vergelijkt, moet ze eerst door een parser halen en de genormaliseerde vorm vergelijken — precies de vorm die hier op de regels verschijnt.

Bijna alles is een schema

Een typefout als `htp://voorbeeld.nl` wordt niet geweigerd: het wordt gelezen als een adres met het schema `htp`. Dat is geen fout van de parser — de specificatie laat elk schema toe, want er zijn er honderden: `mailto:`, `tel:`, `git+ssh:`, `spotify:`, en geen enkele parser kan weten welke in jouw wereld geldig zijn.

In de praktijk: staat er een schema dat je niet verwachtte, dan heb je je typefout gevonden. En het betekent dat een controle in de trant van «laat het zich ontleden» geen controle is dat het adres naar het web wijst; daarvoor moet je het schema tegen een uitdrukkelijke lijst leggen.

Inloggegevens binnen het adres

De vorm `https://gebruiker:wachtwoord@host/` bestaat nog steeds, en duikt op in oude scripts, in verbindingsreeksen naar databases en in voorbeelden in documentatie. Browsers hebben het gebruik ervan beperkt omdat het ideaal was voor phishing, maar bibliotheken en gereedschap op de opdrachtregel nemen het nog gewoon aan.

Hier wordt de gebruikersnaam getoond en het wachtwoord niet: daarvoor in de plaats staat er de mededeling dat er een is. De reden is alledaags en telt evengoed — deze uitkomsten belanden regelmatig in een schermafdruk of in een ticket, en een wachtwoord dat je al hebt hoeft niet nog eens te worden afgedrukt.

Geïnternationaliseerde namen worden herschreven

Een host met een trema of een accent wordt naar Punycode omgezet: `ideeën.example` wordt `xn--ideen-qsa.example`. Dat is de vorm die werkelijk in het DNS bestaat, want het namensysteem kent alleen ASCII; de leesbare schrijfwijze is een weergavehulp van de browser.

Zichtbaar maken wat er daadwerkelijk wordt opgevraagd heeft nut voor de veiligheid. Homografische aanvallen gebruiken tekens uit andere schriften die op Latijnse lijken; in de Punycode-vorm springen die eruit, want in plaats van een vertrouwde naam staat er een letterbrij.

De oorsprong is niet hetzelfde als het domein

De oorsprong is schema, host en poort samen, en dat is de eenheid waarop de browser zijn veiligheidsregels baseert. `https://voorbeeld.nl` en `http://voorbeeld.nl` zijn verschillende oorsprongen, en `https://app.voorbeeld.nl` is dat ook.

Cookies volgen een andere regel, en daar zit veel verwarring. Een cookie kan voor `voorbeeld.nl` en al zijn subdomeinen gelden en trekt zich van de poort niets aan. Twee pagina’s kunnen dus dezelfde cookies delen en toch verschillende oorsprongen zijn — en omgekeerd. Wie een probleem met CORS of met sessies onderzoekt, moet weten welke van de twee regels van toepassing is.

AVG: er wordt niets opgevraagd

Een adres uit een logregel of uit een foutmelding draagt regelmatig persoonsgegevens in zijn parameters: een e-mailadres, een zoekterm, een identifier die aan een account hangt. Omdat het ontleden op de pagina gebeurt, wordt daar niets van aan ons verstrekt.

Er is nog een tweede kant, en die is bij deze pagina eigen: doordat er niets wordt opgevraagd, komt er ook niets terecht in het logboek van de host in het adres. Bij een link die je onderzoekt en niet wilt aanraken, is dat het verschil tussen kijken en je aankondigen.

URL ontleden: veelgestelde vragen

Wordt het adres bezocht?

Nee. Het wordt ontleed, niet geopend: geen verzoek naar de host, geen voorbeeld, geen doorstuurketen. Bij een verdachte of eenmalige URL is dat precies waar het om gaat.

Waarom is de host niet wat ik verwachtte?

Waarschijnlijk staat er een apenstaartje in: in https://[email protected]/ is alles ervoor een inloggegeven en is de host kwaadaardig.example. Dat is volgens de norm en de basis van een oude phishingtruc.

Waarom verdwijnt mijn poort 443?

Omdat dat de standaardpoort van https is en de normalisatie hem weglaat. https://voorbeeld.nl:443/ en https://voorbeeld.nl/ zijn hetzelfde adres — een veelvoorkomende reden dat een tekstvergelijking tussen twee URL’s faalt.

Waarom wordt htp:// niet als fout aangemerkt?

Omdat de specificatie elk schema toelaat — mailto, tel, git+ssh en honderden meer. htp is dus syntactisch een geldig schema. Dat het daar staat, is juist de aanwijzing voor je typefout.

Wordt mijn wachtwoord getoond als de URL er een bevat?

Nee. De gebruikersnaam verschijnt, en van het wachtwoord alleen de mededeling dat er een is. Deze uitkomsten belanden vaak in schermafdrukken en tickets, en daar hoort het niet.

Andere hulpmiddelen