URL'ens historie: Hvis du ville logge på, skulle du oplyse passwordet som en del af URL’en
I denne artikel skal vi blandt andet se lidt nærmere på nogle tegn og kombinationer, som forekommer i mange URL’er, men som ofte bare fremstår som unyttig støj for de uindviede.
Men allerførst skal vi starte med en idé, som nok var praktisk dengang, men som i dag åbenlyst er en meget dårlig idé, nemlig muligheden for at kunne oplyse brugernavn og adgangskode i URL’en – på denne måde:
- emailE-mail
- linkKopier link

Fortsæt din læsning
- Sortér efter chevron_right
- Trådet debat
Nu er jeg så egentlig mere interesseret i Olufsen end o som så, men jeg kan godt se hvad du siger, hvorfor jeg selvfølgelig også skal replace & - det undrer mig så at validatoren ikke løfter en pegefinger.Ja men &o; er en HTML entitet. Den er dog ukendt, så muligvis vælger browseren at vise den i stedet for at fortolke. Hvis du udskifter "o" med "amp" eller "lt", etc, vil den pludselig fortolke det.
Jeg prøvede for sjov skyld at kikke på ReactJS, og der er f.eks. et eksempel med remarkable som outputter indholdet af et textarea - og der sker det sjove at hvis der er et lineskift i textareaet så kommer det ikke med i deres output, hvilket så ødelægger en hel del af værdien.Igen det mest effektive er at bruge et færdiglavet framework der sikrer at du ikke kan lave fejl her.
Interessant nok samme fænomen som nærværende forum som virker på samme jammerlige måde, så man er nødt til at lave to linjeskift, hvilket medfører en blank linje (nyt afsnit), hvis man gerne vil have bedre læsbarhed.
Det er imo ikke så imponerende, for så skal man alligevel til at tage specielhensyn til frameworkets særheder. - så vil jeg hellere lave de tilpasninger til mit eget framework som er nødvendige.
Øhh og er vi så ikke enige om at search and replace vel er det samme som det jeg kalder stringreplace og dermed er tilbage ved start, uden at have indkasseret de 100 kr - og så lige en lille faldgruppe, som du også pointerer, at det er vigtigt at det første man replacer er &, ellers risikerer man at lave dobbelt replace og dermed ødelægge det hele.Men hvis du vælger at lave noget selv, så er det ganske simpelt at lave en search and replace på de få tegn der skal beskyttes.
Dette er valid HTML (også ifølge W3Cs' validator):
Ja men &o; er en HTML entitet. Den er dog ukendt, så muligvis vælger browseren at vise den i stedet for at fortolke. Hvis du udskifter "o" med "amp" eller "lt", etc, vil den pludselig fortolke det.
Igen det mest effektive er at bruge et færdiglavet framework der sikrer at du ikke kan lave fejl her. Men hvis du vælger at lave noget selv, så er det ganske simpelt at lave en search and replace på de få tegn der skal beskyttes. Noget i stil med:
data.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll(""","").replaceAll("'","'")
Så skulle den være nogenlunde sikker uanset hvor i HTML koden det skal bruges :-)
Ideen er at starte med at escape & og herefter kan du tage resten i vilkårlig rækkefølge.
Dette er valid HTML (også ifølge W3Cs' validator):I attribute sektioner er det i stedet valgfrit enten ' eller " samt linjeskift, \ og & der ikke må forekomme.
<!DOCTYPE html> <html> <head><title>test</title></head> <body> <input type="text" value="xxx'<>blabla'ogquot;/*?b&o;:" id="indfelt" name="indfelt"><br><br> </body> </html>
Det virker med innerText i stedet for innerHTML. Men det er defekt HTML du har der. Der er tre tegn der ikke må forekomme i tekst sektioner i HTML: <, > og &.
I attribute sektioner er det i stedet valgfrit enten ' eller " samt linjeskift, \ og & der ikke må forekomme.
Det nemmeste hvis man arbejder med JavaScript er at bruge JSON til at overføre data til og fra serveren. Så skal du bare bruge et JSON bibliotek server side. JSON formattet har naturligvis også nogle tegn der skal escapes, men det er derfor du bruger noget nogle andre har lavet, som tager sig af det bøvl. På klienten har browseren indbygget JSON fortolker, så der behøver du ikke tænke over det.
Hvis du vil bygge det selv, så er det nemmeste nok at lave en simpel length/value protokol. Skriv først en linje med længden af value, ny linje efterfulgt af value efterfulgt af ny linje. Det er i øvrigt cirka sådan HTTP fungerer. Fordelen er at du kan overføre arbitrært data uden at skulle escape noget som helst.
En variant er at indføre feltnavn efter længden, så at du kan lave en generisk funktion der indlæser det i et javascript key value map. Du kan tilmed lave en generisk funktion der bruger elementID til at sætte værdierne automatisk og hvis du også automatisk vil have dem ud igen, så de kan sendes til serveren, så kan du nemt iterere over DOM træet for at finde dem uden at hardcode en liste af ID'er.
Men personligt vil jeg nu nok anbefale at læse op på noget som ReactJS, for det er en meget bedre måde at bygge web baseret systemer på i 2020.
Meget simplificeret, men du kan prøve at smide den ind i f.eks. W3Schools Tryit Editor (eller JSFiddle) og se resultatet.Har du et kode eksempel der demonstrerer problemet?
<!DOCTYPE html> <html> <body> <div id='xxx'>blabla'"/*?b&o</div> <input type="text" value="placeholder" id="indfelt" name="indfelt"><br><br> <script> document.getElementById("indfelt").value=document.getElementById("xxx").innerHTML; </script> </body> </html>
Og hvis jeg i stedet prøver at skrive en værdi direkte ind i valuefeltet, så får jeg problemet med ", som "lukker" valuefeltet, og dermed korrumperer resten af linjen, som tidligere beskrevet - mens & til gengæld ikke medfører nogen problemer.
Så jeg kan vælge mellem at blive hængt eller skudt.
Da der kan være en del felter der skal fyldes ud føler jeg ikke lige frem for at skulle lave et Ajax kald for hvert felt, så resultatet er blevet at jeg faktisk er endt med modellen hvor valuefeltet fyldes ud forlods, men jeg laver stringreplacement af " til HTML koden.
Det virker, og ser ud til at være ret robust.
Har du et kode eksempel der demonstrerer problemet?
@Baldur.
Det fungerer rigtig godt på den måde, så tak for hintet.
Tekstsstrengen kan nu indholde stort set hvad som helst, inklusive komma, punktum, slash, backslash, anførselstegn osv. - det fyldes altsammen ind i inputfeltet som forventet.
Der er dog en mærkelig lille krølle, nemlig at et & tegn konverteres til HTML koden ogamp; som så vises i stedet i inputfeltet - men umiddelbart kun & tegnet.
Hvis jeg bare råt og usødet har hældt det ind i en div, så er der ikke noget problem.
Har du et bud på den?
Super Baldur, tak.Programmet kan hentes herfra og der er screenshots der dokumentere ovenstående:
Nu har jeg godt nok ikke rodet med NodeJS, men jeg fangede ideen, og i virkeligheden kan det vel egentligt forklares meget simplere, nemlig ved at value tilføres vha. Javascript, efter at browseren har parset HTML'en.
Så jeg lavede et lille eksempel for at prøve det af, og det kan rent forståelsesmæssigt barberes ned til:
<!DOCTYPE html> <html> <body> <input type="text" value="xxx" id="indfelt" name="indfelt"><br><br> <script> document.getElementById("indfelt").value='8" højttaler'; </script> </body> </html>
At få variablen overført fra serveren er trivielt.
Så tak for lige at give mig det rigtige og brugbare hint.
Jeg har lavet et nyt program, denne gang i NodeJS. Designet explicit til at undgå enhver form for escape af tekststrenge. Ingen HTML entities og ingen JSON escape eller nogen anden form for behandling af tekst strenge. Teksten transmitteres som den er i UTF-8 format, fra databasen, over HTTP, gemmes i en ren JavaScript variabel, og når du klikker "Gem" sendes den til serveren som en ren UTF-8 streng og videre til databasen.
Hvis du vælger "view source" så står der blot value="loader" uanset den faktiske værdi i input feltet. Hvis du bruger Chromes udviklingsværktøj til at inspicere DOM træet, så står der også value="loader" uanset den faktiske værdi i input feltet. Brugere ser naturligvis ikke "loader" men eksempelvis 8" højtaler.
Programmet består af tre filer:
// server.js const express = require('express') const bodyParser = require('body-parser') const app = express() const port = 3000 const Pool = require('pg').Pool const pool = new Pool({ user: 'baldur', host: 'localhost', database: 'baldur', password: 'baldur', port: 5432, }) const getDims = (request, response) => { pool.query('SELECT navn FROM dims limit 1', (error, results) => { const navn = results.rows[0].navn console.log('getDims: '+navn) response.status(200).type('text/plain').send(navn) }) } const setDims = (request, response) => { const navn = request.body console.log('setDims: ' + navn) pool.query('update dims set navn=$1', [navn], (error, results) => { response.status(201).type('text/plain').send('ok') }) } app.use(bodyParser.text()) app.use(express.static('public')) app.get('/get', getDims) app.post('/set', setDims) app.listen(port, () => { console.log(<code>App running on port ${port}.</code>) })
// public/demo.js const navn = document.getElementById('navn') fetch('get').then((response) => { response.text().then(function (text) { navn.value = text }); }) function gem() { fetch('set', { method: 'POST', headers: { 'Content-Type': 'text/plain' }, body: navn.value }) }
public/demo.html:
[html]
<script src='demo.js'></script> [/html]Programmet kan hentes herfra og der er screenshots der dokumentere ovenstående:
Altså, du vil lade al HTML'en blive genereret ud fra Javascript, og så renderes.
HTML er et format til at gemme tilstanden af et DOM træ, dog uden eventtrickers og andet, som er usynligt i HTML repræsentation. Browseren indlæser en HTML side ved at parse HTML og generere DOM træet. Herefter kan man via JavaScript manipulere DOM træet, inklusiv slette og tilføje nye noder.
Browseren arbejder ikke med HTML og det vil ikke give mening løbende at generere HTML der repræsentere DOM træet. Browseren har ingen funktion til at gemme det aktuelle DOM træ, ud over et eventuelt developer værktøj. Developer værktøjet konvertere kun til HTML til ære for dig, så du nemmere kan forstå DOM træet. Den konvertering er nogle gange indkomplet, for i hvertfald Chrome genererer ugyldig HTML ved blandt andet at glemme at quote værdier korrekt.
Et DOM træ består af objekter som du kender fra et objekt orienteret programmeringssprog (rent praktisk naturligvis JavaScript objekter) og et input felt er repræsenteret ved en klasse som har nogle felter, herunder et value felt der indeholder den aktuelle værdi som en JavaScript tekst streng.
Quote karaktere, også kendt som HTML entities, er ikke noget JavaScript kender. Input-felt klassens value felt indeholder ikke HTML entities men blot den faktiske værdi, som du ser på skærmen. Det er helt analogt til at i C skal du muligvis skrive " i programteksten, men det der ender med at blive gemt i hukommelsen er kun " tegnet.
Med alt det vil jeg sige, at en JavaScript tilgang på klienten ikke genererer HTML. Den genererer DOM objekter. Som er JavaScript objekter, ikke HTML objekter. HTML kodning kommer aldrig på tale og herunder naturligvis hellere ikke den escaping der er nødvendig i HTML.
Nej, men den kan så ses vha. webdeveloper i f.eks. FF.
Jeg har ikke tjekket Firefox men Chromes DOM træ udviklingsværktøj viser ikke den aktuelle værdi i et inputfelt. Og den viser den initielle værdi uden quote tags, dvs som ugyldig HTML.
Det er åbenlyst at ingen browser vil vælge at gemme strings i quote form, så hvis den viser dem, så er det kun til ære for dig, dvs udviklingsværktøjets visualiseringen af DOM træet der generere tags som de ville have set ud, hvis der havde været HTML bag dette DOM træ.
Jeg tror jeg nu giver op. Rendering kan sagtens bruges om HTML generering, søg lidt på nettet. Og det kan også bruge om den endelige skærmoptegning, selvfølgelig, og 3D og alt muligt andet. Men du vil kun forstå din egen verden. Husk at kigge indad.
Du kan lave øvelsen med notepad, du behøver slet ikke noget framework.
Tak for denne gang.
Du misforstår vist hvad rendering går ud på.Du misforstår mig, når jeg her taler om rendering, så handler det om hvem som laver HTML strengen.
Rendering er når browseren "tegner" en side ud fra HTML kode - det andet er HTML generering og er noget helt andet.
Fra Wikipedia:
"A browser engine (also known as a layout engine or rendering engine) is a core software component of every major web browser. The primary job of a browser engine is to transform HTML documents and other resources of a web page into an interactive visual representation on a user's device."
Det gør ikke samtalen mere forståeligt hvis man pludselig afviger fra den almindelige fortolkning af begreberne.
Aha.Jeg tror du må læse lidt om det, eller endnu bedre kode det selv. Der sker ikke nogen stringreplacement/encoding. Det er en DOM operation, i DOM træet er værdier ikke HTML encodet. Igen, sammenligningen med SQL parametre er 100% analog - her sendes teksten heller ikke med escapet apostroffer.
Har du selv prøvet at lave præcis den øvelse jeg taler om?
Og i givet fald, hvilke værktøjer har du så benyttet?
Nej, men den kan så ses vha. webdeveloper i f.eks. FF.Som tidligere beskrevet, så vil du oså opleve at "view source" slet ikke viser den HTML streng som du nok forventer at se.
Øhh, nej, rendering foregår altid på klienten.
Du misforstår mig, når jeg her taler om rendering, så handler det om hvem som laver HTML strengen. Det sker klassisk på serveren, men kan også ske på klienten.
Et eller andet sted i processen skal der være en stringreplacment, således at anførselstegn konverteres til ogquotsemikolon, og tilbage igen den anden vej, hvem der så har ansvaret for den kan der være mange løsninger på - men det sker altså ikke på magisk vis.</p>
<p>Og selv om jeg så via et ajaxkald indsætter hele input linjen, feks. ved at bruge en divs id, eller tildeler value som du beskriver, så vil problematikken altså bestå, der må ikke forekomme et anførselstegn inde i en input value - der er nogle helt regelfaste krav til rendering af HTML, og dem kan vi altså ikke lave om på (og det er i bund og grund de regelfaste krav jeg mener man ikke har tænkt sig om med).
Jeg tror du må læse lidt om det, eller endnu bedre kode det selv. Der sker ikke nogen stringreplacement/encoding. Det er en DOM operation, i DOM træet er værdier ikke HTML encodet. Igen, sammenligningen med SQL parametre er 100% analog - her sendes teksten heller ikke med escapet apostroffer. Du har kun brug for encoding når du arbejder med HTML som en streng. Som tidligere beskrevet, så vil du oså opleve at "view source" slet ikke viser den HTML streng som du nok forventer at se.
Browseren sørger for at det sker tilbage igen (magi), som Baldur også skriver og det er nærmere beskrevet i HTML Standarden.Et eller andet sted i processen skal der være en stringreplacment, således at anførselstegn konverteres til ogquotsemikolon, og tilbage igen den anden vej, hvem der så har ansvaret for den kan der være mange løsninger på - men det sker altså ikke på magisk vis.
Altså, du vil lade al HTML'en blive genereret ud fra Javascript, og så renderes.De her frameworks kan jo virke på mange måder. Nogle sender blot en template (altså ikke HTML) som på klienten fortolkes via Javascript og renderes som HTML
Øhh, nej, rendering foregår altid på klienten.Men HTML kan også renderes på serveren
HTML'en (som renderes på klienten) kan genereres på serveren, aktivt eller passivt, men så vil vi være tilbage til start, fsva. indlejrede seperatorer, eller serveren kan generere den Javascript du nævner overnfor, som så genererer HTML'en, som så renderes på klienten.
Men i min optik en voldsomt kompliceret vej at gå, med kæmpe overhead.
Et eller andet sted i processen skal der være en stringreplacment, således at anførselstegn konverteres til ogquotsemikolon, og tilbage igen den anden vej, hvem der så har ansvaret for den kan der være mange løsninger på - men det sker altså ikke på magisk vis.og så skal klinten (igen via Javascript) blot sætte value på dine input felter. I begge udgaver finder du ingen streng-replacements.
Og selv om jeg så via et ajaxkald indsætter hele input linjen, feks. ved at bruge en divs id, eller tildeler value som du beskriver, så vil problematikken altså bestå, der må ikke forekomme et anførselstegn inde i en input value - der er nogle helt regelfaste krav til rendering af HTML, og dem kan vi altså ikke lave om på (og det er i bund og grund de regelfaste krav jeg mener man ikke har tænkt sig om med).
Den må du gerne uddybe - hvad mener du med at HTML genereres på klienten?
De her frameworks kan jo virke på mange måder. Nogle sender blot en template (altså ikke HTML) som på klienten fortolkes via Javascript og renderes som HTML. Men HTML kan også renderes på serveren, og så skal klinten (igen via Javascript) blot sætte value på dine input felter. I begge udgaver finder du ingen streng-replacements.
var str = ... streng fra et ajax kald; document.getElementById('myid').value = str;
De er ikke sårbar overfor forkert escape af dette inputfelt. Det har bare en sindssyg parser der ud over at supportere stjerner til at gøre tekst bold også forsøger at supportere udvalgt HTML syntaks. Og det virker ad pommern til.
Enig, de har valgt den farlige vej og forsøger at parse/fjerne tags. Der skal nok være et par XSS huller i den.
Hehe, du mener en kompensation for at "Teknologiens" mediehus ikke er lige så avancerede som Baldur :-D
De er ikke sårbar overfor forkert escape af dette inputfelt. Det har bare en sindssyg parser der ud over at supportere stjerner til at gøre tekst bold også forsøger at supportere udvalgt HTML syntaks. Og det virker ad pommern til.
Den må du gerne uddybe - hvad mener du med at HTML genereres på klienten?jeg tror du misser at HTML genereres ude på klienten
Hehe, du mener en kompensation for at "Teknologiens" mediehus ikke er lige så avancerede som Baldur :-DMange, mange tak. Det var ikke en fejl, men bevidst for at den ikke skulle fortolkes. Husk at kigge indad. :)
(Du havde så lige lavet en lille fejl med mellemrummet før semikolonet, men lad det nu ligge)
Mange, mange tak. Det var ikke en fejl, men bevidst for at den ikke skulle fortolkes. Husk at kigge indad. :)
Nu kender jeg ikke Scalatags, men pointen er vel at der ikke genereres statisk HTML med din tekststreng htmlencodet, som jo nok er det du søger.
Den kan køre både på server og klient. I det eksempel jeg har postet er det bare en traditionel server der laver noget HTML på serveren og derfor bliver den initielle input værdi naturligvis HTLM encoded før den resulterende HTML kode transmitteres.
Hvis man bruger Scalatags på klienten kan man vælge om den skal lave HTML eller DOM objekter. Det sidste er hurtigst og giver mulighed for efterfølgende at manipulere objekterne, så er det naturlige valg. Når den laver DOM objekter, så sker der naturligvis ingen HTML escape da det bare er en simpel variabel tildeling:
inputfelt.value = data;
hvor data er en variabel der kunne være hentet med et Ajax kald.
DOM objekter er naturligvis ikke gemt med HTML escapes i memory. Det ville ikke have noget formål.
Det interessante er i øvrigt at det ingen forskel gør om man vælger at lave HTML eller lave DOM objekter. Det er helt usynligt for programmøren hvordan den initielle input værdi bliver sat. Teknologien sørger for at escape, hvis escape er nødvendigt.
Og kan vi så ikke også blive enige om at "nogen" (mig, mit framework, eller julemanden) skal lave en stringreplacement før data gemmes i databasen?
Nej, vi er ikke enige. Hvis du bruger de rigtige abstraktioner/frameworks så sker dette aldrig (og det gør Baldur). Hverken når du skriver til databasen med parametre og når browseren sætter value via en DOM operation (jeg tror du misser at HTML genereres ude på klienten)
Hvis du arbejder direkte med SQL og HTML som strenge, ja så skal du huske at encode.
Kan du ikke bare svare på mit spørgsmål, hvordan vil indholdet af value se ud - det burde ikke være så svært at svare på!
For at være lidt fræk, så ved jeg det ikke. Er det noget der burde interessere mig? DET er pointen!
Det eneste jeg ved er at det ikke er et problem fordi jeg vælger at bruge teknologier, der ikke har problemet.
Ok ikke helt sandt, jeg ved fint hvordan de forskellige teknologier fungerer under hjelmen. Du bad om en gammeldags form der er HTML baseret, så naturligvis vil data overføres efter de regler der gælder for HTML. Senere bringer du Ajax på banen, og det er faktisk den metode jeg normalt bruger, og da overfører jeg IKKE data som HTML og dermed IKKE med HTML escape. Typisk bruger jeg JSON i begge retninger men det er bare et valg.
Når man bruger DOM kald fra JavaScript så modificeres HTML koden i øvrigt ikke. Så du vil slet ikke kunne se input værdien hvis du vælger view source. Det er ligesom du ikke kan se den aktuelle værdi i et input felt hvis du vælger view source på en traditionel HTML-siden uden javascript, du kan kun se hvad den startede som.
Og kan vi så ikke også blive enige om at "nogen" (mig, mit framework, eller julemanden) skal lave en stringreplacement før data gemmes i databasen?
Nej, hvis du lige smider en enctype="multipart/form-data" på form feltet, så overfører den følgende over nettet:
------WebKitFormBoundaryItFrr1492QD9BiWd Content-Disposition: form-data; name="navn" 8" højtaler ------WebKitFormBoundaryItFrr1492QD9BiWd--
Tada, ingen stringreplacement!
Og med Ajax bestemmer du fuldstændig selv formattet i begge retninger, så hvis string replacement genererer dig, så kan du bare bruge et format der ikke har det. Eksempelvis MIME multipart. Eller et binært format, eksempelvis Pascal style.
Tak![html][/html]
Og kan vi så ikke også blive enige om at "nogen" (mig, mit framework, eller julemanden) skal lave en stringreplacement før data gemmes i databasen?
(Du havde så lige lavet en lille fejl med mellemrummet før semikolonet, men lad det nu ligge)
Og hallelulja, hvis jeg prøver at gentage din html tekst som hthl inde i citat her i dette forum, så går det sandelig galt, derfor 8ogquotsemikolon!!
Kan du ikke bare svare på mit spørgsmål, hvordan vil indholdet af value se ud - det burde ikke være så svært at svare på!
Rolig nu, Baldur gør da et fantastisk arbejde med atr beskrive hvordan det hele hænger sammen.
Nu kender jeg ikke Scalatags, men pointen er vel at der ikke genereres statisk HTML med din tekststreng htmlencodet, som jo nok er det du søger.
[html] [/html]
HTML renderes sandsynligvis ud fra en template og vædier sættes via DOM operationer (det hele sker på klinten)
Kan du ikke bare svare på mit spørgsmål, hvordan vil indholdet af value se ud - det burde ikke være så svært at svare på!MIN pointe er at du bør bruge et bibliotek til at håndtere formatet ,så du ikke kan lave fejl, ja så du endog ikke behøver vide præcis hvordan formatet koder data.
Godt, og hvis jeg så går ind på siden og viser kildekoden, hvordan ser din "text" ud hvis det er min 8" højttaler?
Scalatags har gjort det nødvendige. Prøv at genlæse hvad jeg skriver om mine pointer. Hvis du vælger vis kildekode for JSX varianten, så ser du intet da den ikke generer HTML i tekstform (hvorfor skulle den?). JSX varianten overføre data i JSON som sikkert også escapper " på en anden måde, men why do we care?
Rent datalogisk kan jeg kun komme i tanke om få muligheder for at overføre arbitrært data og den ene virker ikke for noget mennesker skal kunne skrive (HTTP chunked encoding med længde i starten af hver blok). De andre er en escape mekanisme og det man gør ved MIME multipart emails (ikke egnet her). Og så måske DNS punycode, hellere ikke en forbedring.
At opfinde et nyt tegn virker IKKE. Hvordan indlejre du så dokumenter af samme type, eksempelvis på nærværende forum hvor vi indtaster HTML eksempler på en HTML side? Hvis det kan foranledige at nogen tror vi kan klare sig uden at brug af solide værktøjer, der automatisk tager sig af det, så har du bare åbnet for massive problemer med cross site hacking.
Så medmindre dit forslag er at gøre HTML til et binært dataformat med feltlængde i starten af hver streng, så har HTML, JSON og alle andre tekstformatter der kan repræsentere arbitrær data, inklusiv indlejrede dokumenter af samme type, det til fælles at de gør brug af en escape mekanisme eller noget andet der minder om. MIN pointe er at du bør bruge et bibliotek til at håndtere formatet ,så du ikke kan lave fejl, ja så du endog ikke behøver vide præcis hvordan formatet koder data.
Godt, og hvis jeg så går ind på siden og viser kildekoden, hvordan ser din "text" ud hvis det er min 8" højttaler?På HTML siden ser du:</p>
<p>input(<code>type</code> := "text", name := "navn", value := navn)</p>
<p>
Nu har jeg ikke prøvet at rode med Ammonite, er det noget du har prøvet i praksis?
Ammonite er mit standard shell scripting sprog, så ja jeg har en masse kørende. Det er Scala med en udvidelse der gør det mere egnet til brug som shell scripting. Den største forskel er at du ikke skal oversætte (compile) da den automatisk finder ud af at gøre det hvis du har ændret i scriptet. Dernæst at du automatisk har adgang til alle Scala og Java biblioteker med "import $ivy" som får den til automatisk at downloade det du skal bruge.
Altså hent noget med " i et databasefelt (trivielt), vær sikker på det omskrives til ogquotsemikolen i input value, og endelig vær sikker på det ved submit igen gemmes som "?
Du kan i ovenstående program se hvordan det gøres:
sql"update dims set navn=${navn}".execute.apply
Det bliver til en god gammeldags PreparedStatement med navn=? i motorrummet. Ingen mulighed for SQL injection her.
På HTML siden ser du:
input(<code>type</code> := "text", name := "navn", value := navn)
Det der er ScalaTags som er et Scala bibliotek til at håndtere HTML som et DSL. Pointen her er at den automatisk ved i hvilken kontekst du indsætter en variabel og dermed også hvordan den eventuelt skal omskrives. Helt generelt kan man sige, at man skal bruge et framework der kan forstå HTML som mere end blot en streng. I JavaScript kan du eksempelvis vælge at bruge metoder der håndtere DOM træet direkte og så undgår du også problemer.
PS, og lad os lige løfte barren lidt, og huske at nogen kald kan være Ajax kald, og der som regel på en side også er en masse JavaScript der måske skal flytte rundt på data.
Jeg lavede det eksempel som en god gammeldags form submit fordi du bad om det. Normalt vil jeg lave den slags med eksempelvis ReactJS og Ajax kald. Det skaber ingen problemer, jeg har tidligere i tråden givet et eksempel på hvordan det ser ud:
const element = <h1>Hello, {name}</h1>;
Det der er JSX https://reactjs.org/docs/introducing-jsx.html som gør mere eller mindre det samme som ScalaTags bare i JavaScript. Igen ved den helt naturligt i hvilken kontekst {name} står i. Det kunne også være:
const element = <input type="text" name="navn" value={navn}/>
Og hvis man bruger NodeJS på serversiden, så kan du selv vælge om du kører JSX på serveren eller klienten, resultatet bliver det samme. ScalaTags kan i øvrigt fungere sammen med Scala.js og på den måde ligeledes køre på både server og klient.
Jeg er sikker på at der femten alternativer der gør noget lignende. Dette er bare de teknologier jeg har arbejdet med.
Eksempel på Ajax kald:
fetch("nytKabel", { method: "POST", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(kabelData) }).then((response) => { return response.json(); }).then((data) => { console.log(data) })
Der er ikke rigtig så meget at sige på server siden, du stopper det ind i dine JSON udpakker og får objekter du kan arbejde med uden at skulle tænke på hvordan JSON formattet håndterer vilkårligt data.
Nu har jeg ikke prøvet at rode med Ammonite, er det noget du har prøvet i praksis?Her er et eksempelprogram skrevet i Ammonite (<a href="https://ammonite.io/">https://ammonite.io/</a>).
Altså hent noget med " i et databasefelt (trivielt), vær sikker på det omskrives til ogquotsemikolen i input value, og endelig vær sikker på det ved submit igen gemmes som "?
PS, og lad os lige løfte barren lidt, og huske at nogen kald kan være Ajax kald, og der som regel på en side også er en masse JavaScript der måske skal flytte rundt på data.
PS.:
baldur=# select * from dims ; navn ------------- 8" højtaler (1 row)
Godt, hvordan vil du så håndtere følgende:</p>
<p>Hent min 8" højttaler fra databasen, fyld værdien i et inputfelt (sætter value på input af typen text), tillad brugeren retter det til f.eks. 8" subwoofer (uden han piller ved anførselstegnet), og han dernæst returner data via en form submit?</p>
<p>Hvad bliver så gemt i databasen, hvis ikke "nogen" undervejs laver stringreplacement?
Her er et eksempelprogram skrevet i Ammonite (https://ammonite.io/).
Jeg ved ikke om din pointe skal være at webbrowseren, webserveren og frameworks under hjelmen laver en masse omskrivninger. Min pointe er at det skal ikke være noget du som programmør fedtes ind i og på den måde kan du hellere ikke lave fejl. Og det bliver du så hellere ikke med moderne værktøjer og programmeringsstil.
#!/usr/bin/env amm import $ivy.<code>org.postgresql:postgresql:9.4-1200-jdbc41</code> import $ivy.<code>org.scalikejdbc::scalikejdbc:3.1.0</code> import $ivy.<code>com.typesafe.akka::akka-http:10.1.12</code> import $ivy.<code>com.typesafe.akka::akka-stream:2.5.26</code> import $ivy.<code>com.lihaoyi::scalatags:0.8.2</code> object Database { import scalikejdbc.<em> Class.forName("org.postgresql.Driver") ConnectionPool.singleton("jdbc:postgresql://localhost:5432/baldur", "baldur", "baldur") def getDims: String = { DB.localTx { implicit tx => val data = for (rs <- sql"select navn from dims limit 1") yield rs.string("navn") data.list.apply.head } } def setDims(navn: String) = { DB.localTx { implicit tx => sql"update dims set navn=${navn}".execute.apply } } } object HTML { import scalatags.Text.all.</em> def makeHTML(navn: String) = { html( body( div( h1("Form demo"), form( method := "post", input(<code>type</code> := "text", name := "navn", value := navn), input(<code>type</code> := "submit", value := "Gem") ) ) ) ) } } object HTTP { import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.model.<em> import akka.http.scaladsl.server.Directives.</em> import akka.stream.ActorMaterializer def runWebserver = { implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() val route = path("hello") { concat( get { complete(HttpEntity(ContentTypes.<code>text/html(UTF-8)</code>, HTML.makeHTML(Database.getDims).toString)) }, post { formFields('navn) { (navn) => Database.setDims(navn) redirect("/hello", StatusCodes.SeeOther) } } ) } val bindingFuture = Http().bindAndHandle(route, "::", 5001) println("klar på port 5001") while(true) Thread.sleep(1000) } } @main def main() = { HTTP.runWebserver }
Godt, hvordan vil du så håndtere følgende:Name kan komme direkte fra en database, det er ligemeget. Der er sørget for at den kan indeholde vilkårlig data inklusiv tegn der skal escapes. Hvorvidt ReactJS fixer dette ved at escape eller om de blot kalder de relevante DOM metoder direkte, således at det ikke er nødvendigt, er irrelevant.
Hent min 8" højttaler fra databasen, fyld værdien i et inputfelt (sætter value på input af typen text), tillad brugeren retter det til f.eks. 8" subwoofer (uden han piller ved anførselstegnet), og han dernæst returner data via en form submit?
Hvad bliver så gemt i databasen, hvis ikke "nogen" undervejs laver stringreplacement?
Og det er helt legitimt inde i et inputfelt at skrive 8" højttaler, som så faktisk overføres med ", ikke ogquotsemikolon, men hvis jeg henter værdien fra en database, så er jeg nødt til at konvertere, ellers ødelægges HTML'en.
Det er hvad jeg forsøger at sige, de fleste moderne HTML baseret frameworks har en metode, så at du ikke skal tænke på at konvertere. Det er helt analogt til SQL injection, den slags sker ikke hvis man koder korrekt.
Lad mig bruge ReactJS som eksempel:
const name = 'Josh Perez'; const element = <h1>Hello, {name}</h1>; ReactDOM.render( element, document.getElementById('root') );
Ovenstående er andet eksempel fra https://reactjs.org/docs/introducing-jsx.html
Name kan komme direkte fra en database, det er ligemeget. Der er sørget for at den kan indeholde vilkårlig data inklusiv tegn der skal escapes. Hvorvidt ReactJS fixer dette ved at escape eller om de blot kalder de relevante DOM metoder direkte, således at det ikke er nødvendigt, er irrelevant.
En tekststreng er jo en repræsentation af en bagvedliggende hexværdi (ascii), så der behøver jo sådan set ikke være en grafisk fremstilling af det - at det så kan være ganske praktisk er en anden sag, men så kunne man jo have opfundet nogle tegn som ikke konflikter med almindeligt skriftsprog.
Når det nu har været dit kæphest i mange år, og du aldrig ser det løst, så er det måske på tide at kigge ind af. :)
Du er nødt til at skelne mellem en visuel streng, som mennesker skal indtaste og læse fx en URL. Her skal vi kunne se separator-tegnet og samme sekund du har indført det, er der nogen som vil gemme det i en værdi (fx en url i en url). Prøv også at forestille de exploits der kunne ligge i en URL, hvis der er usynlige tegn?
Hvorfor tror du ikke at alle nyere programmeringssprog fikser din kæphest? Giv mig et sprog som ikke har escape-tegn til strenge.
Man kunne har gjort HTML til et binært format, som kun kunne genereres med et programmeringssprog/bibliotek. Det ville sikkert være gavnligt (ironi), men igen så flytter du blot det menneskevenlige præsentation og escapebehovet et led længere ud.
Det løser jo kun halvdelen af problemet.Og hvis databasen er PostgreSQL (ved ikke hvordan MySQL fungerer) så bliver sidstnævnte overført med en binær protokol, hvor hvert felt starter med længden af det efterfølgende data, Pascal style, hvorfor ingen escape eller string replacement er nødvendig.
Der er ikke noget problem i at lave parameteriserede variable, det gør jeg allerede i forvejen, så ingen problemer med SQL injections, og jeg kan for den sags skyld sagtens gemme ogquotsemikolon (gider altså ikke prøve at bøvle med V2!).
Men som jeg skrev, så er det ikke nok i et heterogent miljø, for hvis min 8" højttaler indtastes i et andet system, og skal bruges der, så går den ikke.
Og det er helt legitimt inde i et inputfelt at skrive 8" højttaler, som så faktisk overføres med ", ikke ogquotsemikolon, men hvis jeg henter værdien fra en database, så er jeg nødt til at konvertere, ellers ødelægges HTML'en.
Du skal jo ikke kikke meget længere end nærværende placeholder for debatten, det burde være noget af det ypperligste her i landet, men det fungerer jo også kummerligt.
Og så er der alle morsomhederne når man skal eksportere data via en kommasepareret fil.
og under alle omstændigheder bliver dit "framework" altså nødt til at lave en masse bagvedliggende string replacements
Gør det? Hvis vi sammenligner klassisk PHP skod kode:
$sql = "select * from foo where bar = '" + $bar + "'";
Med moderne kode:
$sql = "select * from foo where bar = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("s", $bar);
Og hvis databasen er PostgreSQL (ved ikke hvordan MySQL fungerer) så bliver sidstnævnte overført med en binær protokol, hvor hvert felt starter med længden af det efterfølgende data, Pascal style, hvorfor ingen escape eller string replacement er nødvendig.
Og ja første eksempel fører til: https://xkcd.com/327/
Problemet med URL, HTML og andre tekst baseret formatter, som skal kunne transportere vilkårlig information inklusiv indlejrede dokumenter af samme type, er at der ikke findes nogen måde at undgå at have en escape mekanisme. Det er ligemeget om du opfinder nye specialtegn. Hvis ikke du sender alt igennem en robust mekanisme der sikrer at ting er escapet korrekt, er at du havner i XKCD nummer 327.
With all due respect, det er noget vrøvl Baldur.Sådan gør man ikke i noget fornuftigt framework, hverken til databaser eller html. Det sker automatisk så der ikke opstår fejl.
Der er ikke lige noget Karlsons klister der lige fikser den, slet ikke i et heterogent miljø - og under alle omstændigheder bliver dit "framework" altså nødt til at lave en masse bagvedliggende string replacements, pga. nogle dovne programmører historisk har sprunget over hvor gærdet var absolut lavest.
Hvis jeg f.eks. har en værdi der hedder noget med en 8" højttaler i et databasefelt, så er jeg nødt til at søge gennem min tekststreng og erstatte " med den tilsvarende escape sekvens hvis jeg skal bruge strengen i et HTML inputfelt, og guddødemig en gang til den anden vej.</p>
<p>Det er sgu da tåbeligt.
Sådan gør man ikke i noget fornuftigt framework, hverken til databaser eller html. Det sker automatisk så der ikke opstår fejl.
Hvorfor det?Det giver altså ikke helt mening, man skal jo kunne aflæse seperatortegnet i en URL, derfor skal der jo være et tegn som angiver det.
En tekststreng er jo en repræsentation af en bagvedliggende hexværdi (ascii), så der behøver jo sådan set ikke være en grafisk fremstilling af det - at det så kan være ganske praktisk er en anden sag, men så kunne man jo have opfundet nogle tegn som ikke konflikter med almindeligt skriftsprog.
Og diskussionen rækker sådan set lidt videre en kun til URL'er.
Hvis jeg f.eks. har en værdi der hedder noget med en 8" højttaler i et databasefelt, så er jeg nødt til at søge gennem min tekststreng og erstatte " med den tilsvarende escape sekvens hvis jeg skal bruge strengen i et HTML inputfelt, og guddødemig en gang til den anden vej.
Det er sgu da tåbeligt.
Hvad kom først, almindeligt skriftsprog eller datamater?... og de her specieltegn, hvordan skulle man indtaste dem i sin kode? Eller hvordan skulle de optræde i en URL? De må jo være visuellle, og så pludselig en dag er der nogen som vil gemme disse specieltegn i en værdi og så skal du igen escape.
Hvis det udgør et problem (eller programmøren er for doven) at skrive f.eks. chr(29) i ens program, så har jeg sådan ikke noget problem med der opfindes en række grafiske repræsentationer af det, på linje med backslash, som Baldur skriver.
Det er klart det vil også kunne give problemer, men primært når programmører udveksler erfaringer, men vil friholde almindeligt sprogbrug.
Hvilket endnu engang leder frem til min kæphest, nemlig at man kvajede sig voldsomt i barndommen, da man undlod at opfinde en række specialtegn, men i stedet tillod at lade tegn, som er en del af det almindelige sprog, blive brugt som seperatorer mv.
Der er mindst et godt eksempel på et specialtegn der blev indført af den årsag: \ (backslash). Tegnet har tilsyneladende ikke noget dansk navn. Der er også | (pipe) som dog også bruges i matematik.
Problemet er bare at vi så er nødt til at escape specialtegnene. Pludselig skal du skrive \\ for at udskrive et enkelt \. Og skal du udskrive denne sætning, så må du skrive \\\\ for at få det første med etc :-)
PS.: Version2 kræver at jeg escaper \ så jeg har skrevet dobbelt så mange af dem, som du læser her...
... og de her specieltegn, hvordan skulle man indtaste dem i sin kode? Eller hvordan skulle de optræde i en URL? De må jo være visuellle, og så pludselig en dag er der nogen som vil gemme disse specieltegn i en værdi og så skal du igen escape.
En hyppig og overset årsag til at ting forsvinder, synes at være skift af web-server.
Ja, og når diverse ministerier, styrelser og andet (offentligt) overgår til andet ressortområde --- så har man en masse bogmærker som er ubrugelige :-(
En hyppig og overset årsag til at ting forsvinder, synes at være skift af web-server. En server, der kører på Windows er ret ligeglad med om et bogstav er stort eller lille, så sjusk her giver ingen problemer. Før man flytter tilen Unix-lignende server. Så fejler de måske. Æ, ø og å i navne på billedfiler synes også at give overraskelser, når man flytter server.
Ja det er jo ligesom hele hjørnestenen hvis vi taler CGI variable.Sådanne teknikker er meget udbredte i dag.
At man så ikke kan se URL'en hvis der bruges POST i stedet for GET ændrer sådan set ikke på det.
Hvilket endnu engang leder frem til min kæphest, nemlig at man kvajede sig voldsomt i barndommen, da man undlod at opfinde en række specialtegn, men i stedet tillod at lade tegn, som er en del af det almindelige sprog, blive brugt som seperatorer mv.I praksis er dette en form for ‘escape’, for at og-tegnet skal tolkes rigtigt.
Hvorfor vi stadig i det 21' århundrede skal rode med at omskrive almindeligt sprogbrug til escapesekvenser, fordi "man" åbenbart har ment at mennesket skal tilpasse sig maskinen, ikke omvendt.
Jeg har bitchet over det tidligere, f.eks. tekstseperatorer, og det mest kreperlige er at man kunne sådan set bare have brugt Char 28-31, men dovne programmører synes det var lettere bare at bruge anførselstegn som det f.eks. bruges i SQL.
Er overskriften ikke lige strammet en tak for meget?
Det er korrekt at syntaxen for URI'er tillader at authentificerings-oplysninger fremgår ar URI'en, men derfra og til at det var den normale måde at authentificerer sig på er der lidt et skridt.
Mig bekendt har alle interaktive browsere, med understøttelse for HTTP Basic Auth, altid givet mulighed for at skrive brugernavn og kodeord udenom url'en.
Hele forklaringen om Base64 er dog også malplaceret i en artikel om URL'ens historie, da det er et protokol-spørgsmål og ikke et addresserings spørgsmål.