Naar de inhoud

Blog ·

Een badge die op elke pagina een cookie zette

Eén afbeelding in de voettekst kostte tweeëntwintig Lighthouse-punten op de hele site. De reparatie was niet hem weghalen, maar wat een proxy moet weigeren.

Door Provibr

De best practices-score van onze marketingsite stond op elke pagina op 78. Niet op een pagina, op elke pagina: de homepage, de prijspagina, de documentatie, alles, uniform. Uniforme scores zijn een goed teken, want ze betekenen dat de oorzaak in iets zit dat elke pagina deelt.

Het was één afbeeldingstag in de voettekst. Een badge van een lanceringsvermelding, rechtstreeks geladen van het platform dat hem uitgeeft, want zo hoort zo'n badge ingebed te worden en het getal erop hoort live te zijn.

Wat een afbeeldingstag kan doen

De badge wordt geleverd door een API-host die achter Cloudflare zit, en Cloudflare beantwoordt verzoeken met zijn botmanagementcookie: __cf_bm, SameSite=None, Secure, met bereik op het domein van de uitgever van de badge. Dat is geen beslissing van de site waarvan het de badge is. Het is wat een CDN doet, op een SVG, bij elke paginalading, voor elke bezoeker.

Twee Lighthouse-audits reageren daarop. De audit op cookies van derden weegt vijf van de achtentwintig gewichten in die categorie, en een inspectorkwestie weegt er één. Zes gewichten verloren op een afbeelding. Over de achtendertig metingen van de vorige ronde was dat het volledige gat tussen 78 en 100.

Het derde gevolg is het gevolg dat geen enkele score vangt. Het IP-adres van elke bezoeker ging naar een bedrijf waarmee hij niet gekozen had te praten, op elke pagina, in ruil voor een getal in een voettekst.

Hem weghalen is het antwoord ook niet

We hadden de afweging maanden eerder al opgeschreven, in een commentaarregel: wil je dit ooit zonder toestemmingsbanner, dan is de SVG zelf hosten de route. Met het tegenargument erbij, namelijk dat een zelf gehoste kopie een foto is. De badge bestaat om een levende vermelding te tonen; bevries de bytes en je hebt een plaatje van een vermelding.

Er is een derde weg, en die is pas voor de hand liggend zodra je twee dingen scheidt die een browser tegelijk doet. De browser haalt bytes op, en de browser maakt een verbinding. Alleen dat tweede is het probleem.

De badge komt daarom nu van onze eigen oorsprong, op een pad in onze eigen API, en die route haalt de bron op de server op. Dezelfde bytes. De browser van de bezoeker doet één verzoek, aan ons. Er is op de lijn niets om een cookie op te zetten, want er zit helemaal geen derde partij in de pagina van de bezoeker. En het getal blijft live, want we blijven het vragen.

Best practices ging van 78 naar 100 op tweeëndertig van de zesendertig metingen. De overige vier zijn de artikelpagina's, die op 96 staan door een heel andere knop van een derde partij, en dat is een apart besluit en geen restant.

Wat een proxy verschuldigd is aan wie hij proxyt

Andermans bytes vanaf je eigen oorsprong leveren verandert wat ze zijn. Een SVG die via een afbeeldingstag geladen wordt kan geen script uitvoeren; dat is een garantie uit de specificatie en het is een goede. Maar op het moment dat die bytes van ons domein komen, is wat erin staat van ons.

De route controleert het antwoord daarom voordat ze het doorgeeft. Die controle is bewust geen opschoner. Een opschoner probeert gevaarlijke inhoud veilig te maken; deze weigert alles wat er niet uitziet als de badge die we al kennen, en de route valt terug op een bevroren kopie. Het slechtste geval is een badge van vanochtend in plaats van een badge van deze minuut, en dat is een prijs die het waard is om nooit te hoeven redeneren over wat andermans antwoord zou kunnen bevatten.

Twee van de weigeringen gaan specifiek over datgene waar deze hele wijziging voor bedoeld was. Een SVG kan naar een externe afbeelding verwijzen, en hij kan vanuit een stijldeclaratie naar een externe bron verwijzen. Elk van die twee zou een laag dieper dan de tag die we net weghaalden naar een derde partij reiken, vanuit een bestand dat wij als het onze leveren. Een controle die alleen naar scripts keek had ze allebei doorgelaten.

Bewust falen naar een plaatje

Elk faalpad geeft de bevroren kopie terug met status 200. Netwerkfout, timeout, een status die geen 200 is, een body die de controle niet vertrouwt: allemaal 200, met een badge erin.

De redenering gaat over hoe het falen eruitziet. Een 404 of een 502 op een afbeelding in de voettekst van elke pagina is een pictogram van een kapotte afbeelding op elke pagina, en dat leest als een kapotte site, voor een decoratief element. Een iets oude badge leest als helemaal niets.

De compensatie is dat het faalpad een korte cache-header draagt en het slaagpad een lange. Anders zou een storing van vijf minuten aan de bronkant de bevroren kopie voor iedereen het volledige cachevenster lang vastzetten.

Er is één bevroren kopie en die staat bewust niet als bestand in de publieke map. Als bestand zou hij naast de route een tweede publiek adres hebben, en een volgende ronde zou er met goede reden een afbeeldingstag op kunnen richten, wat stilletjes het levende gedrag weghaalt waarvoor deze hele constructie bestaat. Als constante bewaard is de enige manier om hem te leveren de route die eerst ook het netwerk probeert.

Twee caches met verschillend werk

