Ordinær eksamen - ABC-system
Type: Blandet kodeanalyse - Systemforståelse, Dockerfile, CGI, HTML, sikkerhet
Fokus: Filroller, Docker-optimalisering, HTTP-metoder, CGI-miljøvariabler
Metode: Skriv egne svar først, sammenlign deretter med sensorveiledning
(06%) Del 1: Gi en kortfattet og overordnet beskrivelse av dette eksempelsystemet.
(14%) Del 2: Gi en kortfattet og overordnet beskrivelse av hvilken rolle hver av filene spiller i eksempelsystemet. La svaret hovedsaklig være basert på filnavnene – uten nødvendigvis å gå inn på innholdet i filene.
Filer: compose.yaml, Dockerfile, index.html, abc.js, abc.cgi, abc.dtd, abc.css
Dette er et webbasert system med et HTML-basert grensesnitt mot en database. Grensesnittet gir brukeren mulighet til å hente og endre data i databasen.
compose.yaml - En fil med parametre som bestemmer systemets tilstand. Gjør det mulig å enkelt håndtere bygging, oppstart, nedstenging og omstart av systemet ved hjelp av docker-compose.
Dockerfile - Beskriver hvordan konteinerbildet skal bygges (ved hjelp av f.eks. Docker). Systemet kjører en webtjener i en kontainer basert på dette bildet.
index.html - Gir brukergrensesnittet i form av et skjema som fylles ut og sendes til et CGI-skript på webtjeneren.
abc.js - Inneholder en funksjon som kjøres ved klikk på en knapp i brukergrensesnittet. Funksjonen gjør en HTTP-PUT-forespørsel mot et CGI-skript – en forespørsel om å gjøre endringer i databasen.
abc.cgi - Inneholder kode som behandler forespørselene (GET eller PUT) fra klienten. Ved GET gjøres oppslag i databasen. Ved PUT gjøres endring i databasen.
abc.dtd - Definerer hva som er gyldig format for XML-dokumentet som sendes (av funksjonen i abc.js).
abc.css - Inneholder bestemmelser om utseende for brukergrensesnittet (fargelegging av knappene).
(18%): Gi en detaljert beskrivelse, linje for linje, av filen Dockerfile.
(02%): Tre av linjene i filen begynner med ordet RUN. Forklar kort hvorfor det kan være lurt å slå disse sammen til én enkelt linje.
1: FROM alpine 2: RUN apk add busybox-extras libxml2-utils sqlite 3: COPY abc.cgi var/www/cgi-bin/abc.cgi 4: COPY index.html abc.css abc.js abc.dtd var/www/ 5: RUN echo "CREATE TABLE abc (a1 SMALLINT PRIMARY KEY, a2 VARCHAR(200))" | \\ 6: sqlite3 var/www/abc.db 7: RUN echo "INSERT INTO abc VALUES (1,'a'),(2,'b');" | \\ 8: sqlite3 var/www/abc.db 9: RUN chmod a+w var/www/abc.db 10: EXPOSE 80 11: CMD httpd -p 80 -h /var/www -f -vv
Linje 1: Angir at lettvekts-linuxdistroen Alpine skal brukes som grunnbilde. De påfølgende linjene legger lag på lag oppå dette.
Linje 2: Installerer tre programpakker (busybox-extras, libxml2-utils og sqlite). De nye filene vil utgjøre et nytt lag i bildet som bygges.
Linje 3: Kopierer en fil (abc.cgi) inn i et nytt lag i bildet som bygges.
Linje 4: Kopierer fire filer (index.html, abc.css, abc.js og abc.dtd) inn i et nytt lag i bildet som bygges.
Linje 5-6: Oppretter databasen (med en tabell) i en fil i et nytt lag i bildet som bygges.
Linje 7-8: Setter inn verdier i databasen. Ny versjon av databasefila blir opprettet i et nytt lag av bildet som bygges.
Linje 9: Gjør databasenfilen skrivbar (for alle brukere av systemet) slik at det er mulig å gjøre endringer i databasen. Endringen medfører en ny versjon av databasefila – i et nytt lag i bildet som bygges.
Linje 10: Angir at systemet kommer til å bruke TCP-port 80 for å lytte etter innkommende forespørsler.
Linje 11: Angir hvilken kommando som skal utføres når en konteiner, basert på bildet som bygges, igangkjøres. Kommandoen starter en webtjener som er innebygd i busybox.
Hver RUN-kommando lager et nytt lag i bildet som bygges. Ved å slå sammen flere RUN-kommandoer reduseres antall lag. Bildene vil dermed bli mer kompakte – mindre lagringsplass, mindre overføringstid og raskere konteiner-oppstart.
(03%): Forklar kort funksjon/virkemåte og hensikt med den innledende delen (linjene 1–3)
(06%): Forklar kort funksjon/virkemåte og hensikt med den første kodeblokken i if-setningen (linjene 4–12)
(06%): Forklar kort funksjon/virkemåte og hensikt med den andre kodeblokken i if-setningen (linjene 13–18)
(05%): De to kodeblokkene gjør begge en tilordning av variabelen B (linjene 5 og 14). Dette gjøres på to forskjellige måter. Forklar hvordan og hvorfor det må være ulikt.
1: #!/bin/sh 2: echo "Content-type:text/plain;charset=utf-8" 3: echo 4: if [ "$REQUEST_METHOD" = "GET" ]; then 5: B=$(echo "$QUERY_STRING" | tr '&' ' ') 6: for I in $B; do 7: N=$(echo "$I"|cut -f1 -d=) 8: V=$(echo "$I"|cut -f2 -d=) 9: if [ "$N" = "a1" ]; then 10: echo SELECT '*' FROM abc WHERE a1="$V" | sqlite3 ../abc.db 11: fi 12: done 13: elif [ "$REQUEST_METHOD" = "PUT" ]; then 14: B=$(head -c "$HTTP_CONTENT_LENGTH") 15: A1=$(echo "$B" | xmllint --xpath "/abc/a1/text()" -) 16: A2=$(echo "$B" | xmllint --xpath "/abc/a2/text()" -) 17: echo UPDATE abc SET a2="'"$A2"'" WHERE a1=$A1 | sqlite3 ../abc.db 18: fi
Linje 1: Angir stien til programmet som skal tolke de etterfølgende kommandoene. I dette tilfellet angir stien at dette er et shell-skript.
Linje 2: Skriver ut slutten av HTTP-hodet. Siden dette er et CGI-skript, er det webtjenerens ansvar å skrive begynnelsen av hodet. I dette tilfellet angis at kroppen skal tolkes (av HTTP-klienten) som ren tekst.
Linje 3: Angir et skille – slutten av hodet og begynnelsen av kroppen.
Før webtjeneren starter CGI-skriptet lagrer den informasjon fra HTTP-forespørselen i miljøvariabler som arves av prosessene som kjører CGI-skriptet. I kodeblokken i linjene 4–12 brukes informasjon om type HTTP-forespørsel (REQUEST_METHOD) og spørrestrengen (QUERY_STRING). Den sistnevnte inneholder det som står etter spørsmåltegnet i URL-en.
Om forespørselstypen er GET, gjøres et oppslag i databasen basert på skjemaverdiene som ble sendt inn og kodet som en spørrestreng (etter spørsmåltegnet i URL-en).
Utskriften fra databaseoppslaget skrives til standard utgang (STDOUT). Denne er omdirigert til (en socket som er koblet til) HTTP-klienten. Resultatet hos klienten blir at websiden med skjemaet blir erstattet av resultatet fra databaseoppslaget.
Om forespørselstype er PUT, kjøres kodeblokken i linjene 14–17. Her hentes også informasjon fra tekstfeltene i skjemaet. Denne gangen er de formatert som XML og sendt i HTTP-forespørselens kropp.
Skriptet bruker informasjon om lengden av kroppen for å vite hvor mange byte som skal leses fra standard inngang (STDIN) – som er koblet til HTTP-klienten. Informasjon om kroppslengden er på forhånd satt av webtjeneren i miljøvariabelen HTTP_CONTENT_LENGTH.
Verdiene hentes ut av XML-dokumentet og brukes som grunnlag for en oppdatering i databasen.
Her skrives ingen ting ut. På klientsiden blir websiden med skjemaet stående uendret, siden det ikke finnes kode som endrer den.
Med PUT sendes dataene i HTTP-kroppen, og må dermed leses fra standard inngang (STDIN) – som er koblet til HTTP-klienten.
Med GET sendes dataene i URL-en, og må dermed hentes fra en miljøvariabel (QUERY_STRING) som settes av webtjeneren.
(05%): Forklar hva brukeren ser når filen lastes i en nettleser.
(02%): Forklar betydningen av linjene 1, 2 og 17.
(05%): Forklar betydningen av linjene f.o.m. 3 t.o.m. 8.
(05%): Forklar betydningen av linjene f.o.m. 9 t.o.m. 16.
(03%): Websiden gir brukeren to måter å sende data. Forklar forskjellen på dem.
1: <!doctype html> 2: <html> 3: <head> 4: <meta charset="utf-8"> 5: <title>ABC</title> 6: <link rel="stylesheet" type="text/css" href="abc.css" /> 7: <script src="abc.js"> </script> 8: </head> 9: <body> 10: <form action='cgi-bin/abc.cgi' method='get'> 11: <input name='a1' id='a1' type='text'> 12: <input name='a2' id='a2' type='text'> 13: <input type='submit'> 14: </form> 15: <button type="button" onclick='abc1()'> U </button> 16: </body> 17: </html>
Brukeren kan se følgende:
Linje 1: Angir at dokumenttypen er HTML (HTML5).
Linjene 2 og 17: Angir rot-elementet. Det omslutter selve dokumentet med start- og slutt-merkelapper (-tagger).
Linjene 3–8 utgjør HTML-dokumentets hode, som er omsluttet av merkelapper for start (linje 3) og slutt (linje 8).
I hodet ligger informasjon om:
Linjene 9–16 utgjør HTML-dokumentets kropp, omsluttet av merkelapper for start (linje 9) og slutt (linje 16).
I kroppen finner vi:
abc1() (definert i abc.js)Den ene knappen utløser en PUT-forespørsel som sender data som en del av HTTP-kroppen (formatert som XML), mens den andre sender en GET-forespørsel som sender dataene i URL-en, som er en del av HTTP-hodet.
Den førstnevnte sender data formatert eksempelvis slik: navn1=verdi1&navn2=verdi2. Dataene blir tilgjengelig i en miljøvariabel i CGI-skriptet.
I sistnevnte tilfelle blir dataene sendt i XML-format og må leses fra standard inngang (STDIN) i CGI-skriptet.
Basert på eksistensen av Dockerfile og compose.yaml: Hva kan du si om sikkerhetsmekanismer og prinsipper som er i bruk i systemet?
Linje 12 i filen abc.js antyder en sikkerhetsmekanisme. Forklar hvordan en slik sikkerhetsmekanisme fungerer.
// Linje 12 i abc.js: credentials: 'include',
Eksistensen av filene indikerer bruk av operativsystemvirtualisering/konteiner. Dette betyr at systemet har stor grad av isolasjon/begrensning av ressurser fra vertssystemet. Da er diverse mekanismer innebygd i Linux-kjernen tatt i bruk. Spesielt bør namespaces, cgroups og capabilities nevnes.
Konteinere lages ofte etter prinsipper som innebærer:
Eksistensen av compose.yaml indikerer at et eget nettverkssegment med nettverksadresseoversettelse (NAT) er satt opp og at kun angitte porter er tilgjengelig (som en brannmurfunksjonalitet).
Identitetsbevis (credentials) skal følge med i HTTP-forespørselen. Dette antyder at en autentiseringsmekanisme er implementert ved hjelp av informasjonskapsler (cookies).
Hvordan det fungerer:
Set-cookie: [...])Cookie: [...])Velg en fil fra listen over for å vise koden...