/ / Jak mogę wyświetlać obraz w Perlu z pewnym bezpieczeństwem i najmniejszymi zasobami? - perl, image, cgi

Jak mogę wyświetlać obraz w Perlu z pewnym bezpieczeństwem i najmniejszymi zasobami? - perl, image, cgi

Znalazłem tu kilka powiązanych postów, ale nictak jest.. Muszę wyświetlać obraz (humm) „poprawnie” i wykorzystywać jak najmniej zasobów. Pracowałem nad sub (poniżej), ale nie jest zbyt przyjazny zasobom, ponieważ używam CGI. To tylko moje przypuszczenie. Jestem nowicjuszem w Perlu, ale podoba mi się to lepiej niż php.

Zapytanie zostanie wygenerowane przez „somescript.pl?img=image.png”

#!/usr/bin/perl -Tw
use strict;
use warnings;
use CGI;

#I should drop warnings after all is said and done. Also name my vars generically. Right?
#I dont know if this query method will work or is even the best method.
$query = new CGI;
my @img = $query->param;
if ( $_ eq "img" ) { my $file = $query->param($_); }
if ( $_ ne "img" ) {    ## I will send to an error sub that serves up a error image
}

# Prob a one liner to take care of the above. Not within my ability though.
# Still figuring all this out here.. Very verbose sorry...
# I will strip everything but lowercase alpha and the "."
# with s =~ /[something like A-Z] I will look it up //g;
# Still.. prob all above will fit in a one liner by a PERL guru!

# Below is related to -Taint, I was told this is important to use the -T.
$ENV{PATH} = "bin:/usr/bin";
delete( $ENV{qw(IFS CDPATH BASH_ENV ENV)} );

# now I will grab the images extension.
my $ext = ( $file =~ m/[^.]+$/ )[0];

#I was informed to use the "three" but, I am unsure what that means.
# My attempt based on my reading many posts here.

my $length = ( stat($file) )[10];
my $image  = do {
local $/ = undef;
print "Content-type: image/$extn";
print "Content-length: $length nn";
binmode STDOUT;
open( FH, "<", $file ) || die "Could not find $file: $!";
my $buffer = "";
while ( read( FH, $buffer, 10240 ) ) {
print $buffer;
}
close(FH);
};

Jak widać, moja próba tutaj jest oczywiście dla początkujących.

Znalazłem świetne rady w przepełnieniu stosu. Dziękuję wszystkim przeszłym i obecnym.

Odpowiedzi:

5 dla odpowiedzi № 1
  1. Jeśli zamierzasz używać rozszerzenia jako substytutu typu MIME, lepiej nazwij wszystkie swoje zdjęcia JPEG .jpeg i nie .jpg! File::MMagic lub File::MimeInfo uczyniłby lepsze rozwiązania ogólnego przeznaczenia.
  2. (stat $file)[10] nie jest to długość zawartości, to jest ctime, co jest dla ciebie bezwartościowe. (stat $file)[7] działa, ale -s $file działa równie dobrze i dla każdego programisty Perla jest oczywiste, co robi bez konieczności sprawdzania stat podręcznik. (2a: użyj -s na uchwycie pliku po jego otwarciu zamiast nazwy pliku, aby uniknąć ścigania się z zastąpieniem pliku.)
  3. Mogę uzyskać dostęp do dowolnego pliku w systemie plików, który może być odczytany przez użytkownika, na którym działa CGI, np. image.pl?image=../../../../../../../etc/passwd. Sugeruję konkretnie wspomnienie katalogu obrazów, abyś nie był zależny od getcwdi używanie File::Spec->no_upwards i File::Spec->catfile zbudować ścieżkę, która może znajdować się tylko w katalogu images.
  4. To nie jest naprawdę dobra forma dla CGI die jeśli „da się uniknąć. Jeśli plik nie zostanie znaleziony, zwróć a 404 status. Jeśli żądanie jest nielegalne, zwróć a 400 lub 403 status itp.
  5. Twoje adresy URL byłyby ładniejsze, gdybyś używał path_info zezwolić image.pl/foo.png zamiast image.pl?img=foo.png.
  6. Jeśli nie dodasz więcej logiki, obrazy, które serwujesz, nie będą buforowane przez klienta.
  7. Człowieku, to się układa. Czy zastanawiałeś się nad znalezieniem kodu, który został już napisany w tym celu, zamiast pisać własny?

