Historia pytania:
Analiza leksykalna (lexical analysis) to pierwszy etap interpretacji kodu Perl. Na tym etapie tekst źródłowy jest dzielony na "leksemy": zmienne, słowa kluczowe, operatory, literały itd. Cechą charakterystyczną Perla jest to, że składnia języka jest bardzo elastyczna, wiele konstrukcji dopuszcza warianty, a zmienne przeplatają się z operatorami i identyfikatorami.
Problem:
Głównym wyzwaniem podczas analizy leksykalnej Perla jest niejednoznaczność parsowania i niebezpieczeństwo bezpośredniego wstawiania wartości zmiennych/łańcuchów do kodu, szczególnie w konstrukcjach takich jak eval oraz przy podstawianiu zmiennych w łańcuchach z plikami, ścieżkami, wyrażeniami regularnymi. Perl nie dokonuje "podwójnej analizy": jeśli tworzysz łańcuch dla eval, parsowanie odbywa się od zera, co może prowadzić do nieoczekiwanych błędów i luk (iniekcje SQL dla DBI, błędna składnia itd.).
Rozwiązanie:
Aby uniknąć nieoczekiwanych efektów podczas analizy leksykalnej, pisze się maksymalnie jawny kod, stosuje się ścisłe formatowanie za pomocą use strict i warnings, unika się nadmiernego eval oraz wyraża dynamikę nie przez wstawianie łańcuchów, ale strukturalnie: przez podprogramy, zamknięcia i silną typizację danych. Do złożonych podstawień często używa się sprintf, formatów podobnych do sprintf oraz modułów, na przykład Text::Template.
Przykład kodu:
my $operation = 'print'; my $argument = 'Hello, world!'; # Nigdy NIE rób tego: eval "$operation \"$argument\";"; # Niebezpieczne! # Lepiej: if ($operation eq 'print') { print $argument; }
Kluczowe cechy:
Pytanie z pułapką 1: "Czy można po prostu eskapować pojedyncze i podwójne cudzysłowy w łańcuchu, aby uniknąć luk przy użyciu eval?"
W rzeczywistości, prosta eskapacja cudzysłowów nie chroni przed wszystkimi możliwymi lukami, ponieważ parser Perla interpretuje łańcuch w całości, a złożone zagnieżdżone konstrukcje mogą obejść eskapację. Używaj podejścia strukturalnego.
Pytanie z pułapką 2: "Czy można użyć here-doc do bezpiecznego generowania kodu Perl dla eval?"
Here-doc ułatwia formatowanie długich łańcuchów, ale nie chroni przed błędami składniowymi i wciąż jest podatny na iniekcje, jeśli wstawiasz nieoczyszczone dane. To nie zapewnia bezpieczeństwa.
Pytanie z pułapką 3: "Czy Perl odczytuje wyrażenia w łańcuchach, które nie są bezpośrednio przekazywane do eval?"
Nie, Perl parsuje tylko rzeczywiście wykonywalny kod, łańcuchy poza eval lub podobnymi mechanizmami nie są parsowane i nie są wykonywane.
Programista tworzy dynamiczne zapytanie SQL w łańcuchu, podstawiając parametry użytkownika bez walidacji, a następnie wbudowanym sposobem przez eval stara się wykonać to zapytanie.
Zalety:
Wady:
Zamiast dynamicznego eval używa się przygotowanych wyrażeń w DBI, parametry podstawia się przez placeholdery, błędy są załatwiane przez use strict i warnings.
Zalety:
Wady: