PDA

Bekijk Volledige Versie : [PHP/MySQL] bestanden via database beveiligen



Branko Collin
12/11/03, 16:45
Ongetwijfeld is deze vraag al eens gesteld, maar ik kan de juiste
sleutelwoorden niet vinden, dus verwijs me ten antwoord gerust naar de
juiste draad in Google Groups.

Hoe geeft ik gebruikers toegang tot grote bestanden die voor andere
gebruikers moeten zijn afgeschermd?

Het probleem wat zich voordoet is dat ik op een al gedeeltelijk gebouwde
applicatie moet voortbouwen.

De site is op PHP/MySQL gebaseerd, waarbij gebruikers verschillende
toegangsniveau's hebben. De site geeft toegang tot grote bestanden (we
spreken over tientallen megabytes per bestand), maar zal niet
noodzakelijkerwijs tegelijkertijd veel gebruikers hebben.

De authenticering wordt via de database en PHP-sessies afgehandeld: in de
database staan de inloggegevens, en als die overeenkomen met wat de
gebruiker opgeeft, wordt een sessie aangemaakt. Gebruikers behoren niet
alleen tot een bepaald niveau (bezoeker, gebruiker, beheerder,
sitebeheerder), maar hebben in sommige gevallen ook voor bepaalde duur
toegang tot de site, en daarna niet meer. Gebruikers van een hoger nivueau
hebben over het algemeen toegang tot een grotere verzameling bestanden, en
meer mogelijkheden die bestanden te manipuleren.

Als ik de bestanden in normale mappen binnen de documentroot zou zetten,
zou iedereen die de naam van de map en de bestanden kan raden, bij de
bestanden kunnen. Dat wil ik niet.

De verschillende methoden die ik via Google heb gevonden of zelf heb
bedacht, om alleen de juiste gebruiker toegang te geven tot een bepaald
bestand, hebben allemaal hun nadelen:

- Ik laat PHP via fread() of fpassthrough() het bestand oplepelen. Dat
heeft het grote voordeel dat authenticering puur via de sessie gaat, maar
het nadeel dat je met intelligente buffering moet gaan werken (PHP
reserveert voor een bestand van 50 MB gerust 50 MB geheugenruimte, en
hardware schaalt over het algemeen niet zo lekker), en dat er een extra
schakel in het proces zit die de boel mogelijk vertraagt.

- Ik maak tijdelijke (voor de duur van de sessie) map- en bestandsnamen aan
en m.b.v. mod_rewrite laat ik die nepnamen verwijzen naar de echte namen.

- Ik laat de PHP-code .htaccess- en .htpasswd-bestanden aanpassen. Schakel
ik daarmee dan niet echter een tweede laag van authenticering in? Is er een
manier om Apache naar de sessies van PHP te laten kijken?

Zijn er andere methoden?

Uiteraard is HTTP niet echt een geschikt protocol voor het versturen van
grote bestanden. Ik heb al FTP voorgesteld, maar dat was niet de bedoeling;
de applicatie moet er zo 'gebruiksvriendelijk' mogelijk uitzien, en
blijkbaar betekent dat, dat het een webapplicatie moet worden.

--
Branko Collin
if you reply by e-mail, please change invalid to nl and z to s
(but replies to the newsgroup are preferred)

Daniel Tryba
12/11/03, 18:00
Branko Collin <branko@mixedflavourz.invalid> wrote:
> - Ik laat PHP via fread() of fpassthrough() het bestand oplepelen. Dat
> heeft het grote voordeel dat authenticering puur via de sessie gaat, maar
> het nadeel dat je met intelligente buffering moet gaan werken (PHP
> reserveert voor een bestand van 50 MB gerust 50 MB geheugenruimte, en
> hardware schaalt over het algemeen niet zo lekker), en dat er een extra
> schakel in het proces zit die de boel mogelijk vertraagt.

??? fpassthru schrijft direct naar de output, dus tenzij je zelf aan het
OB-en bent is er geen probleem. Als alternatief kan je dan naturlijk
feof()/fgets($fp,4096) icm met flush() gebruiken om de buffers van PHP te
flushen (naar het buffer van je httpd indien aanwezig).

--

Daniel Tryba

Branko Collin
12/11/03, 18:15
Daniel Tryba wrote:
> Branko Collin <branko@mixedflavourz.invalid> wrote:

