[PHP]Bestanden uploaden, beveiligen met session voor downen

Pagina: 1
Acties:
  • 143 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • RickvanHaas
  • Registratie: Oktober 2004
  • Laatst online: 15-05-2024
Ik werk aan een systeem waarin leden bestanden kunnen uploaden. Die bestanden horen alleen door die gebruiker zelf bekeken te kunnen worden.

De bestanden worden geupload in een map en met MySQL-tabel houd ik bij wie welk bestand mag zien. De bestanden zelf staan dus niet in de database, maar in een map op de server.

Uiteraard kan niet iedereen zien welke bestanden er in die map staan. Ik geef de namen bovendien een random-code bestaande uit 15 tekens mee, zodat je niet 'toevallig' dat bestand in je adresbalk kan intypen en vervolgens bewonderen.

Toch is dit niet waterdicht, aangezien men in de geschiedenis van een openbare computer o.i.d. kan kijken en zo het bestand alsnog inzien, wat uiteraard niet de bedoeling is?

Mijn vraag: hoe zorg ik ervoor dat ieder lid alleen de door hem geuploade bestanden kan inzien? Het inloggen gebeurt overigens met sessions.

Acties:
  • 0 Henk 'm!

  • TXC
  • Registratie: Oktober 2002
  • Laatst online: 16-09 12:13

TXC

Wat je zou kunnen doen is de bestanden opslaan in een map waar niemand bij kan (beveiligen via maprechten). De bestanden lees je dan op aanvraag met php uit en in de code kun je dan ook controleren of de aanvrager wel rechten heeft.

Even een kleine aanvulling: de bestanden kun je dan lezen met readfile() met de juiste Content-type header.

[ Voor 19% gewijzigd door TXC op 10-02-2007 15:38 ]


Acties:
  • 0 Henk 'm!

  • RickvanHaas
  • Registratie: Oktober 2004
  • Laatst online: 15-05-2024
Probleem is dat ik de map een chomd van 777 moet geven om bestanden te kunnen uploaden. Hoe zorg ik er dan voor dat niet iedereen ze kan downloaden?

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Het is niet zo heel moeilijk, en er zijn genoeg topics hier @ GoT erover. Ik heb het als volgt opgelost:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$location = "path/to/file";
$mime = "mime/type";
$size = "10012347";
$fp = fopen($location, "rb");
header("Content-Type: $mime");
header("Content-Length: $size");

//Voor geforceerd downloaden
header("Content-Disposition: attachment; filename=\"$name\"");
//Plaatjes mogen in browsers, dan deze uitcommenten en de regel 
// hierboven weghalen
#header("Content-Disposition: inline; filename=\"$name\"");

header("Content-Transfer-Encoding: binary\n");
fpassthru($fp);
exit;


Het is dan een kwestie van een mooie url sturen, bijv. http://domain.tld/download/1/image.jpg. Je filtert die 1 eruit, zoekt in de database naar het bestand (locatie, mime etc) en kijkt of de rechten goed zijn. Zo ja -> mijn stuk code :)

Als je je image.jpg dan bijv. op http://domain.tld/media/download/128931287.jpg hebt staan en er nergens naar toe linkt, ben je vrij zeker dat niemand het vind. Natuurlijk kán het wel, maar zolang je nergens een directe url naar de locatie plaatst ben je best veilig.

[ Voor 13% gewijzigd door mithras op 10-02-2007 15:40 ]


Acties:
  • 0 Henk 'm!

  • DJ Buzzz
  • Registratie: December 2000
  • Laatst online: 19-09 08:24
Je kunt prima met PHP functions zoals move_uploaded_file een file ergens neerzetten waar een gebruiken niet zomaar bij kan. Het makkelijkste is om de directory met de bestanden te beveiligen met een .htaccess bestand, zodat niemand erbij kan. Je download script kan dan de rechten controleren en vervolgens het bestand als het doorsturen vanuit die directory naar de user.

Acties:
  • 0 Henk 'm!

  • TXC
  • Registratie: Oktober 2002
  • Laatst online: 16-09 12:13

TXC