4 dla odpowiedzi nr 2

Spójrz na sposób w Apachegallery

http://metacpan.org/pod/Apache::Gallery

Używa Imlib2 i jest dość wydajny, w tym zaawansowane funkcje, takie jak zmiana rozmiaru i obracanie w locie oraz korzystanie z udostępnionej pamięci podręcznej dysku.


1 dla odpowiedzi nr 3

Myślę, że coś tu brakuje:

my @img = $query->param;
if ( $_ eq "img" ) { my $file = $query->param($_); }
if ( $_ ne "img" ) {    ## error }

$_ jest niezainicjowany. Myślę, że chciałeś powiedzieć:

my @img = $query->param;
foreach (@img) {
if ( $_ eq "img" ) { my $file = $query->param($_); }
if ( $_ ne "img" ) {    ##  error }
}

lub dla lepszej czytelności i łatwości konserwacji

my @img = $query->param;
foreach my $param (@img) {
if ( $param eq "img" ) { my $file = $query->param($param); }
if ( $param ne "img" ) {    ## error }
}

Po drugie, prawdopodobnie chcesz użyć

( stat($file) )[7];

i nie

( stat($file) )[10];

aby uzyskać długość pliku. (stat $file)[10] poda czas zmiany pliku.


1 dla odpowiedzi nr 4

Najprostszym sposobem na wyświetlenie obrazu jest użycie obsługi plików, która prawdopodobnie jest już zawarta w twoim serwerze.

Możesz także dodać uwierzytelnianie za pomocą .htaccess plik (jeśli używasz Apache).


1 dla odpowiedzi nr 5

Zmieniłbym tylko kilka rzeczy.

Najpierw zamień blok kodu po pierwszym bloku komentarza na ten:

my $query = new CGI;
my $file = $query->params("img");

Twój kod, aby uzyskać rozszerzenie pliku, nie działa dla mnie.

my ($ext) = $file =~ m/.([^.]+)$/;

Nie rozumiem używania „my $ image = do {...”. To po prostu nie wydaje się konieczne.

Odkąd korzystasz już z modułu CGI, używaj go do wykonywania swoich nagłówków:

print $query->header(
-type => "image/" . $ext,
-Content_length => $length,
);

Sposób, w jaki czytasz plik i zapisujesz go z powrotem, wygląda funkcjonalnie idealnie.

Mam kilka dodatkowych komentarzy i sugestii. Po pierwsze, twój kod jest bardzo niepewny. To miłe, że „zastanawiasz się nad trybem taint, ale nie robisz niczego na temat nazwy pliku przekazywanego z twojego klienta. Co jeśli na przykład przekażą„ / etc / passwd ”? otwórz plik obrazu (po wykonaniu większej liczby kontroli bezpieczeństwa) przed wysyłanie nagłówków HTTP. Pozwoli to na wysłanie rozsądnego błędu z powrotem do klienta (404?), A nie tylko na śmierć. Aby to ułatwić, użyj metody „nagłówka” CGI. Jeśli chcesz, możesz napisać coś do STDERR.

To wszystko, o czym mogę teraz pomyśleć.


0 dla odpowiedzi № 6

Nie jestem pewien, co próbujesz zrobić, ale towygląda na to, że łatwiej byłoby sobie z tym poradzić bez Perla i CGI. Jakiego serwera używasz? Wolę to naprawić za pomocą reguły przepisywania w Apache.

Jednak nigdy nie byłem fanem skryptów gatekeepera. Może jeśli powiesz dlaczego próbujesz to zrobić, możemy wymyślić dobre rozwiązanie (a nie tylko lepsze :).