>> - Ik laat PHP via fread() of fpassthrough() het bestand oplepelen.
>> Dat heeft het grote voordeel dat authenticering puur via de sessie
>> gaat, maar het nadeel dat je met intelligente buffering moet gaan
>> werken (PHP reserveert voor een bestand van 50 MB gerust 50 MB
>> geheugenruimte, en hardware schaalt over het algemeen niet zo
>> lekker), en dat er een extra schakel in het proces zit die de boel
>> mogelijk vertraagt.
>
> ??? fpassthru schrijft direct naar de output, dus tenzij je zelf aan
> het OB-en bent is er geen probleem. Als alternatief kan je dan
> naturlijk feof()/fgets($fp,4096) icm met flush() gebruiken om de
> buffers van PHP te flushen (naar het buffer van je httpd indien
> aanwezig).

Volgens commentaar in de PHP-documentatie reserveert PHP de bestandsgrootte
aan geheugenruimte bij fpassthru().

Ik ben ook een beetje ongerust dat het systeem trager wordt, omdat PHP iets
met het bestand doet, maar ik neem aan dat dat wel mee zal vallen, omdat
het traject van bestandssysteem naar webserver veel sneller zal zijn dan
van webserver naar client, toch?

Daniel Tryba
12/11/03, 22:45
Branko Collin <branko@mixedflavourz.invalid> wrote:
>> ??? fpassthru schrijft direct naar de output, dus tenzij je zelf aan
>> het OB-en bent is er geen probleem. Als alternatief kan je dan
>> naturlijk feof()/fgets($fp,4096) icm met flush() gebruiken om de
>> buffers van PHP te flushen (naar het buffer van je httpd indien
>> aanwezig).
>
> Volgens commentaar in de PHP-documentatie reserveert PHP de bestandsgrootte
> aan geheugenruimte bij fpassthru().

Ik geloof er helemaal niets van, tenzij er dus een outputbuffer is. Maar
ik heb geen servers met memory limits dus je zal het zelf moeten testen.

> Ik ben ook een beetje ongerust dat het systeem trager wordt, omdat PHP iets
> met het bestand doet, maar ik neem aan dat dat wel mee zal vallen, omdat
> het traject van bestandssysteem naar webserver veel sneller zal zijn dan
> van webserver naar client, toch?

Als je het goed doet, doet PHP niets anders dan het lezen van de file en
naar de outptu sturen, er is dus enige overhead.

--

Daniel Tryba

Marcus
12/11/03, 23:45
Branko Collin wrote:
>
> Ongetwijfeld is deze vraag al eens gesteld, maar ik kan de juiste
> sleutelwoorden niet vinden, dus verwijs me ten antwoord gerust naar de
> juiste draad in Google Groups.
>
> Hoe geeft ik gebruikers toegang tot grote bestanden die voor andere
> gebruikers moeten zijn afgeschermd?
>
> Het probleem wat zich voordoet is dat ik op een al gedeeltelijk gebouwde
> applicatie moet voortbouwen.
>
> De site is op PHP/MySQL gebaseerd, waarbij gebruikers verschillende
> toegangsniveau's hebben. De site geeft toegang tot grote bestanden (we
> spreken over tientallen megabytes per bestand), maar zal niet
> noodzakelijkerwijs tegelijkertijd veel gebruikers hebben.
>
> De authenticering wordt via de database en PHP-sessies afgehandeld: in de
> database staan de inloggegevens, en als die overeenkomen met wat de
> gebruiker opgeeft, wordt een sessie aangemaakt. Gebruikers behoren niet
> alleen tot een bepaald niveau (bezoeker, gebruiker, beheerder,
> sitebeheerder), maar hebben in sommige gevallen ook voor bepaalde duur
> toegang tot de site, en daarna niet meer. Gebruikers van een hoger nivueau
> hebben over het algemeen toegang tot een grotere verzameling bestanden, en
> meer mogelijkheden die bestanden te manipuleren.
>
> Als ik de bestanden in normale mappen binnen de documentroot zou zetten,
> zou iedereen die de naam van de map en de bestanden kan raden, bij de
> bestanden kunnen. Dat wil ik niet.
>
> De verschillende methoden die ik via Google heb gevonden of zelf heb
> bedacht, om alleen de juiste gebruiker toegang te geven tot een bepaald
> bestand, hebben allemaal hun nadelen:
>
> - Ik laat PHP via fread() of fpassthrough() het bestand oplepelen. Dat
> heeft het grote voordeel dat authenticering puur via de sessie gaat, maar
> het nadeel dat je met intelligente buffering moet gaan werken (PHP
> reserveert voor een bestand van 50 MB gerust 50 MB geheugenruimte, en
> hardware schaalt over het algemeen niet zo lekker), en dat er een extra
> schakel in het proces zit die de boel mogelijk vertraagt.
>
> - Ik maak tijdelijke (voor de duur van de sessie) map- en bestandsnamen aan
> en m.b.v. mod_rewrite laat ik die nepnamen verwijzen naar de echte namen.
>
> - Ik laat de PHP-code .htaccess- en .htpasswd-bestanden aanpassen. Schakel
> ik daarmee dan niet echter een tweede laag van authenticering in? Is er een
> manier om Apache naar de sessies van PHP te laten kijken?