Je kunt ze ook eerst naar een temp map uploaden waarna je ze met php verplaatst naar de juiste map. Volgens mij hoef je dan geen 777 rechten op die laatste map te hebben.

Acties:
  • 0 Henk 'm!

  • rogierslag
  • Registratie: Maart 2005
  • Laatst online: 14-10-2024
zet ze buiten de webroot van apache.

Je doet met .htaccess alle verzoeken voor een bestand redirecten
.htaccess
code:
1
2
RewriteEngine On
RewriteRule (.*) download.php?file=$1


download.php
PHP:
1
2
3
4
5
6
7
8
<?php
//sessie controleren. Geen output geven
//Controleren of de gebruiker het bestand mag downloaden
//Het type bestand achterhalen

header("Content-Type" . $strFileType);
include($strFileLocation);
?>


De bestanden laat je dan uploaden naar een directory waar PHP wel kan schrijven, maar waar Apache geen bestanden uit kan serveren (een directory hoger dan de DocumentRoot dus)


edit: ik typ te traag

[ Voor 3% gewijzigd door rogierslag op 10-02-2007 15:42 ]


Acties:
  • 0 Henk 'm!

  • RickvanHaas
  • Registratie: Oktober 2004
  • Laatst online: 15-05-2024
mithras schreef op zaterdag 10 februari 2007 @ 15:38:Als je je image.jpg dan bijv. op http://domain.tld/media/download/128931287.jpg hebt staan en er nergens naar toe linkt, ben je vrij zeker dat niemand het vind. Natuurlijk kán het wel, maar zolang je nergens een directe url naar de locatie plaatst ben je best veilig.
Dat lijkt me toch vrij link, als de url bijvoorbeeld in de History van de browser staat kan ieder bestand zomaar geopend worden. En dat is juist wat ik wil voorkomen.

Acties:
  • 0 Henk 'm!

  • apokalypse
  • Registratie: Augustus 2004
  • Laatst online: 10:21
rogierslag schreef op zaterdag 10 februari 2007 @ 15:41:
zet ze buiten de webroot van apache.

Je doet met .htaccess alle verzoeken voor een bestand redirecten
.htaccess
code:
1
2
RewriteEngine On
RewriteRule (.*) download.php?file=$1


download.php
PHP:
1
2
3
4
5
6
7
8
<?php
//sessie controleren. Geen output geven
//Controleren of de gebruiker het bestand mag downloaden
//Het type bestand achterhalen

header("Content-Type" . $strFileType);
include($strFileLocation);
?>


De bestanden laat je dan uploaden naar een directory waar PHP wel kan schrijven, maar waar Apache geen bestanden uit kan serveren (een directory hoger dan de DocumentRoot dus)


edit: ik typ te traag
dat lijkt mij de beste oplossing :)

Acties:
  • 0 Henk 'm!

  • RickvanHaas
  • Registratie: Oktober 2004
  • Laatst online: 15-05-2024
I'm on it:-)
Het uploaden naar die map lijkt alleen nog niet helemaal te lukken.. Zijn hioer nog speciale instellingen voor nodig?
edit:
Is al gelukt! Nu op naar het downen, thnx!

[ Voor 17% gewijzigd door RickvanHaas op 10-02-2007 16:19 ]


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
RickvanHaas schreef op zaterdag 10 februari 2007 @ 16:04:
[...]
Dat lijkt me toch vrij link, als de url bijvoorbeeld in de History van de browser staat kan ieder bestand zomaar geopend worden. En dat is juist wat ik wil voorkomen.
Nee hoor :)

Als je mijn gehele post leest, zie je dat je deze methode ervoor zorgt dat je _nooit_ de echte locatie van het bestand te zien krijgt. Voorbeeld: hoe zou jij kunnen weten dat deze url het bestand ophaalt van deze plek :?

Test het maar en probeer het bij mij te "kraken" (though ik hoop dat niemand iets sloopt O-) ). Je kan deze url gebruiken om geforceerd te downloaden :)

Acties:
  • 0 Henk 'm!

  • rogierslag
  • Registratie: Maart 2005
  • Laatst online: 14-10-2024
