Brugernavn:




Kodeord: Husk
Forside Forum Artikler Downloads Søg
 

Sikkerhed - Upload

Forord

Sikkerheden er aldrig noget du bør sløse med når du udvikler i PHP. Og det er isært farligt at sløse på sikkerheden ved de smarte og kendte fil uploads løsninger. Læs denne artikel og ungå at blive et offer for hacking.

Indholdsfortegnelse

1.0   Indledning
2.0   Hvad er problemet?
   2.1   Hvorfor er de usikre?
3.0   Et simpelt upload system
   3.1   Hvad er problemet her?
   3.2   Hvad gør vi ved problemet?
      3.2.1   getimagesize() hvad er det?
4.0   Implantering af getimagesize()
   4.1   Er der nogle problemer ved denne metode?
5.0   Den færdige løsning.
6.0   Ekstra sikkerhed
   6.1   Slå PHP helt fra i mappen
7.0   Hvad har vi så lært?

1.0  Indledning

Vi kender alle de små smarte upload systemer. De lader os ligge filer op på vores webserver nemt og hurtigt, uden om FTP og andet bøvl. De er også smarte til CMS systemer hvor evt ansatte ville kunne uploade billeder til webserveren direkte fra et webinterface.
Selvom det hele lyder så praktisk og perfekt, så er der en bagside af det hele som de færreste er opmærksom på... et usikkert upload system VIL kunne lade ALLE OG ENHVER tage kontrollen over din webserver, hvorefter de ville kunne gøre alt hvad der passer dem med den.

2.0  Hvad er problemet?

Problemet er at folk typisk laver søgningen på google efter "php fil upload", det er der i selv ikke noget galt i men de fleste aner ikke hvilken sikkerheds risiko mere end halvdelen af alle de scripts man finder er.

2.1  Hvorfor er de usikre?

De fleste af disse systemer har INGEN indbyggede metoder imod at alle og enhver ville kunne uploade på din webserver. Derudover er det værste af det hele at de IKKE udføre tjek på hvad brugeren rent faktisk er i gang med at uploade til serveren. Faktisk ville en hacker kunne ved hjælp af at uploade et PHP shell (Kendte shells er C99 og R57) kunne downloade, slette eller modificere hele dit website efter eget ønske. På særligt usikre webservere ville hackeren direkte kunne overtage den! Det er derfor ekstremt vigtigt som med alle andre PHP scripts ikke at sløse med sikkerheden.

3.0  Et simpelt upload system

  1. <?
  2. if ($_GET['add'] == 'yes') {
  3.     $max = "1000"; // Maks størrelse i KB
  4.     if($_FILES["upfil"]["size"] > 0) {
  5.         $rand = rand(100000,999999);
  6.         $fra = $_FILES["upfil"]["tmp_name"];
  7.         $til = "../upload/" . $_FILES["upfil"]["name"];
  8.         $fil_stoerrelse = filesize($fra)/1024;
  9.         if($fil_stoerrelse > $max) {
  10.             die("Desværre - dit billede er for stort!<br>Billedet må maks fylde " . $konfiguration["max_stoerrelse"] . " kb, og din fil fylder " . ceil($fil_stoerrelse) . " kb");
  11.         }
  12.         copy($fra, $til);
  13.         echo "Billedet er nu tilføjet! Linket til billedet er: $dir";
  14.     } else {
  15.         echo "Du har ikke valgt et billede";
  16.     }
  17. } else {
  18.     ?>
  19.     <form action="?add=yes" method="post" enctype="multipart/form-data">
  20.     <table border="0" cellpadding="2" cellspacing="0" style="width: 100%;">
  21.     <tr>
  22.     <td width="35%"><b>Billede:</b><br/><em>Vælg et billede fra din computer (Max 1MB)</em></td>
  23.     <td width="65%"><input type="file" name="upfil" style="width: 99%;" /></td>
  24.     </tr>
  25.     </table>
  26.     <input type="submit" name="submit" value="Upload!" style="width: 99%;" />
  27.     </form>
  28.     <?
  29. }
  30. ?>
Dette er et eksempel på et meget nemt og simpelt upload system. Systemet har en HTML formular som lader os vælge det billede vi vil uploade. Systemet kan også tjekke fil størrelsen så vi slipper for kæmpe filer (.bmp anyone?).

3.1  Hvad er problemet her?

