📝 TSD3060 Eksamen 2023-2024

Kontinuasjonseksamen - Bidragsystem med CGI/XML

ℹ️ Om denne eksamenen

Type: Kodeanalyse av bidragsystem med CGI, JavaScript, XML og DTD

Fokus: Systemforståelse, filroller, kjørested-analyse, kodeforklaring linje-for-linje

Metode: Skriv egne svar først, sammenlign deretter med sensorveiledning

Oppgave 1 - Anvendelse 4%

Gi et eksempel på hva du tenker systemet kan brukes til. Begrunn svaret.

✅ Sensorveiledning

Dette systemet kan brukes til mye forskjellig. Et hvilket som helst eksempel som er godt begrunnet får poeng her. Begrunnelse bør vektes minst 50%.

Viktig observasjon: Det er bare mulig å registrere ett bidrag pr. e-post siden tabellen har e-post som primærnøkkel.

Eksempler:

  • Kommentarsystem: Brukere kan legge igjen én kommentar/tilbakemelding knyttet til sin e-post
  • Enkel blogg: Hver forfatter (identifisert ved e-post) kan ha én bloggpost
  • Tilbakemeldingssystem: Kunder kan gi tilbakemelding, men kun én per e-postadresse
  • Konferansebidrag: Forskere sender inn ett paper per e-post

Dersom intet konkret eksempel er oppgitt, bør ingen poeng gis her.

Oppgave 2 - Filenes roller 12%

Forklar hvilken rolle/hensikt hver av filene i systemet har. Begrunn hvordan du kommer frem til svarene.

Filer i systemet: compose.yaml, Dockerfile, index.html, bidrag.js, bidrag.cgi, bidrag.dtd

✅ Sensorveiledning

Begrunnelse må være med for å få full pott.

compose.yaml

Rolle: Gjør det enkelt å håndtere bygging, oppstart, nedstenging og omstart av systemet.

Begrunnelse: Filnavnet er standard-filnavnet for Docker-compose. Siden intet filnavn er oppgitt i build-kommandoen (kun `.`), leter Docker-compose etter en fil navngitt etter gjeldende standard.

Dockerfile

Rolle: Byggeoppskrift for container-bildet.

Begrunnelse: Standardfilnavn for container-bygging. Ligger i samme katalog som compose.yaml. Instruerer innhenting av html/js/dtd-filer, installerer database, legger til testdata og starter webtjener.

index.html

Rolle: Brukergrensesnitt for datainnsamling.