Als je mijn gehele post leest, zie je dat je deze methode ervoor zorgt dat je _nooit_ de echte locatie van het bestand te zien krijgt. Voorbeeld: hoe zou jij kunnen weten dat deze url het bestand ophaalt van deze plek :?
Wat hij bedoelt is dat de url http://juriansluiman.nl/storage/10/nikon_flash_sb600.jpg ergens in een publieke history zou kunnen staan. Omdat jij geen sessie controle hebt zou iedereen het bestand dan alsnog kunnen downloaden, ongeacht wat de echte locatie is.

In mijn voorbeeld vindt er eens een sessie controle plaats, voordat er wordt gedownload.

Verder is het veiliger om het bestand buiten de webroot te plaatsen als je wil dat niemand eraan kan. (denk aan wachtwoorden of creditcardnummers, dat je deze niet wil bekijken via een publieke pc is een tweede). Als een bestand aanwezig is op de server maar de locatie is onbekend, kan iemand die de informatie per sé wil hebben een brute force doen op URL's. Je kan dit allemaal vrij aardig voorkomen met .htaccess ed, maar buiten de webroot plaatsen voorkomt dat een fout in Apache of een fout in jouw config de bestanden blootlegt. Hierdoor heb je al twee mogelijke veiligheidslekken minder.

Acties:
  • 0 Henk 'm!

  • ID-College
  • Registratie: November 2003
  • Laatst online: 21:03
mithras schreef op zaterdag 10 februari 2007 @ 16:13:
[...]

Nee hoor :)

Als je mijn gehele post leest, zie je dat je deze methode ervoor zorgt dat je _nooit_ de echte locatie van het bestand te zien krijgt. Voorbeeld: hoe zou jij kunnen weten dat deze url het bestand ophaalt van deze plek :?

Test het maar en probeer het bij mij te "kraken" (though ik hoop dat niemand iets sloopt O-) ). Je kan deze url gebruiken om geforceerd te downloaden :)
Het gaat ook niet om de "echte" locatie, maar of iemand het kan openen. Waar het staat maakt niet uit.
Als jan de tweede link opent, staat deze in de history. Komt kees op de computer en gaat naar die link dan werkt dat gewoon. En dat wil hij juist niet ;) :)

Acties:
  • 0 Henk 'm!

Verwijderd