Det ser jo alt sammen meget fint ud. Systemet kan bruges til at udvælge en billede på ens computer, uploade det til webserveren og derefter gemme det så faldt at filen overholder fil størrelses grænsen.
Problemet her ligger i at vi ikke tjekker hvad brugeren rent faktisk uploader til webserveren. Det kunne være alt fra et billede til et ondsindet PHP script!

3.2  Hvad gør vi ved problemet?

For at neutralisere dette problem bliver vi nød til at tjekke efter hvad det er som brugeren har uploadet. Dette kan gøres via PHP funktionen getimagesize().

3.2.1  getimagesize() hvad er det?

Denne simple funktion kan udtrække en fils mime type. I dette tilfælde bruger vi funktionen til at udtrække mime type'n på den uploadede fil.
Læs evt mere omkring denne funktion i manualen på php.net: her
Du kan derudover også finde en samling over kendte mime typer på W3schools: her

4.0  Implantering af getimagesize()

Da vi kun ønsker at der kan uploades .png .jpg og .gif billeder så vil vi tjekke efter deres mime typer.
Her er et eksempel på hvor simpelt det vil være at implantere dette:
  1. $imageinfo = getimagesize($_FILES['upfil']['tmp_name']);
  2.     if ($imageinfo['mime'] == 'image/gif' or $imageinfo['mime'] == 'image/jpeg' or $imageinfo['mime'] == 'image/png') {
  3. //Upload gemme del her.
  4. } else {
  5.     echo "Dit billede skal være jpg png eller gif!";
  6. }

4.1  Er der nogle problemer ved denne metode?

Der er et enkelt problem her. Og der er at det er muligt at snyde denne metode! Dette kan gøres via et meget listigt trick. Tricket går ud på at filer kan have mere to dots!
Dette kan for eksempel være ondsindetfil.php.gif. Det er måske ikke noget problem på nogle webservere, men for andre usikre webservere (Ja jeg kigger på jer one, surftown, gigahost, servage og andre!) ser .php delen FØRST og ignorere derefter .gif delen. Denne fil ville kunne uploades uden problemer igennem overståene løsning! Derefter vil vi lave et meget simpelt lille tjek imod dette og modificere vores fil tjek.
  1. $imageinfo = getimagesize($_FILES['upfil']['tmp_name']);
  2.     if (($imageinfo['mime'] == 'image/gif' or $imageinfo['mime'] == 'image/jpeg' or $imageinfo['mime'] == 'image/png') and !eregi('.php', $_FILES['upfil']['tmp_name'])) {
  3. //Upload gemme del her.
  4. } else {
  5.     echo "Dit billede skal være jpg png eller gif!";
  6. }
Som du kan se så har vi nu en if sætning som siger:
Hvis at filens mime type enten er: image/gif, image/jpeg eller image/png OG at der ikke findes .php i filens navn så kan der forsættes.

5.0  Den færdige løsning.

  1. <?
  2. if ($_GET['add'] == 'yes') {
  3.     $max = "1000"; // Maks størrelse i KB
  4.     if($_FILES["upfil"]["size"] > 0) {
  5.         $rand = rand(100000,999999);
  6.         $fra = $_FILES["upfil"]["tmp_name"];
  7.         $til = "../upload/" . $_FILES["upfil"]["name"];
  8.         $fil_stoerrelse = filesize($fra)/1024;
  9.         if($fil_stoerrelse > $max) {
  10.             die("Desværre - dit billede er for stort!<br>Billedet må maks fylde " . $konfiguration["max_stoerrelse"] . " kb, og din fil fylder " . ceil($fil_stoerrelse) . " kb");
  11.         }
  12.         $imageinfo = getimagesize($_FILES['upfil']['tmp_name']);
  13.         if (($imageinfo['mime'] == 'image/gif' or $imageinfo['mime'] == 'image/jpeg' or $imageinfo['mime'] == 'image/png') and !eregi('.php', $_FILES['upfil']['tmp_name'])) {
  14.             copy($fra, $til);
  15.             echo "Billedet er nu tilføjet! Linket til billedet er: $dir";
  16.         } else {
  17.             echo "Dit billede skal være jpg png eller gif!";
  18.         }
  19.     } else {
  20.         echo "Du har ikke valgt et billede";
  21.     }
  22. } else {
  23.     ?>
  24.     <form action="?add=yes" method="post" enctype="multipart/form-data">
  25.     <table border="0" cellpadding="2" cellspacing="0" style="width: 100%;">
  26.     <tr>
  27.     <td width="35%"><b>Billede:</b><br/><em>Vælg et billede fra din computer (Max 1MB)</em></td>
  28.     <td width="65%"><input type="file" name="upfil" style="width: 99%;" /></td>
  29.     </tr>
  30.     </table>
  31.     <input type="submit" name="submit" value="Upload!" style="width: 99%;" />
  32.     </form>
  33.     <?
  34. }
  35. ?>
