2009-06-28 12 views
38

mam prosty skrypt PHP pocztowego, który przyjmuje wartości z formularza złożonego przez POST i maili je do mnie:Jak odseparować dane wejściowe użytkownika w PHP przed wysłaniem wiadomości?

<?php 
$to = "[email protected]"; 

$name = $_POST['name']; 
$message = $_POST['message']; 
$email = $_POST['email']; 

$body = "Person $name submitted a message: $message"; 
$subject = "A message has been submitted"; 

$headers = 'From: ' . $email; 

mail($to, $subject, $body, $headers); 

header("Location: http://example.com/thanks"); 
?> 

Jak można odkazić wejście?

+1

Jeśli używasz prostego pola tekstowego, nie powinno być żadnych htmlentities w danych $ _POST. Jeśli używasz edytora tekstu formatowanego, który generuje html, użyj html_entity_decode(). Pamiętaj, aby usunąć znaki kontrolne z tematu - znaki nowej linii w temacie mogą zepsuć nagłówki wiadomości e-mail. –

+16

@Frank Farmer: sugerujesz, że powinien on ufać, że żaden ofensywny kod nie dotrze do jego kodu tylko dlatego, że użył "prostego" pole tekstowe"? To straszna rada. –

+9

Heh, proste pole tekstowe. Po prostu zrobiłem test XSS na kimś, kto to zrobił. Nie podobało im się zabawne zdjęcie przesłane za pomocą linku img wprowadzonego w "prostym polu tekstowym". –

Odpowiedz

44

Zdezynfekuj zmienną pocztową za pomocą filter_var().

Example here. Jak:

echo filter_var($_POST['email'], FILTER_SANITIZE_EMAIL); 
+0

I like filter_var do tego, niestety, nie wszystkie ustawienia hostingu mają jeszcze 5.2, ale wydaje się być dobrze przemyślaną funkcją. – artlung

+0

php 5 jest całkiem niezły filter_var (PHP 5> = 5.2.0) –

+2

Nie wszystkie konfiguracje hostingu mają jeszcze 5,2, hehe, tak jest w 2009 roku. Teraz to bardziej, jeśli nadal działają one w wersji 5.4. Są podejrzane. – markus

10

Ponieważ nie budujemy zapytanie SQL lub cokolwiek tu jedynym istotnym walidacja że widzę na tych wejściach jest walidacja email do $ _POST [ „email”], a może alfanumeryczny filtruj pozostałe pola, jeśli naprawdę chcesz ograniczyć zakres tego, co może zawierać wiadomość.

Aby filtrować adres e-mail, wystarczy użyć filter_var:

$email = filter_var($email, FILTER_SANITIZE_EMAIL); 

zgodnie z sugestią Frank Farmer, można także odfiltrować znaki nowej linii w temacie e-mail:

$subject = str_replace(array("\r","\n"),array(" "," "),$subject); 
+2

Znaki nowej linii w tematyka wiadomości e-mail jest nieco problematyczna. –

+0

Cześć, Frank, zredagowałem swoją odpowiedź, aby odzwierciedlić Twoją sugestię. –

+7

W zależności od tego, jak jest skonstruowana wiadomość e-mail, znaki nowego wiersza mogą zostać wstawione do dowolnego nagłówka wiadomości e-mail, umożliwiając atakującemu dodanie nowych lub zastępczych nagłówków e-mail, które lubi. Oprócz tego, wstrzyknięcie całej pustej linii (dwóch nowych linii) pozwala intruzowi wstawić wybraną przez siebie pocztę e-mail, całkowicie przesłaniając wygenerowaną wiadomość e-mail. – Cheekysoft

4

jak inni to zauważyli, filter_var jest świetny. Jeśli nie jest dostępna, dodaj to do swojego zestawu narzędzi.

Zmienna $headers jest szczególnie szkodliwa pod względem bezpieczeństwa. Można go dołączyć i spowodować dodanie do niego nagłówków spoofowanych. Ten wpis o nazwie Email Injection omawia go całkiem dobrze.

filter_var i s super, ale innym sposobem zapewnienia, że ​​coś jest adresem e-mail, a nie czymś złym jest użycie funkcji isMail(). Oto jeden:

function isEmail($email) { 
    return preg_match('|^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]{2,})+$|i', $email); 
}; 

więc korzystać z tego, można zrobić:

if (isset($_POST['email']) && isEmail($_POST['email'])) { 
    $email = $_POST['email'] ; 
} else { 
    // you could halt execution here, set $email to a default email address 
    // display an error, redirect, or some combination here, 
} 

Pod względem ręcznego sprawdzania, ograniczając długość korzystając substr(), bieganie strip_tags() i inaczej ograniczenie co można umieścić w

.
+1

Mówiąc o filter_var, ma również filtr do sprawdzania poprawności e-maili, więc twoja funkcja 'isEmail' jest zła i niepotrzebna (nie wspominając, że regex nie może poprawnie zweryfikować e-maili). –

4

Musisz usunąć wszelkie znaki nowej linii z danych wprowadzonych przez użytkowników w nagłówkach $, które zostaną przekazane do mail() ($ email w twoim przypadku)! Zobacz Email injection.

PHP powinien dbać o odkażania $ i $ do tematu, ale są wersje PHP z robakami (Dotknięte są PHP 4 < = 4.4.6 i PHP 5 < = 5.2.1, patrz MOPB-34-2007).

0

Można użyć kodu z artlung nagłówek „s odpowiedzi powyżej, aby potwierdzić e-mail ..

Używam tego rodzaju kodu, aby zapobiec zastrzyk nagłówka ..

// define some mail() header's parts and commonly used spam code to filter using preg_match 
$match = "/(from\:|to\:|bcc\:|cc\:|content\-type\:|mime\-version\:|subject\:|x\-mailer\:|reply\-to\:|\%0a|\%0b)/i"; 

// check if any field's value containing the one or more of the code above 
if (preg_match($match, $name) || preg_match($match, $message) || preg_match($match, $email)) { 

// I use ajax, so I call the string below and send it to js file to check whether the email is failed to send or not 
echo "failed"; 

// If you are not using ajax, then you can redirect it with php header function i.e: header("Location: http://example.com/anypage/"); 

// stop the script before it reach or executing the mail function 
die(); 

} 

mail()” s filtrowanie powyżej jest zbyt rygorystyczne, ponieważ niektórzy użytkownicy mogą używać filtrowanych ciągów w swoich wiadomościach bez zamiaru przejęcia twojego formularza e-mail, więc przekieruj go na stronę wyjaśniającą, jakiego rodzaju ciągi znaków nie są dozwolone w formularzu lub wyjaśnij je na swoim strona formularza.