Sulaiman Bil Service

Ingen demoGitHub Repo
2024 · Fullstack webapp · Studentprosjekt · USN
Skjermbilde av Sulaiman Bil Service

Booking-system for et ekte bilverksted bygget i team av fire. Min del var hele admin-panelet.

Sulaiman Bil Service er et lite bilverksted i Hønefoss som tok bookinger på telefon. Vi bygde en nettside med booking og admin-panel slik at de kunne ta bestillinger uten å løfte røret.

Problem

Sulaiman Bil Service er et bilverksted som tok bestillinger på telefon. Det betydde ingen logg over hvem som hadde booket hva, ingen oversikt for verkstedet, og av og til at samme tidspunkt ble lovet bort to ganger. Eieren ville ha noe på nett.

Løsning

Fire av oss bygde systemet som bachelor (BOP3000, USN, 2024). Stacken er PHP, MySQL og Bootstrap, med Flatpickr for kalenderen. Databasen administrerte vi gjennom phpMyAdmin. Der laget jeg tabellene, satt opp ENUM for service-typer, og brukte exportfunksjonen til å hente ut ledige tider som JSON som booking-kalenderen leser. Helger er sperret og åpningstid starter 06:00.

Booking-flyten og kontaktskjemaet bygde de andre på teamet. Min del var hele admin-panelet, altså mappen admin/: innlogging, registrering, dashboard, og full CRUD på bestillinger.

Admin-dashboard logget inn som Deqa, med tre snarveier til bestillinger

Adminen logger inn, ser alle bestillinger i en tabell, kan redigere eller slette dem. Hver side i admin-mappen starter med en sjekk på om sessionen finnes, ellers blir man kastet tilbake til login. Greit nok, men det forutsetter at sessionen i seg selv er trygg. Mer om det lenger ned.

Beslutninger og refleksjon

Beslutninger jeg tok

Login og register i samme fil med tabs. Jeg ville ikke ha to nesten-identiske sider. Løsningen ble en parameter i URL-en (?mode=login eller ?mode=register), og samme fil rendrer riktig skjema basert på det. Jeg whitelistet verdien på toppen, så hvis noen tukler med URL-en faller den tilbake til login. Admin er én bruker som vet hvor knappene er, og færre filer gjør vedlikehold enklere.

Login-tab i tabbed UI med e-post og passord

Register-tab med brukernavn, e-post, passord og bekreft passord

bcrypt over enklere hashing. Brukerne her er admin-kontoer, så det er ikke et stort angrepsmål. Men MD5 og SHA1 er knekt for passord, og det er ingen grunn til å ta snarveier på lagring. PHP har password_hash og password_verify innebygd, og da slipper jeg å håndtere salt manuelt.

CSRF-token på sletting. Sletting er den mest destruktive operasjonen i panelet. Hvis admin er logget inn og åpner en fiendtlig side i en annen fane, kan den siden i prinsippet sende en POST til min slett-endpoint og fjerne en bestilling uten at admin merker det. Løsningen var et tilfeldig token lagret i sessionen, lagt inn som skjult felt i hver slett-form, og sammenlignet på serversiden før slettingen kjører. Sammenligningen gjøres med en funksjon som tar like lang tid uansett hvor lik gjettingen er, så ingen kan gjette tokenet tegn for tegn ved å måle responstid. Strengt tatt mer enn et bachelorprosjekt trenger. Jeg ville bare lære det riktige mønsteret.

Sletteflyten med tabell over seks bestillinger og rød Slett-knapp på hver rad

Prepared statements på alle queries. Parametriserte SQL-spørringer, der verdier sendes separat fra spørringen og dermed ikke kan tolkes som kode. Da forsvinner SQL-injection som angrepsflate. Litt mer kode per spørring, men det går raskt inn i hånden.

Eget mørkt stylesheet (admin.css). Jeg startet med å gjenbruke kundesidens lyse Bootstrap-tema, men admin-tabellene har mange rader og kolonner med små data-celler. Etter ti minutter var det slitsomt for øynene. Admin fikk derfor sitt eget mørke stylesheet, og de to delene av siden henvender seg uansett til helt ulike brukere.

Bestillingsliste med seks realistiske kunder, mørkt tema og Rediger og Slett per rad

Hva jeg lærte

CSRF-tokenet havnet på delete fordi det var den synlige risikoen jeg tenkte på først. Sletting føles farlig, edit føles trygt. Men edit endrer også state. Hvis noen klarer å lure adminen til å sende en POST, kan de like gjerne overskrive en bestilling som å slette den. I dag ville jeg satt CSRF på alle endepunkter som endrer noe i databasen, ikke bare delete.

Sessionen er den andre tingen. Jeg sjekker at admin er logget inn på hver side, men jeg regenererer aldri session-ID etter innlogging, og det finnes ingen timeout. Det betyr at hvis noen klarer å plante en session-ID i nettleseren før admin logger inn, er den IDen fortsatt gyldig etterpå. Burde vært en regenerering rett etter at passordet er verifisert. Det er to linjer kode jeg glemte.

Arkitekturen er det største. Vi delte koden i tre parallelle PHP-moduler (admin/, kontaktskjema/, hovedside/) med hver sin config.php, pluss en til på rot-nivå. Det er fire steder de samme databaseinnstillingene ligger. Endrer du DB-passord, må du huske alle fire. Én kodebase med en router og en PSR-4-autoloader hadde løst det. Konfigen burde også ha ligget i miljøvariabler, ikke i en fil per mappe. Ikke pent, men appen kjører.

Technology Stack

  • Frontend:HTML, CSS, JavaScript, Bootstrap, Flatpickr
  • Backend:PHP
  • Database:MySQL, phpMyAdmin
  • Sikkerhet:bcrypt, CSRF-token, prepared statements
  • Verktøy:Git, Scrum

Key Features

  • Online booking

    Kunder booker service direkte på nett uten å ringe. Helger er sperret og åpningstid starter 06:00.

  • Admin-panel med full CRUD

    Innlogging, registrering, dashboard og full redigering eller sletting av bestillinger.

  • CSRF-beskyttet sletting

    Tilfeldig token i sessionen sammenlignes på serversiden før destruktive operasjoner kjører.

Andre prosjekter