Begrunnelse: HTML-fil med input-felt (), knapper (

Oppgave 3 - Kjørested 4%

Hvor kjøres (1) bidrag.js og (2) bidrag.cgi? Begrunn svaret ditt.

✅ Sensorveiledning

Begrunnelsen skal telle minst 50%.

bidrag.js kjøres i nettleseren

Begrunnelse:

  • Filen inkluderes i HTML-filen (index.html) og kalles opp derfra
  • Funksjonene som brukes (document.querySelector() og fetch()) er klientside-funksjoner som kun finnes i nettlesere
  • JavaScript inkludert via <script src=""> kjører alltid i nettleseren

bidrag.cgi kjøres av webserveren i containeren

Begrunnelse:

  • Dette er et CGI-program (Common Gateway Interface = standard for kjøring av programmer på webservere)
  • Filen slutter på '.cgi' som indikerer CGI-script
  • Innholdet viser at det er et serverside-script:
    • Skriver ut HTTP-header ("Content-type:...")
    • Bruker CGI-miljøvariabler ($REQUEST_METHOD, $HTTP_CONTENT_LENGTH)
    • Gjør database-operasjoner (sqlite3)
  • Ligger i cgi-bin/-katalogen som er standard for CGI-programmer
Oppgave 4 - Kodebeskrivelse 40%

Gi en detaljert beskrivelse av koden, linje for linje, i følgende filer:

  • Dockerfile
  • index.html
  • bidrag.js
  • bidrag.cgi

Krav: Forklar hva hver linje gjør og hvordan den bidrar til systemets funksjonalitet.

✅ Sensorveiledning - Dockerfile

1. FROM alpine
   - Starter med Alpine Linux (lettvekts distro)
2. RUN apk add busybox-extras libxml2-utils sqlite
   - Installerer pakker (httpd, xmllint, database)
3. COPY bidrag.cgi var/www/cgi-bin/bidrag.cgi
   - Kopierer CGI-script til riktig plassering
4. COPY index.html bidrag.js bidrag.dtd var/www/
   - Kopierer frontend-filer til webroot
6-11. RUN echo "CREATE TABLE..."
   - Oppretter database med 5 kolonner (epost som PK)
13-16. RUN echo "INSERT INTO..."
   - Legger inn 3 testbrukere
18. RUN chmod a+w var/www/bidrag.db
   - Gir skriverettigheter til alle (nødvendig for CGI)
19. EXPOSE 80
   - Deklarerer port 80
20. CMD httpd -p 80 -h /var/www -f -vv
   - Starter webserver

✅ Sensorveiledning - index.html

1. <!doctype html> - HTML5-deklarasjon
2-3. <html><head> - Start dokument og metadata
4. <meta charset="utf-8"> - UTF-8 tegnsett
5. <title> - Sidetittel
6. <script src="bidrag.js"> - Inkluderer JavaScript
7-8. </head><body> - Start body
10-14. <input...> - 5 tekstfelt for brukerinndata
16. <br/> - Linjeskift
18. <button onclick='bidrag("delete")'> - Slett-knapp
19. <button onclick='bidrag("put")'> - Endre-knapp
20. <a href='cgi-bin/bidrag.cgi'> - Liste-lenke (GET)
21-22. </body></html> - Avslutt dokument

✅ Sensorveiledning - bidrag.js

1. function bidrag(funksjon) { - Funksjonsdeklarasjon
3-4. let h1/h2 - XML-deklarasjon og DOCTYPE
6-7. let u = new URL(...) - URL til CGI-script
9-13. let epost = document.querySelector(...) 
   - Henter verdier fra input-felt
15-21. let b = '<bidrag>...' - Bygger XML-string
23-29. fetch(u, {...}) - Sender HTTP-request
   - method: funksjon (put/delete)
   - body: h1+h2+b (komplett XML)
   - headers: Content-Type application/xml

✅ Sensorveiledning - bidrag.cgi

1. #!/bin/sh - Shebang (shell-script)
2. echo "Content-type:text/plain..." - HTTP-header
3. echo - Tom linje (markerer slutt på header)
5. if [ "$REQUEST_METHOD" = "GET" ] - Sjekk GET
6. echo "SELECT * FROM Bidrag" | sqlite3 -line
   - Hent alle bidrag fra database
7. exit - Avslutt hvis GET

9. else - Hvis ikke GET (PUT/DELETE)
10. KR=$(head -c "$HTTP_CONTENT_LENGTH")
   - Les request body
11-15. E=$(...) / P=$(...) osv.
   - Parser XML med xmllint og XPath
   - Henter epost, passord, kommentar, tittel, tekst

18-19. P2=$(echo "SELECT passord...")
   - Henter lagret passord for brukeren
21. if [ "$P" != "$P2" ]; then exit; fi
   - Validerer passord, avslutter hvis feil

25. if [ "$REQUEST_METHOD" = "DELETE" ]
26-28. echo "DELETE FROM Bidrag WHERE epost='$E'"
   - Sletter brukerens bidrag

30. elif [ "$REQUEST_METHOD" = "PUT" ]
31-32. echo "UPDATE Bidrag SET..."
   - Oppdaterer kommentar, tittel og tekst
Oppgave 5 - Autentisering 20%

Gi en vurdering av autentiseringsmekanismen som brukes i systemet.

Foreslå en forbedring. Begrunn svaret.

✅ Sensorveiledning

Autentiseringsmekanismen er ekstremt enkel og meget usikker:

Problemer:

  • Klartekst: Epost og passord sendes ukryptert (ingen HTTPS)
  • Ingen hashing: Passord lagres i klartekst i databasen
  • Ingen validering: E-postadressen valideres ikke
  • Ingen sesjonhåndtering: Brukeren må "logge inn" (sende passord) ved hver endring
  • SQL injection: Ingen sanering av input ($E brukes direkte i SQL)

Forbedringsforslag:

  1. Passordhashing: Lagre bcrypt/argon2-hash i stedet for klartekst
  2. Sesjonshåndtering: Ved vellykket login, opprett sesjonsID som returneres i cookie. Påfølgende requests bruker denne i stedet for passord
  3. HTTPS: Krypter all kommunikasjon
  4. Input-validering: Saner all brukerinput før SQL (prepared statements)
  5. Session timeout: Begrens gyldighetstid på sesjoner
  6. Rate limiting: Begrens antall påloggingsforsøk

Viktigste forbedring: Passordhashing + HTTPS + sesjonshåndtering

Oppgave 6 - Nye poster 20%

Hvordan ville du endret systemet slik at det kun var mulig for autentiserte brukere å legge til nye bidrag/poster i databasen?

La svaret ditt være mest mulig konkret og detaljert.

Observasjon: Systemet implementerer sletting og endring for autentiserte brukere. Opprettelse av nye poster mangler.

✅ Sensorveiledning

Svaret må sørge for at skjemadata som kommer inn, blir oversatt til en SQL-setning med INSERT.

Viktig hensyn:

En bruker kan ikke ha flere bidrag siden e-postadressen er primærnøkkel. For å få full pott må dette addresseres ved å enten:

  1. Beskrive et opplegg for opprettelse av ny bruker + autentisering, eller
  2. Foreslå endring i database-skjemaet slik at nye bidrag kan knyttes til eksisterende brukere

Løsning 1: Ny bruker-registrering

// I index.html:
<button onclick='nyBruker()'>Ny bruker</button>

function nyBruker() {
    epost = document.querySelector('#epost').value;
    passord = document.querySelector('#passord').value;
    
    fetch(new URL('./cgi-bin/bidrag.cgi', base), {
        method: 'post',
        body: buildXML(epost, passord, '', '', ''),
        headers: {'Content-Type': 'application/xml'}
    });
}

// I bidrag.cgi:
elif [ "$REQUEST_METHOD" = "POST" ]; then
    # Sjekk at e-post ikke finnes fra før
    EXISTS=$(echo "SELECT COUNT(*) FROM Bidrag WHERE epost='$E'" | sqlite3 ../bidrag.db)
    
    if [ "$EXISTS" -gt 0 ]; then
        echo '{"error":"E-post finnes allerede"}'
        exit
    fi
    
    # Opprett ny bruker
    echo "INSERT INTO Bidrag (epost,passord,kommentar,tittel,tekst) VALUES ('$E','$P','$K','$T','$X')" | sqlite3 ../bidrag.db
fi

Løsning 2: Endre database-skjema

CREATE TABLE Bruker (
    epost VARCHAR(200) PRIMARY KEY,
    passord VARCHAR(200)
);

CREATE TABLE Bidrag (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    epost VARCHAR(200),
    kommentar VARCHAR(1000),
    tittel VARCHAR(100),
    tekst VARCHAR(1000),
    FOREIGN KEY(epost) REFERENCES Bruker(epost)
);

-- Nå kan én bruker ha flere bidrag

📋 Kodevisning - Bidragssystem

Velg en fil fra listen over for å vise koden...