Beveiliging van bestanden (links)
Waarschijnlijk zal het wel ergens bekend zijn, maar heb tot op heden nog geen goed script kunnen vinden.
Ik heb een website met waarbij een inlogprocedure aan vast zit.
Nu krijgen gebruikers bijvoorbeeld een download pagina waarin ze bestanden kunnen downloaden. (elke gebruikersgroep krijgt de links zichtbaar o.b.v. de user_role)
Echter nu wil ik hierop wat meer beveiliging zetten. Zodat de gebruiker die op de link klikt het bestand ook daadwerkelijk mag downloaden. Ieder elk ander bestand wat hij niet mag zien, mag hij ook niet downloaden.
Nu heb ik zelf ook al achterhaald, dat wanneer iemand de link van het bestand achterhaald, en niet ingelogd is het bestand ook kan downloaden. Wil dus dit dicht hebben, zodat er geen bestanden gedownload kunnen worden door bezoekers & gebruikers waar zij geen recht op hebben.
Heeft iemand een script of kan iemand mij hier bij assisteren?
Gewijzigd op 20/01/2015 20:19:14 door Jordy Heer
Zet de bestanden uiteraard buiten de webroot, en haal ze met readfile () en de juiste headers op.
Ik heb een tabel genaamd "downloads" waarin ik alle info heb staan van het bestand om de <a> link te creëren. (path,file_name).
Per record staat de user_group die recht zou mogen hebben tot dit bestand. Hier wordt al door bepaald of de user de link mag zien op de pagina
2. De bestanden heb ik nu buiten de "public_html" folder gezet
3. Ophalen met readfile() en juiste headers. Hoe kan ik dat het beste doen? op de downloads.php pagina wordt de <a> </a> gecreëerd met if statements en dan een echo.
Hoor ook graag of punt 1 en 2 ook correct zijn.
Gewijzigd op 20/01/2015 20:34:53 door Jordy Heer
Situatie nu:
table downloads:
ID: 1
path media/uploads/nl/fileuploads/
file: bestand.pdf
titl: Titel
display: Weergave
user_rol: rechtengroep
active_flag: link_actief? (1/0)
target_blank: moet er een target_blank uitgevoerd worden (1/0)
file_type: type bestand (pdf,doc,xls etc)
downloads.php
bouwt de <a> </a> op vanuit de bovenstaande informatie o.b.v. de user_role.
Hoe bouw ik dan de readfile & GET in de downloads.php o.b.v. de user_role ?
Heb je een dumpje van je database structuur met enkele records. Dan heb ik beter inzicht.
document 3,3 Mb 1 media/uploads/nl/fileuploads/ aktevansplitsing.pdf Akte van Splitsing Akte van Splitsing 0 1 1 pdf
document 99 Kb 2 media/uploads/nl/fileuploads/ huishoudelijkreglement.pdf Huishoudelijkreglement Huishoudelijkreglement 0 1 1 pdf
document 64 Kb 3 media/uploads/nl/fileuploads/ bouwprocedure.pdf Bouwprocedure Bouwprocedure 0 1 1 pdf
Toevoeging op 20/01/2015 21:03:46:
Volgens mij is het niet echt leesbaar met records: maar dit is sowieso de structuur.
Field Type Null Key Default Extra
subject varchar(200) YES NULL
size varchar(20) YES NULL
order_by int(11) NO PRI NULL auto_increment
path varchar(500) YES NULL
file varchar(200) YES NULL
title varchar(200) YES NULL
display varchar(200) YES NULL
user_role int(11) YES 1
active_flag int(11) YES 0
target_blank int(11) YES 0
file_type varchar(200) YES NULL
order by is het id
Gewijzigd op 20/01/2015 21:04:25 door Jordy Heer
Gelukkig hebben we hier codetags en kan je met phpMyAdmin een mooie export maken.
Code (php)
1
2
3
4
2
3
4
"subject","size","order_by","path","file","title","display","user_role","active_flag","target_blank","file_type"
"document","3,3 Mb","1","media/uploads/nl/fileuploads/","aktevansplitsing.pdf","Akte van Splitsing","Akte van Splitsing","0","1","1","pdf"
"document","99 Kb","2","media/uploads/nl/fileuploads/","huishoudelijkreglement.pdf","Huishoudelijkreglement ","Huishoudelijkreglement ","0","1","1","pdf"
"document","64 Kb","3","media/uploads/nl/fileuploads/","bouwprocedure.pdf","Bouwprocedure","Bouwprocedure","0","1","1","pdf"
"document","3,3 Mb","1","media/uploads/nl/fileuploads/","aktevansplitsing.pdf","Akte van Splitsing","Akte van Splitsing","0","1","1","pdf"
"document","99 Kb","2","media/uploads/nl/fileuploads/","huishoudelijkreglement.pdf","Huishoudelijkreglement ","Huishoudelijkreglement ","0","1","1","pdf"
"document","64 Kb","3","media/uploads/nl/fileuploads/","bouwprocedure.pdf","Bouwprocedure","Bouwprocedure","0","1","1","pdf"
Gewijzigd op 20/01/2015 21:12:25 door - Ariën -
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// Sessie Starten
session_start();
// Connectie Includen
include 'connection.php';
// Variabelen opmaken. Je kunt de variabelen ook direct in de query zetten
$file = mysqli_real_escape_string($con,$_GET['file']);
$role = mysqli_real_escape_string($con,$_SESSION['role']);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysqli_num_rows(mysqli_query($con,"SELECT order_by FROM downloads WHERE file = '$file' AND user_role = '$role'"));
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == '1'){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
// Bij onjuist geven we een foutmelding
else{
echo "U bent niet bevoegd dit bestand te downloaden.";
}
}
?>
// Sessie Starten
session_start();
// Connectie Includen
include 'connection.php';
// Variabelen opmaken. Je kunt de variabelen ook direct in de query zetten
$file = mysqli_real_escape_string($con,$_GET['file']);
$role = mysqli_real_escape_string($con,$_SESSION['role']);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysqli_num_rows(mysqli_query($con,"SELECT order_by FROM downloads WHERE file = '$file' AND user_role = '$role'"));
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == '1'){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
// Bij onjuist geven we een foutmelding
else{
echo "U bent niet bevoegd dit bestand te downloaden.";
}
}
?>
Edit: Paar fouten eruit gehaald.
Gewijzigd op 20/01/2015 21:12:57 door Peter Flos
Heb deze nu in een download_check.php bestand gezet.
Als ik deze benader met bv download_check.php?file=aktevansplitsing.pdf krijg ik nog allerlei foutmeldingen.
Warning: mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in public_html/download_check.php on line 9
Warning: mysqli_real_escape_string() expects parameter 1 to be mysqli, null given in public_html/download_check.php on line 10
Warning: mysqli_query() expects parameter 1 to be mysqli, null given in public_html/download_check.php on line 13
Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, null given in public_html/download_check.php on line 13
Gewijzigd op 20/01/2015 23:01:42 door Jordy Heer
Volgens mij mysql :-)
Mysql heeft geen 2e parameter nodig bij een real escape. Ik zit al een tijdje in de mysqli, dus hoop dat het zo goed gaat:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// Sessie Starten
session_start();
// Connectie Includen
include 'connection.php';
// Variabelen opmaken. Je kunt de variabelen ook direct in de query zetten
$file = mysql_real_escape_string($_GET['file']);
$role = mysql_real_escape_string($_SESSION['role']);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysql_num_rows(mysql_query("SELECT order_by FROM downloads WHERE file = '$file' AND user_role = '$role'"));
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == '1'){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
// Bij onjuist geven we een foutmelding
else{
echo "U bent niet bevoegd dit bestand te downloaden.";
}
}
?>
// Sessie Starten
session_start();
// Connectie Includen
include 'connection.php';
// Variabelen opmaken. Je kunt de variabelen ook direct in de query zetten
$file = mysql_real_escape_string($_GET['file']);
$role = mysql_real_escape_string($_SESSION['role']);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysql_num_rows(mysql_query("SELECT order_by FROM downloads WHERE file = '$file' AND user_role = '$role'"));
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == '1'){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
// Bij onjuist geven we een foutmelding
else{
echo "U bent niet bevoegd dit bestand te downloaden.";
}
}
?>
Gewijzigd op 20/01/2015 21:32:52 door Peter Flos
Krijg nu U bent niet bevoegd dit bestand te downloaden
maar $count is wel 1
Mis ik niet nog het pad van de locatie waar het bestand staat?
of moet die in $file zitten?
Het kan nog netter met een mooie functie en een DEBUG-'switch', maar ik houd het even simpel.
Verder heb ik de bestandnaam toegevoegd en de count check verbeterd.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
// VANAF LIJN 12!!!
// query opslaan in een result en uitvoeren
$result = mysql_query("SELECT order_by FROM downloads WHERE file = '$file' AND user_role = '$role'");
if($result) {
// resultaat van query in een array zetten.
$data = mysql_fetch_assoc($result);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysql_num_rows($result);
$file = $data['file']; // 'file' is veldnaam uit de tabel.
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == 1){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
} else {
// Bij onjuist geven we een foutmelding
echo "U bent niet bevoegd dit bestand te downloaden.";
}
}
} else {
// Als de query stuk is of niet uitgevoerd kan worden tonen we een foutmelding.
echo "Er is een fout opgetreden in de query: ".mysql_error();
}
?>
// VANAF LIJN 12!!!
// query opslaan in een result en uitvoeren
$result = mysql_query("SELECT order_by FROM downloads WHERE file = '$file' AND user_role = '$role'");
if($result) {
// resultaat van query in een array zetten.
$data = mysql_fetch_assoc($result);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysql_num_rows($result);
$file = $data['file']; // 'file' is veldnaam uit de tabel.
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == 1){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
} else {
// Bij onjuist geven we een foutmelding
echo "U bent niet bevoegd dit bestand te downloaden.";
}
}
} else {
// Als de query stuk is of niet uitgevoerd kan worden tonen we een foutmelding.
echo "Er is een fout opgetreden in de query: ".mysql_error();
}
?>
Gewijzigd op 20/01/2015 21:44:16 door - Ariën -
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
// VANAF LIJN 12!!!
// query opslaan in een result en uitvoeren
$result = mysql_query("SELECT file FROM downloads WHERE file = '$file' AND user_role = '$role'");
if($result) {
// resultaat van query in een array zetten.
$data = mysql_fetch_assoc($result);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysql_num_rows($result);
$file = $data['file']; // 'file' is veldnaam uit de tabel.
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == 1){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
echo "Het bestand is niet gevonden.";
} else {
// Bij onjuist geven we een foutmelding
echo "U bent niet bevoegd dit bestand te downloaden.";
}
} else {
// Als de query stuk is of niet uitgevoerd kan worden tonen we een foutmelding.
echo "Er is een fout opgetreden in de query: ".mysql_error();
}
?>
// VANAF LIJN 12!!!
// query opslaan in een result en uitvoeren
$result = mysql_query("SELECT file FROM downloads WHERE file = '$file' AND user_role = '$role'");
if($result) {
// resultaat van query in een array zetten.
$data = mysql_fetch_assoc($result);
// Controleren of de gebruiker bij het bestand de juiste rechten heeft
$count = mysql_num_rows($result);
$file = $data['file']; // 'file' is veldnaam uit de tabel.
// User-Output aan de hand van $count
// Bestand en Rol zijn juist? Bestand downloaden
if($count == 1){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
echo "Het bestand is niet gevonden.";
} else {
// Bij onjuist geven we een foutmelding
echo "U bent niet bevoegd dit bestand te downloaden.";
}
} else {
// Als de query stuk is of niet uitgevoerd kan worden tonen we een foutmelding.
echo "Er is een fout opgetreden in de query: ".mysql_error();
}
?>
Edit: En nog een extra foutafhandelingetje toegevoegd
Edit 2: Nog een kleine fout in de select eruit gehaald.
Gewijzigd op 20/01/2015 21:48:40 door Peter Flos
Krijg nu inderdaad dat het bestand niet is gevonden, volgens mij mis ik nu nog het pad van waar het bestand staat (buiten de root)
Waar moet die inkomen?
Je krijgt dus:
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- ROOT
(in je root)
---- bestand1.pdf
---- bestand2.pdf
---- bestand3.pdf
---- public_html
(in je public_html)
------- index.php
------- download_check.php
(in je root)
---- bestand1.pdf
---- bestand2.pdf
---- bestand3.pdf
---- public_html
(in je public_html)
------- index.php
------- download_check.php
Download_check.php staat in dit geval in je public_html. 1 map terug staat je root en je bestanden.
Nu heb ik het zelf niet getest, maar ../ zorgt ervoor dat je 1 map terug gaat.
Gewijzigd op 20/01/2015 21:57:00 door Peter Flos
@peter, is het niet handig om het pad in $file te plaatsen? Anders snapt filesize, en file_exists het ook niet meer helemaal ;-)
Gewijzigd op 20/01/2015 21:58:46 door - Ariën -
maar nog steeds bestand niet gevonden