Mijn ervaring is dat methode 2 de meest gebruikte is (bij webmail en zo).

> Uiteraard is HTTP niet echt een geschikt protocol voor het versturen van
> grote bestanden. Ik heb al FTP voorgesteld, maar dat was niet de bedoeling;
> de applicatie moet er zo 'gebruiksvriendelijk' mogelijk uitzien, en
> blijkbaar betekent dat, dat het een webapplicatie moet worden.

Je zou eventueel nog kunnen kijken naar bittorrent, waarbij als er
weinig wordt gedownload je altijd zelf moet seeden. Deze techniek is
vooral interessant als je weinig bandbreedte hebt, maar erg veel
downloads verwacht. Het neemt namelijk vrijwel geen bandbreedte, maar
maakt gebruik van de upload van de downloader.

Mark

Daniel Tryba
13/11/03, 00:15
Marcus <mark@ijbema.xs4all.nl.invalid> wrote:
[knip 34 regels over de wensen van filedownloads met authenticatie]
>> - Ik laat PHP via fread() of fpassthrough() het bestand oplepelen. Dat
[knip]
>> - Ik maak tijdelijke (voor de duur van de sessie) map- en bestandsnamen aan
>> en m.b.v. mod_rewrite laat ik die nepnamen verwijzen naar de echte namen.
>>
>> - Ik laat de PHP-code .htaccess- en .htpasswd-bestanden aanpassen. Schakel
>> ik daarmee dan niet echter een tweede laag van authenticering in? Is er een
>> manier om Apache naar de sessies van PHP te laten kijken?
>
> Mijn ervaring is dat methode 2 de meest gebruikte is (bij webmail en zo).

Probleem is dat dat voor geen meter schaalt.

[bittorent als alternatief]
En hoe zit het dan met de door de OP gewenste authenticatie?

BTW je mag knippen en samenvatten in een posting. Dat is zeker handig
als je er toch niets mee doet.

--

Daniel Tryba

Marcus
13/11/03, 08:15
Daniel Tryba wrote:
> Marcus <mark@ijbema.xs4all.nl.invalid> wrote:
> [knip 34 regels over de wensen van filedownloads met authenticatie]
>>> - Ik laat PHP via fread() of fpassthrough() het bestand oplepelen. Dat
> [knip]
>>> - Ik maak tijdelijke (voor de duur van de sessie) map- en bestandsnamen aan
>>> en m.b.v. mod_rewrite laat ik die nepnamen verwijzen naar de echte namen.
>>>
>>> - Ik laat de PHP-code .htaccess- en .htpasswd-bestanden aanpassen. Schakel
>>> ik daarmee dan niet echter een tweede laag van authenticering in? Is er een
>>> manier om Apache naar de sessies van PHP te laten kijken?
>>
>> Mijn ervaring is dat methode 2 de meest gebruikte is (bij webmail en zo).
>
> Probleem is dat dat voor geen meter schaalt.

Toch gebruikt oa de webmail van kennisnet het. Lijkt me niet een kleine
applicatie. Ik zie niet echt in waarom het niet schaalt (ipv een
mod-rewrite zijn symbolic links misschien handiger).

> [bittorent als alternatief]
> En hoe zit het dan met de door de OP gewenste authenticatie?