Mij niet. Het lijkt mij een ongelofelijk stomme oplossing. Het lijkt mij namelijk een goed plan om een PHP bestand te uploaden, die dan vervolgens bij het opvragen geïncluded wordt. |:(

De bestanden hoeven ook helemaal niet per se buiten de webroot, zolan je Apache maar zo configureert dat hij die bestanden niet serveert.
TXC schreef op zaterdag 10 februari 2007 @ 15:40:
Je kunt ze ook eerst naar een temp map uploaden waarna je ze met php verplaatst naar de juiste map. Volgens mij hoef je dan geen 777 rechten op die laatste map te hebben.
Het uploaden gebeurt normaal gesproken al in een andere directory, vaak de /tmp directory. Of de doeldirectory die 777 rechten moet hebben ligt aan de eigenaar. Welke rechten er ook ingesteld zijn, de gebruiker waaronder de server draait moet er schrijfrechten hebben. Dat zou ook best 775 of 755 of 770 of 700 kunnen zijn.
--
En verder is het natuurlijk een kwestie van mensen uit laten loggen zodra ze klaar zijn, of een wachtwoord te laten ingeven als er een bepaalde tijd verstreken is, of bij elke belangrijke request.
Sessies zijn er voor gebruikersgemak, niet voor extra beveiliging.

Acties:
  • 0 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
rogierslag schreef op zaterdag 10 februari 2007 @ 15:41:
download.php
PHP:
1
2
3
4
5
6
7
8
<?php
//sessie controleren. Geen output geven
//Controleren of de gebruiker het bestand mag downloaden
//Het type bestand achterhalen

header("Content-Type" . $strFileType);
include($strFileLocation);
?>
Gebruik geen include, maar readfile. Include is hier helemaal niet voor bedoeld, en brengt ook een groot risico met zich mee.

Acties:
  • 0 Henk 'm!

  • rogierslag
  • Registratie: Maart 2005
  • Laatst online: 14-10-2024
Verwijderd schreef op zaterdag 10 februari 2007 @ 19:36:
[...]

Mij niet. Het lijkt mij een ongelofelijk stomme oplossing. Het lijkt mij namelijk een goed plan om een PHP bestand te uploaden, die dan vervolgens bij het opvragen geïncluded wordt. |:(
Hier had ik helemaal niet aangedacht. Ik heb net dat stukje zo even neergetypt zonder er diep over na te denken. Damned, dat was wel een gigantisch risico geweest, vooral omdat je waarschijnlijk een open database verbinding had gehad!

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
rogierslag schreef op zaterdag 10 februari 2007 @ 19:24:
[...]

Wat hij bedoelt is dat de url http://juriansluiman.nl/storage/10/nikon_flash_sb600.jpg ergens in een publieke history zou kunnen staan. Omdat jij geen sessie controle hebt zou iedereen het bestand dan alsnog kunnen downloaden, ongeacht wat de echte locatie is.
ID-College schreef op zaterdag 10 februari 2007 @ 19:30:
[...]

Het gaat ook niet om de "echte" locatie, maar of iemand het kan openen. Waar het staat maakt niet uit.
Als jan de tweede link opent, staat deze in de history. Komt kees op de computer en gaat naar die link dan werkt dat gewoon. En dat wil hij juist niet ;) :)
Kennelijk zijn jullie grondig lezen verleerd. Als je _goed_ had gelezen, had je gezien dat ik het ook zo oplos:
mithras schreef op zaterdag 10 februari 2007 @ 15:38:
Het is dan een kwestie van een mooie url sturen, bijv. http://domain.tld/download/1/image.jpg. Je filtert die 1 eruit, zoekt in de database naar het bestand (locatie, mime etc) en kijkt of de rechten goed zijn. Zo ja -> mijn stuk code :)
Verder is de stap sessie ok -> aanbieden. Sessie niet ok -> niet aanbieden nou niet de meest moeilijke vraag, aangezien elke php noob dat kan programmeren. Dat het hele sessie gebeuren niet relevant is, is aangezien de TS dat al had vermeld (en ik neem aan dat het gewoon werkt):
RickvanHaas schreef op zaterdag 10 februari 2007 @ 15:32:
Het inloggen gebeurt overigens met sessions.
Geef ik je nog een uitdaging: wat is de echte locatie van dit bestand, wat echt een plaatje is, namelijk de verkleinde versie van deze ;)


rogierslag schreef op zaterdag 10 februari 2007 @ 19:24:
[...]
Verder is het veiliger om het bestand buiten de webroot te plaatsen als je wil dat niemand eraan kan. (denk aan wachtwoorden of creditcardnummers, dat je deze niet wil bekijken via een publieke pc is een tweede). Als een bestand aanwezig is op de server maar de locatie is onbekend, kan iemand die de informatie per sé wil hebben een brute force doen op URL's. Je kan dit allemaal vrij aardig voorkomen met .htaccess ed, maar buiten de webroot plaatsen voorkomt dat een fout in Apache of een fout in jouw config de bestanden blootlegt. Hierdoor heb je al twee mogelijke veiligheidslekken minder.
Als jij een .htaccess plaatst en die een beetje zorgvuldig chmod, ben je knap als je 1-2-3 het bestand te pakken krijgt. Als je om de .htaccess heen bent is het komen buiten de webroot volgens mij ook niet zo'n probleem.

Daarnaast -maar dat was al gemeld- is die include _helemaal_ niet zo handig ;)

[ Voor 4% gewijzigd door mithras op 10-02-2007 23:28 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Waarom maak je binnen de filestore map, geen mappen aan per gebruiker, deze mappen geef je dusdanig rechten dat alleen de server lees/schrijf toegang heeft. Vervolgens gebruik je een van de eerder voorgestelde oplossingen om de rechtencheck te doen en indien gerechtvaardigd de beschikbare content aan te doen? Eventueel als forced-download, zodat je geen beveiligingsproblemen hebt als er bijvoorbeeld php geupload wordt.
Pagina: 1