Dette er så vores meget simple sikre upload system.

6.0  Ekstra sikkerhed

Man kan aldrig få for meget sikkerhed!
Først og fremmest ville det være klogt at gemme upload siden bag et login system som sikre at det kun er dig og andre med tilladelse ville kunne uploade.

6.1  Slå PHP helt fra i mappen

Selvom vi sikre os at vi ikke får uploadet nogle PHP scripts så kan vi ikke afvise at der ville være andre metoder til at få sneget den onde fil ind på vores server. Derfor laver vi i vores mappe som indeholder vores filer en .htaccess fil og indsætter følgene i toppen af den:
  • php_flag engine off
Dette fortæller apache at den ikke skal benytte PHP i pågældene mappe.

7.0  Hvad har vi så lært?

Vi har lært at det at efterlade et usikret upload system kan føre til overtagelse af din webserver.
Vi er lært at beskytte os imod disse angreb og effektivt ungå dem.
Vi har også lært hvor vigtigt det er altid at have styr på vores sikkerhed og aldrig at sløse med den.
Sidst redigeret 12:50 14/01/2010
Oprettet af:

PHP

Point modtaget: 499

Rating: 4.1
09:24 14/01/2010

Kommentarer

Giv din mening tilkende om denne artikel, eller læs andres.
Har du spørgsmål eller brug for hjælp til denne artikel henvises du til forummet.
Mange tak! Jeg stod netop og skulle i gang med noget upload og jeg var MEGET i tvivl om hvordan jeg kunne sikre det - så TAK!

Men jeg altså lige et spørgsmål. I mit upload script skal der kunne uploades doc dokumenter osv. - er der et sted, hvor man kan se en samlet oversigt over sådan nogenlunde normale filtyper?
Oprettet af:
  Mail
12:29 14/01/2010
Sådan Emil har lige smidt et link til det ind i artiklen :P
Oprettet af:
  Mail
12:50 14/01/2010
Mange tak!
Oprettet af:
  Mail
13:47 14/01/2010
Virkelig god artikel :)
Skal helt klart have lavet nogle .htaccess filer i mine mapper hvor der oploades, tak for artikelen.

5/5 :)
Oprettet af:
  Mail
16:25 14/01/2010
Fint artikel, 5/5.
Og skriver ud efter egne oplevelser ^^
Oprettet af:
  Mail
21:21 14/01/2010
Jeg får fejlen at billedet skal være jpg, gif eller png, selvom det er en af de tre billeder jeg uplaoder ??

og jeg synes du mangler at fortælle om denne sætning:

  1. $imageinfo['mime'] == 'image/gif'

altså hvad mime er
og hvorfor du skriver image/gif osv. ?
men ellers en super god artikel. like it..
Oprettet af:
  Mail
23:06 14/01/2010
Der er fejl hist og pist i artiklen, men altså hvis man tager den med et gran salt, og så bare tænker lidt over, at man skal tjekke hvilken en filtype det er, så er man da lidt bedre sikret.
Oprettet af:
  Mail
15:16 17/01/2010
Nikolaj man skal aldrig være "Lidt bedre sikret" men "HELT SIKRET". Se det sådan her. Dine systemer er små dine døre i dit hus. Hvis dine døre ikke er sikre så bryder tyvene ind.
Oprettet af:
  Mail
13:10 22/01/2010
Du kan aldrig være helt sikker - bare lige for at få det med.
Oprettet af:
  Mail
20:00 24/01/2010
- og hvis tyvene vil ind - så kommer de ind - og det er det samme med crackere og hackere :)..
Oprettet af:
  Mail
21:56 24/01/2010
Du skal være oprettet og logget ind for at kommentere en artikel
Copyright © Rowl.dk v/ Michael Raagaard | 2005-10 | Alle rettigheder forbeholdes