Je kan die torrent natuurlijk wel op manier 1 beveiligen :)

Mark

Michiel de Roo
13/11/03, 15:15
Branko Collin wrote:
>
> - Ik laat PHP via fread() of fpassthrough() het bestand oplepelen. Dat
> heeft het grote voordeel dat authenticering puur via de sessie gaat, maar
> het nadeel dat je met intelligente buffering moet gaan werken (PHP
> reserveert voor een bestand van 50 MB gerust 50 MB geheugenruimte, en
> hardware schaalt over het algemeen niet zo lekker), en dat er een extra
> schakel in het proces zit die de boel mogelijk vertraagt.
>

Ik heb deze methode vaak gebruikt, en dat werkte voor mij altijd prima.
Alleen die grote bestanden... daar heb ik geen ervaring mee, maar ik
betwijfel of de stelling over buffering klopt. Bovendien, het is simpel te
implementeren en als blijkt dat het niet goed schaalt kun je altijd nog
wat anders verzinnen.

Je moet iig wel de volgende headers gebruiken, om er voor te zorgen dat de
filenaam bij het downloaden correct wordt opgepikt:

<?

$file = "filenaam";
$path = "volledige/path";

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$file\"");

$fd=fopen($path); fpassthru($fd);

?>


Michiel.

Arnoud Galactus Engelfriet
13/11/03, 20:00
In article <3fb38ed1$0$58708$e4fe514c@news.xs4all.nl>,
Michiel de Roo <michiel@mderooPUNTNL> wrote:
>header("Content-type: application/octet-stream");
>header("Content-Disposition: attachment; filename=\"$file\"");
>
>$fd=fopen($path); fpassthru($fd);

Meestal is het efficienter om readfile($path) te doen. Dat
doet hetzelfde als fpassthru() maar zonder dat je in PHP
dat bestand eerst open moet doen. Met een beetje geluk gaat
dat achter de schermen een stuk sneller.

Bovendien gebruikt readfile() volgens de manual geen
buffer, en fopen() samen met fpassthru() en vriendjes wel.

Arnoud

--
Arnoud Engelfriet, Dutch patent attorney - Speaking only for myself
Patents, copyright and IPR explained for techies: http://www.iusmentis.com/

Branko Collin
14/11/03, 18:45
Marcus wrote:

> Je zou eventueel nog kunnen kijken naar bittorrent, waarbij als er
> weinig wordt gedownload je altijd zelf moet seeden. Deze techniek is
> vooral interessant als je weinig bandbreedte hebt, maar erg veel
> downloads verwacht. Het neemt namelijk vrijwel geen bandbreedte, maar
> maakt gebruik van de upload van de downloader.

Zijn er webgebaseerde bittorrentclients?

Branko Collin
14/11/03, 18:45
Michiel de Roo wrote:

> Bovendien, het is simpel te implementeren en als blijkt dat het
> niet goed schaalt kun je altijd nog wat anders verzinnen.

Dat is de conclusie die we hier inmiddels ook getrokken hebben. Het
uitzoeken van hoe je een goed-schalend systeem maakt, gaat waarschijnlijk
even veel of meer tijd kosten dan een systeem wat doet wat het nu moet
kunnen.

Iedereen bedankt voor de antwoorden!

Daniel Tryba
14/11/03, 20:00
Marcus <mark@ijbema.xs4all.nl.invalid> wrote:
>>> Mijn ervaring is dat methode 2 de meest gebruikte is (bij webmail en zo).
>>
>> Probleem is dat dat voor geen meter schaalt.
>
> Toch gebruikt oa de webmail van kennisnet het. Lijkt me niet een kleine
> applicatie.

Geen idee... wat is kennisnet?

> Ik zie niet echt in waarom het niet schaalt (ipv een
> mod-rewrite zijn symbolic links misschien handiger).

Je krast op het filesystem van 1 webserver. Als je er meerdere hebt kan
het natuurlijk zo zijn dat de gebruiker om wat voor een reden dan ook
(bv machine valt om, loadbalancer vindt het te druk op de webserver waar
je de kras actie gedaan hebt) op een andere machine de daadwerkelijke
request doet voor de file. Dan krijgt die gebruiker toch mooi iets
anders dan verwacht.

--

Daniel Tryba