Er zijn hier twee cachelagen, en ze verwarren levert een systeem op dat ofwel de bron hamert ofwel voor altijd oude bytes toont.

De datacache van het framework houdt het antwoord van de bron vast: met een hervalidatie van zes uur veroorzaakt één bezoeker per zes uur één uitgaand verzoek, ongeacht het verkeer. De HTTP-cache-header houdt ons antwoord vast, bij de CDN en in de browser. De bron zet vier uur op zijn eigen antwoord; zes uur aan onze kant is een bewuste halve stap ruimer, zodat een storing daar ons niet op een ritme van vier uur op de bevroren kopie laat vallen.

Eén kleine val, die een build kostte. Next leest de configuratie van een routesegment statisch uit de bron, dus de hervalidatie-export moet een letterlijk getal zijn. Hem als uitdrukking schrijven, ook als constante die een paar regels lager in hetzelfde bestand gedeclareerd is, breekt de build af met een fout over ongeldige segmentconfiguratie. De constante leest nu uit de export in plaats van andersom, dus er is nog steeds precies één getal.

De 307 die een startvlag was

Dezelfde ronde besteedde tijd aan iets dat eruitzag als een routeringsfout en dat niet was, en het is het waard vast te leggen omdat het een eerdere ronde volledig verspild heeft.

Bij het lokaal draaien van de productiebuild antwoordde elk kaal marketingpad met 307, doorverwijzend naar zichzelf. Niet de gelokaliseerde paden, niet de API-routes: de kale. Dit had de Engelse helft van elke lokale layoutsweep wekenlang geblokkeerd en stond genoteerd als een onverklaard defect.

Het is de hostbinding. Gestart met een letterlijk loopbackadres als hostnaam laat Next die waarde staan, terwijl een lege of jokerhostnaam genormaliseerd wordt naar localhost. De begin-URL en de oorsprong die de middleware berekent zijn het dan oneens, de rewrite blijft absoluut, de router behandelt hem als extern en gaat opnieuw naar binnen. Gestart met de joker, de waarde die productie gebruikt, of met localhost, antwoordt alles met 200.

Er was niets te repareren. Wat er wel te doen was, was de juiste startregel in het script schrijven en opschrijven waarom, want een defect dat in werkelijkheid een vlag is wordt anders door de volgende persoon met hetzelfde vertrouwen opnieuw ontdekt.

Het falen dat we niet gerepareerd hebben

Een derde ding uit dezelfde ronde is een bewuste niet-reparatie, en die verdienen het minstens zo zorgvuldig opgeschreven te worden als reparaties.

We hadden in het veld 404's op chunks gezien: HTML die verwijst naar JavaScript-bestanden die niet meer bestaan. De verklaring bleek één header te zijn. De homepage draagt een stale-while-revalidate-venster dat in een jaar gemeten wordt, dus een CDN-edge mag heel lang HTML van een oudere build leveren, en de chunknamen in die HTML horen bij die build.

De knop ligt er en we hebben hem laten liggen, want juist die oude kopie hield de site twee weken eerder in de lucht tijdens een crashlus van de database. Het venster verkorten ruilt een zeldzame kapotte lading in tegen een nog zeldzamere volledige storing. Dat is een echte afweging, ze hoort bij wie het risico draagt, en het werk van de ronde was het mechanisme uitleggen en niet de knoop doorhakken.

Wat we zouden opschrijven

  1. Een uniforme score op elke pagina wijst naar iets dat elke pagina deelt. Dat is het goedkoopste spoor dat je krijgt.
  2. Een afbeeldingstag is een verbinding, niet alleen bytes. Alles wat een CDN op een verzoek wil doen, doet hij ook op dit ene.
  3. Zelf hosten is niet het enige alternatief voor inbedden. Op de server ophalen behoudt het levende gedrag en haalt de derde partij uit de pagina van de bezoeker.
  4. Zodra je andermans bytes levert, zijn ze van jou. Controleer ze, en controleer specifiek op de verwijzingen die het gat dat je net dichtte weer zouden openen.
  5. Geef de voorkeur aan een oud plaatje boven een kapotte afbeelding. Voor decoratie kost een zichtbaar falen meer dan een onzichtbare veroudering, zolang het verouderingsvenster op het faalpad kort is.
  6. Geef de bevroren kopie geen publiek adres. Alles wat bereikbaar is wordt uiteindelijk gelinkt, en dan wordt het levende pad stilletjes overgeslagen.
  7. Weet welke cache wat vasthoudt. De ene houdt het antwoord van de bron vast, de andere het jouwe, en hun vensters beantwoorden verschillende vragen.
  8. Sommig rood is een vlag en geen fout. Reproduceer het mechanisme voordat je het symptoom repareert, en blijkt het je eigen startcommando te zijn, zeg dat dan in het script.

Voor de duidelijkheid over wat dit is: de route staat live en de scores komen uit een lokale productiebuild over zesendertig metingen, niet uit veldgegevens. De verklaring voor de 404's op chunks is uit headers afgeleid en niet gereproduceerd, en het besluit over dat cachevenster hoort bij de persoon die het beschikbaarheidsrisico draagt en niet bij de ronde.

Uit het platformwerk aan Provibr. Een andere meting die om de verkeerde reden groen stond staat in een toegankelijkheidsuitzondering die zichzelf meet, en een veld dat een intentie droeg waar een feit hoorde staat in een datum in de toekomst is geen agenda.

Begin met één host en één agent

Maak een account aan, installeer de agent met één commando en koppel je eerste Proxmox-host. De proefperiode loopt 14 dagen en vraagt geen betaalgegevens.