Perl beklagt sich darueber, dass du ungeprueft Benutzerdaten fuer das
open(DATS, ">>$_[0]") in
writed() benutzt. Mit dieser Zeile kann ich an jede Datei auf dem Server Daten anhaengen, fuer die der User, unter dem das Skript laeuft, Schreibrechte hat! Und die Funktion writes() reicht mir schon, um mir jede Datei anzeigen zu lassen. (Was Perl zwar per se nicht als unsicher ansieht, aber darueber kann man geteilter Meinung sein.)
Beispiel:
http://dein.server.tld/pfad/zum/skript?func=writes&datei=/etc/passwd
Was macht diese URL wohl, wenn der Server unter Linux/Unix laeuft?
Offensichtlich laeuft dein Skript unter Taint-Mode (gut!) und hat deshalb zumindest etwas gehobenere Sicherheitsansprueche.
Abhilfe: Entferne mit einer Regex alles aus den Benutzerparametern, was dort nicht hingehoert, z.B. Pfadangaben.
Noch ein paar Anmerkungen:
- Woher hast du diese Syntax mit "local"? Ersetze bitte alle "local variablenname" durch "my variablenname", falls du nicht ein uraltes Perl (< 5.0) benutzt.
- CGI-Parameter von Hand auszuwerten ist fehlertraechtig. Es gibt CGI.pm, und das ist bei Perl dabei.
Hier mal ein Vorschlag, wie man das mit CGI.pm schreiben koennte:
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/perl -T
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
my $FilePath = '/home/username/public_html/files/';
my $Cgi = CGI->new;
my %Dat = $Cgi->Vars;
if (exists $Dat{func} && $Dat{func} eq 'writes') {
writes ($Dat{datei});
} elsif (exists $Dat{func} && $Dat{func} eq 'writed') {
writed ($Dat{datei}, $Dat{text});
} else {
first();
}
sub first{
printhead('Datenschreiber');
print $Cgi->p('In welche Datei soll geschrieben werden?'),
$Cgi->start_form,
$Cgi->textfield (-name => 'datei', -size => 40),
$Cgi->hidden (-name => 'func', -default => 'writes'),
$Cgi->submit (-value => 'Senden'),
$Cgi->end_form;
printfoot();
}
sub writes{
my ($file) = @_;
if ($file =~ /([.\w-]+)/) { # nur Folgen von A-Z, a-z, 0-9, ., - oder _ zulassen
$file = $1;
} else {
$file = 'test.dat'; # Fallback
}
open(DATEI, '<', $FilePath . $file) or die "Kann Datei $file nicht lesen: $!";
my @zeilen = <DATEI>;
close DATEI;
printhead('Datenschreiber');
print $Cgi->p("In der Datei $file steht Folgendes:"),
$Cgi->p(join '<br />', @zeilen);
print $Cgi->p('Wollen Sie etwas schreiben, so geben Sie es hier ein:'),
$Cgi->start_form,
$Cgi->textarea (-name => 'text', -rows => 10, -columns => 40, -wrap => 'virtual'),
$Cgi->br,
$Cgi->hidden (-name => 'func', -default => 'writed'),
$Cgi->hidden (-name => 'datei', -default => $file),
$Cgi->submit (-value => 'Speichern'),
$Cgi->reset (),
$Cgi->end_form;
printfoot();
}
sub writed{
my ($file, $text) = @_;
if ($file =~ /([.\w-]+)/) { # nur Folgen von A-Z, a-z, 0-9, ., - oder _ zulassen
$file = $1;
} else {
$file = 'test.dat'; # Fallback
}
open(DATS, '>>', $FilePath . $file) or die "Kann Datei $file nicht schreiben: $!";
print DATS $text;
close(DATS);
printhead('Datenschreiber');
$text =~ s/\n/<br>/g;
print $Cgi->h1("Schreiben erfolgreich!"),
$Cgi->p("In die Datei $file wurde Folgendes geschrieben:"),
$Cgi->p($text);
printfoot();
}
sub printhead
{
my ($title) = @_;
print $Cgi->header(),
$Cgi->start_html($title);
}
sub printfoot
{
print $Cgi->end_html;
}
Ob man CGI.pm auch fuer den HTML-Code benutzt ist Geschmackssache, aber zumindest fuer Header und Formulare ist es anzuraten.