E-Mail-Validierung: Neuer Ansatz
![](/uploads/default_avatar/thumb/missing.png)
- php
1 Alexander (HH)0 Tom0 Marc Reichelt
0 Alexander (HH)0 Tom
0 Der Martin
0 Tom
2 dedlfix
0 Endergebnis & Danke
Marc Reichelt
Hallo an alle,
für mein aktuelles Projekt ipv6-fuer-alle.de benötige ich eine Funktion, die prüft, ob die Adresse für die PHP-mail()-Funktion genutzt werden kann.
Hierbei möchte ich ausdrücklich NICHT prüfen, ob die E-Mail-Adresse logisch korrekt ist, sondern größeren Schaden verhindern. Hierzu soll die Funktion folgenden Gesichtspunkten standhalten:
1. Sie soll so einfach wie möglich gestaltet sein.
2. Die Benutzung in der Funktion mail() soll möglich sein ohne Schaden anzurichten (Injenction).
3. Es soll nur eine E-Mail-Adresse angegeben werden können (nicht mehrere).
4. Die E-Mail-Adresse soll eindeutig identifizierbar sein, damit nicht mehrfach die gleiche Adresse als Ziel verwendet wird.
5. Nicht jede mögliche Form einer E-Mail-Adresse muss der Prüfung standhalten, wenn sie eine der ersten 4 Regeln verletzt.
Dazu habe ich mir nun folgende Gedanken gemacht:
Ich möchte mir diese Funktion bis morgen Abend geschrieben und auch getestet haben, werde diese aber natürlich dann auch hier veröffentlichen.
Meine Frage an euch ist nun: Fällt euch noch etwas dazu ein, das beachtet werden sollte?
Grüße
Marc Reichelt || http://www.marcreichelt.de/
Moin Moin!
Hierbei möchte ich ausdrücklich NICHT prüfen, ob die E-Mail-Adresse logisch korrekt ist, sondern größeren Schaden verhindern.
Was für Schäden?
Hierzu soll die Funktion folgenden Gesichtspunkten standhalten:
- Sie soll so einfach wie möglich gestaltet sein.
... aber nicht einfacher (Einstein)
- Die Benutzung in der Funktion mail() soll möglich sein ohne Schaden anzurichten (Injenction).
Wenn PHP selbst nicht vernünftig escapen kann, mußt Du es vorher machen.
- Es soll nur eine E-Mail-Adresse angegeben werden können (nicht mehrere).
- Die E-Mail-Adresse soll eindeutig identifizierbar sein, damit nicht mehrfach die gleiche Adresse als Ziel verwendet wird.
Welche der folgenden Adressen sind mit joe@example.com identisch? Welche füllen garantiert die selbe Mailbox?
joe@example.com.
Joe@example.com
JOE@example.com
JOE@EXAMPLE.COM
joe@EXAMPLE.COM
joe+ipv6@example.com
joe-ipv6@example.com
joe@ipv6.example.com
joe@example.org
josef-maria.doe@example.com
- Es muss mindestens ein "@" vorkommen.
Nach dem letzten @ muß mindestens ein Punkt vorkommen, der nicht direkt am @ hängen darf.
Ein abschließender "." ist zwar selten, aber technisch korrekt.
- Die Gesamtlänge darf 255 nicht überschreiten (willkürlich gewählt, um ein Limit zu setzen).
Naja, gut, das kannst Du machen. Aber ein Limit ist in den RFCs nicht drin, soweit ich mich erinnere. Hostnamen haben eine Längenbegrenzung, Mail-Accounts nicht.
- zu 2.) Die ersten 32 ASCII-Codes müssen ausgeschlossen werden.
Tja, da könnte man bestimmt was aus den RFCs basteln, aber das geht wohl so in Ordnung.
- zu 3.) Die Zeichen "," und ";" müssen ausgeschlossen werden.
Prinzipiell könnte man auch diese beiden Zeichen im Account-Namen haben, aber das hat wohl kaum einer.
- zu 4.) Die Zeichen "<" und ">" müssen ausgeschlossen werden, sonst sind Mehrfachnennungen der Form "Eva Mustermann 123@example.com" und "Adam Mustermann 123@example.com" möglich.
s/^(.+)\s+<([^<>]+)>$/$2/;
Alexander
Hello,
- Die Gesamtlänge darf 255 nicht überschreiten (willkürlich gewählt, um ein Limit zu setzen).
Naja, gut, das kannst Du machen. Aber ein Limit ist in den RFCs nicht drin, soweit ich mich erinnere. Hostnamen haben eine Längenbegrenzung, Mail-Accounts nicht.
Aber Zeilenlängen in Mails sind begrenzt. Da ein Header nicht länger sein kann, als eine Zeile, ist er also auf die Zeilenlänge (minus Umbruch ) begrenzt.
Die maximale Länge und die RFC dazu muss sich hier irgendwo im Archiv rumlümmeln.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
siehe:
http://forum.de.selfhtml.org/archiv/2008/3/t168247/#m1098015
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Moin Moin!
Hello,
»» > - Die Gesamtlänge darf 255 nicht überschreiten (willkürlich gewählt, um ein Limit zu setzen).
»»
»» Naja, gut, das kannst Du machen. Aber ein Limit ist in den RFCs nicht drin, soweit ich mich erinnere. Hostnamen haben eine Längenbegrenzung, Mail-Accounts nicht.Aber Zeilenlängen in Mails sind begrenzt. Da ein Header nicht länger sein kann, als eine Zeile, ist er also auf die Zeilenlänge (minus Umbruch ) begrenzt.
Doch, der Header kann durchaus länger als eine Zeile sein. Die folgenden Zeilen beginnen dann mit White Space und zählen logisch zur vorherigen Zeile. Das kannst Du sehr gut bei den Received-Headern fast jeder Mail sehen. Du kannst Dir auch einfach selbst eine Mail mit einem Subject von mehr als 80 Zeichen schicken und Dir dann den Subject-Header ansehen.
Alexander
Hello,
»» > - Die Gesamtlänge darf 255 nicht überschreiten (willkürlich gewählt, um ein Limit zu setzen).
»»
»» Naja, gut, das kannst Du machen. Aber ein Limit ist in den RFCs nicht drin, soweit ich mich erinnere. Hostnamen haben eine Längenbegrenzung, Mail-Accounts nicht.Aber Zeilenlängen in Mails sind begrenzt. Da ein Header nicht länger sein kann, als eine Zeile, ist er also auf die Zeilenlänge (minus Umbruch ) begrenzt.
Doch, der Header kann durchaus länger als eine Zeile sein. Die folgenden Zeilen beginnen dann mit White Space und zählen logisch zur vorherigen Zeile. Das kannst Du sehr gut bei den Received-Headern fast jeder Mail sehen. Du kannst Dir auch einfach selbst eine Mail mit einem Subject von mehr als 80 Zeichen schicken und Dir dann den Subject-Header ansehen.
Die maximale Zeilenlänge laut RFC beträgt 1000 Zeichen inclusive Zeilenendezeichen.
Wo steht das denn mit den mehrzeiligen Headern?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Moin Moin!
Die maximale Zeilenlänge laut RFC beträgt 1000 Zeichen inclusive Zeilenendezeichen.
Richtig. RFC 2822 Abschnitt 2.1.1 sagt, das keine einzelne Zeile länger als 998 Zeichen + CRLF sein darf ("MUST NOT"), gleichzeitig sollten Empfänger aber keine Limits bei der Verarbeitung haben und wenigstens 998 Zeichen+CRLF verdauen können.
Wo steht das denn mit den mehrzeiligen Headern?
RFC 2822 Abschnitt 2.2.3:
Each header field is logically a single line of characters comprising
the field name, the colon, and the field body. For convenience
however, and to deal with the 998/78 character limitations per line,
the field body portion of a header field can be split into a multiple
line representation; this is called "folding". The general rule is
that wherever this standard allows for folding white space (not
simply WSP characters), a CRLF may be inserted before any WSP.
Eine einzelne phsyische Zeile in einer standardkonformen E-Mail kann also nie länger als 998 Zeichen+CRLF sein. Ein einzelner Header kann durch Folding und Unfolding aber durchaus wesentlich länger als 1000 Zeichen sein.
Alexander
Hello,
Eine einzelne phsyische Zeile in einer standardkonformen E-Mail kann also nie länger als 998 Zeichen+CRLF sein. Ein einzelner Header kann durch Folding und Unfolding aber durchaus wesentlich länger als 1000 Zeichen sein.
Das verstehe ich anders. Steht auch an einer anderen Stelle nochmal anders. Muss ich aber selber suchen:
Eine einzelne Zeile kann maximal 998+CRLF werden.
Bei Überschreitung der 78 Zeichen (für die Lesbarkeit, Convenience) kann gefaltet werden.
Das ist noch von Jonathan und mMn noch gültig, weil in RFC 822 und RFC 1341 nochmals kompatibel wiederholt. Das habe ich aber nur noch so im Gedächtnis und noch nicht wieder neu rausgesucht:
4.5.3. SIZES
There are several objects that have required minimum maximum
sizes. That is, every implementation must be able to receive
objects of at least these sizes, but must not send objects
larger than these sizes.
****************************************************
* *
* TO THE MAXIMUM EXTENT POSSIBLE, IMPLEMENTATION *
* TECHNIQUES WHICH IMPOSE NO LIMITS ON THE LENGTH *
* OF THESE OBJECTS SHOULD BE USED. *
* *
****************************************************
user
The maximum total length of a user name is 64 characters.
domain
The maximum total length of a domain name or number is 64
characters.
path
The maximum total length of a reverse-path or
forward-path is 256 characters (including the punctuation
and element separators).
command line
The maximum total length of a command line including the
command word and the <CRLF> is 512 characters.
reply line
The maximum total length of a reply line including the
reply code and the <CRLF> is 512 characters.
[Page 42] Postel
RFC 821 August 1982
Simple Mail Transfer Protocol
text line
The maximum total length of a text line including the
<CRLF> is 1000 characters (but not counting the leading
dot duplicated for transparency).
recipients buffer
The maximum total number of recipients that must be
buffered is 100 recipients.
****************************************************
* *
* TO THE MAXIMUM EXTENT POSSIBLE, IMPLEMENTATION *
* TECHNIQUES WHICH IMPOSE NO LIMITS ON THE LENGTH *
* OF THESE OBJECTS SHOULD BE USED. *
* *
****************************************************
Errors due to exceeding these limits may be reported by using
the reply codes, for example:
500 Line too long.
501 Path too long
552 Too many recipients.
552 Too much mail data.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Moin Moin!
Hello,
»» Eine einzelne phsyische Zeile in einer standardkonformen E-Mail kann also nie länger als 998 Zeichen+CRLF sein. Ein einzelner Header kann durch Folding und Unfolding aber durchaus wesentlich länger als 1000 Zeichen sein.
Das verstehe ich anders. Steht auch an einer anderen Stelle nochmal anders. Muss ich aber selber suchen:
Eine einzelne Zeile kann maximal 998+CRLF werden.
Bei Überschreitung der 78 Zeichen (für die Lesbarkeit, Convenience) kann gefaltet werden.
Es kann jederzeit gefaltet werden. Das Falten erlaubt dem Field Body eine beliebige Länge. Field Bodies sind eine Abstraktionsebene oberhalb der physischen Zeilen, für ihre Representation in einem E-Mail-Header nach RFC2822 können so viele Zeilen wie nötig benutzt werden, eine Einschränkung der Zeilenzahl sehe ich nicht.
Das ist noch von Jonathan und mMn noch gültig, weil in RFC 822
obsoleted by RFC 2822
und RFC 1341 nochmals kompatibel wiederholt.
Darin finde ich gar keine Beschränkungen von Header-Zeilenlängen.
Das habe ich aber nur noch so im Gedächtnis und noch nicht wieder neu rausgesucht:
4.5.3. SIZES
There are several objects that have required minimum maximum
sizes. That is, every implementation must be able to receive
objects of at least these sizes, but must not send objects
larger than these sizes.****************************************************
* *
* TO THE MAXIMUM EXTENT POSSIBLE, IMPLEMENTATION *
* TECHNIQUES WHICH IMPOSE NO LIMITS ON THE LENGTH *
* OF THESE OBJECTS SHOULD BE USED. *
* *
****************************************************user
The maximum total length of a user name is 64 characters.
domain
The maximum total length of a domain name or number is 64
characters.path
The maximum total length of a reverse-path or
forward-path is 256 characters (including the punctuation
and element separators).command line
The maximum total length of a command line including the
command word and the <CRLF> is 512 characters.reply line
The maximum total length of a reply line including the
reply code and the <CRLF> is 512 characters.[Page 42] Postel
RFC 821 August 1982
Simple Mail Transfer Protocoltext line
The maximum total length of a text line including the
<CRLF> is 1000 characters (but not counting the leading
dot duplicated for transparency).recipients buffer
The maximum total number of recipients that must be
buffered is 100 recipients.****************************************************
* *
* TO THE MAXIMUM EXTENT POSSIBLE, IMPLEMENTATION *
* TECHNIQUES WHICH IMPOSE NO LIMITS ON THE LENGTH *
* OF THESE OBJECTS SHOULD BE USED. *
* *
****************************************************Errors due to exceeding these limits may be reported by using
the reply codes, for example:500 Line too long.
501 Path too long
552 Too many recipients.
552 Too much mail data.
Das beschränkt Zeilenlängen und Teile von Header-Feldwerten (Field bodies). 100 Empfänger mit je 64 Zeichen für den User, je einem @ und je 64 für die Domain plus einem Komma dazwischen macht 13.000 Zeichen. Wären Header-Felder auf 998 Zeichen beschränkt, müßte bei 100 Empfängern die durchschnittliche Länge einer Adresse unter 9,9 Zeichen liegen.
Alexander
Hallo Alexander,
»» Hierbei möchte ich ausdrücklich NICHT prüfen, ob die E-Mail-Adresse logisch korrekt ist, sondern größeren Schaden verhindern.
Was für Schäden?
Schäden der Form, wie ich sie beschrieben habe: Header Injections, Angabe mehrerer E-Mails auf ein Mal und Angabe mehrerer Strings, die alle eigentlich die selbe E-Mail-Adresse sind.
»» 2. Die Benutzung in der Funktion mail() soll möglich sein ohne Schaden anzurichten (Injenction).
Wenn PHP selbst nicht vernünftig escapen kann, mußt Du es vorher machen.
Eben genau das ist mein Vorhaben.
»» 4. Die E-Mail-Adresse soll eindeutig identifizierbar sein, damit nicht mehrfach die gleiche Adresse als Ziel verwendet wird.
Welche der folgenden Adressen sind mit joe@example.com identisch? Welche füllen garantiert die selbe Mailbox?
joe@example.com.
Das ist in der Tat eine interessante Angabe - eine einfache Regel hierfür wäre das Ausschließen von Punkten am Ende.
Joe@example.com
JOE@example.com
JOE@EXAMPLE.COM
joe@EXAMPLE.COM
Dies hätte mich sogar gar nicht betroffen, da ich MySQL zur Abfrage verwende. Dennoch ist dies ein wichtiger Punkt, falls Groß- und Kleinschreibung unterschieden wird.
joe+ipv6@example.com
joe-ipv6@example.com
joe@ipv6.example.com
joe@example.org
josef-maria.doe@example.com
Soweit ich das sehe sind dies alles unterschiedliche Adressen, die eventuell später auf die gleiche Mailbox verwaisen können - so etwas soll die Funktion nicht prüfen können. Und außerdem ist das praktisch nicht möglich.
»» - Es muss mindestens ein "@" vorkommen.
- Nach dem letzten @ muß mindestens ein Punkt vorkommen, der nicht direkt am @ hängen darf.
Gute Regel - kann direkt aufgenommen werden, allerdings fehlt mir hier die Angriffsmöglichkeit.
- Ein abschließender "." ist zwar selten, aber technisch korrekt.
Eben deshalb könnte ich ihn in meiner E-Mail-Validierung ausschließen.
»» - Die Gesamtlänge darf 255 nicht überschreiten (willkürlich gewählt, um ein Limit zu setzen).
Naja, gut, das kannst Du machen. Aber ein Limit ist in den RFCs nicht drin, soweit ich mich erinnere. Hostnamen haben eine Längenbegrenzung, Mail-Accounts nicht.
Meine Tabellenspalte in der Datenbank aber schon. ;)
Und: Solche langen E-Mail-Adressen können allein schon deshalb ausgeschlossen werden, weil sie so selten vorkommen. Und wenn sie vorkommen, ist das in 99,9% der Fälle Absicht.
»» - zu 4.) Die Zeichen "<" und ">" müssen ausgeschlossen werden, sonst sind Mehrfachnennungen der Form "Eva Mustermann 123@example.com" und "Adam Mustermann 123@example.com" möglich.
s/^(.+)\s+<([^<>]+)>$/$2/;
Ich könnte natürlich auch einfach das Vorkommen jeglicher "<" und ">" in der Adresse verbieten - das würde meine Regel (1) erfüllen. So ein regulärer Ausdruck ist zwar auch ganz schick und schnell geschrieben, jedoch später schwer nachzuvollziehen wenn man sich länger nicht damit beschäftigt hat.
Alles in allem hast du noch einige Dinge gefunden, die ich in meine Funktion mit aufnehmen sollte. Sehr gut!
Grüße
Marc Reichelt || http://www.marcreichelt.de/
Moin Moin!
Hallo Alexander,
»» »» Hierbei möchte ich ausdrücklich NICHT prüfen, ob die E-Mail-Adresse logisch korrekt ist, sondern größeren Schaden verhindern.
»»
»» Was für Schäden?Schäden der Form, wie ich sie beschrieben habe: Header Injections, Angabe mehrerer E-Mails auf ein Mal und Angabe mehrerer Strings, die alle eigentlich die selbe E-Mail-Adresse sind.
»» »» 2. Die Benutzung in der Funktion mail() soll möglich sein ohne Schaden anzurichten (Injenction).
»»
»» Wenn PHP selbst nicht vernünftig escapen kann, mußt Du es vorher machen.Eben genau das ist mein Vorhaben.
Schade, dass PHP sich nicht um so essenzielle Sachen kümmert.
»» »» 4. Die E-Mail-Adresse soll eindeutig identifizierbar sein, damit nicht mehrfach die gleiche Adresse als Ziel verwendet wird.
»»
»» Welche der folgenden Adressen sind mit joe@example.com identisch? Welche füllen garantiert die selbe Mailbox?
»»
»» joe@example.com.Das ist in der Tat eine interessante Angabe - eine einfache Regel hierfür wäre das Ausschließen von Punkten am Ende.
»» Joe@example.com
»» JOE@example.com
»» JOE@EXAMPLE.COM
»» joe@EXAMPLE.COMDies hätte mich sogar gar nicht betroffen, da ich MySQL zur Abfrage verwende. Dennoch ist dies ein wichtiger Punkt, falls Groß- und Kleinschreibung unterschieden wird.
Rechts des letzten @ nicht, links schon. Typische Mail-Provider arbeiten case insensitiv, aber die RFCs erlauben case sensitive Account-Namen. Joe@example.com, JOE@EXAMPLE.COM und joe@example.com sind bis zu drei verschiedene Mailboxen. joe@example.com und joe@EXAMPLE.COM sind dagegen identisch, ebenso JOE@EXAMPLE.COM und JOE@example.com.
»» joe+ipv6@example.com
»» joe-ipv6@example.com
»» joe@ipv6.example.com
»» joe@example.org
»» josef-maria.doe@example.comSoweit ich das sehe sind dies alles unterschiedliche Adressen, die eventuell später auf die gleiche Mailbox verwaisen können - so etwas soll die Funktion nicht prüfen können. Und außerdem ist das praktisch nicht möglich.
Richtig.
»» »» - Es muss mindestens ein "@" vorkommen.
»»
»» - Nach dem letzten @ muß mindestens ein Punkt vorkommen, der nicht direkt am @ hängen darf.Gute Regel - kann direkt aufgenommen werden, allerdings fehlt mir hier die Angriffsmöglichkeit.
joe@.example.com ist einfach keine gültige Mail-Adresse. Also gibt es auch keinen Grund, die weiter zu behandeln.
»» - Ein abschließender "." ist zwar selten, aber technisch korrekt.
Eben deshalb könnte ich ihn in meiner E-Mail-Validierung ausschließen.
Nein. s/.$//;
»» »» - Die Gesamtlänge darf 255 nicht überschreiten (willkürlich gewählt, um ein Limit zu setzen).
»»
»» Naja, gut, das kannst Du machen. Aber ein Limit ist in den RFCs nicht drin, soweit ich mich erinnere. Hostnamen haben eine Längenbegrenzung, Mail-Accounts nicht.Meine Tabellenspalte in der Datenbank aber schon. ;)
Nimm text, dann brauchst Du Dir darum keine Sorgen mehr machen. ;-)
Und: Solche langen E-Mail-Adressen können allein schon deshalb ausgeschlossen werden, weil sie so selten vorkommen. Und wenn sie vorkommen, ist das in 99,9% der Fälle Absicht.
Naja, wer mit einer mehr als 80 Zeichen langen E-Mail-adresse geschlagen ist, wird sich wohl irgendwo eine kürzere besorgen.
Was aber durchaus vorkommen kann, sind viele Punkte rechts des letzten @. Ich hatte mal eine Adresse xxxxx@hermes.et-inf.xxxxxx.xxx. Auch können solche Adressen bei .uk und anderen TLDs mit fixen SLDs vorkommen: joe@stud.cs.u-bla.edu.tld
Möglich (aber zugegeben extrem selten) wären auch IP-Adressen: joe@127.128.129.130
»» »» - zu 4.) Die Zeichen "<" und ">" müssen ausgeschlossen werden, sonst sind Mehrfachnennungen der Form "Eva Mustermann 123@example.com" und "Adam Mustermann 123@example.com" möglich.
»»
»» s/^(.+)\s+<([^<>]+)>$/$2/;Ich könnte natürlich auch einfach das Vorkommen jeglicher "<" und ">" in der Adresse verbieten - das würde meine Regel (1) erfüllen. So ein regulärer Ausdruck ist zwar auch ganz schick und schnell geschrieben, jedoch später schwer nachzuvollziehen wenn man sich länger nicht damit beschäftigt hat.
OK, laß mich die Codezeile verbessern:
s/^(.+)\s+<([^<>]+)>$/$2/; # extract e-mail address from "name e-mail@address"
CPAN hat dafür übrigens zwei fertige Module: Email::Valid zum Testen und Email::Address zum Parsen.
Alexander
Hello,
»» Wenn PHP selbst nicht vernünftig escapen kann, mußt Du es vorher machen.
Eben genau das ist mein Vorhaben.
Schade, dass PHP sich nicht um so essenzielle Sachen kümmert.
Die lassen uns das hier erst ausdiskutieren, bis sich eine Konvergenz erkennen lässt, diskutieren es dann in dieser Richtung zuende und bauen es dann erst ein. Das kann also dauern :-)
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hallo,
»» 1. Sie soll so einfach wie möglich gestaltet sein.
... aber nicht einfacher (Einstein)
das klingt tatsächlich nach Einstein. Gefällt mir! :-)
»» 4. Die E-Mail-Adresse soll eindeutig identifizierbar sein, damit nicht mehrfach die gleiche Adresse als Ziel verwendet wird.
Welche der folgenden Adressen sind mit joe@example.com identisch? Welche füllen garantiert die selbe Mailbox?
Da ein- und dieselbe Mailbox auch noch beliebig viele Aliases haben kann, ist hier bestenfalls eine Positivaussage "Adressen sind gleichwertig" denkbar. Die umgekehrte Aussage "Adressen gehören zu verschiedenen Postfächern" ist prinzipiell nicht möglich.
joe@example.com.
Joe@example.com
JOE@example.com
JOE@EXAMPLE.COM
joe@EXAMPLE.COM
Ich finde keine Stelle in FRC 2822, die etwas darüber aussagt, ob der Local Part nun case-sensitive ist; ich kenne nur die Praxis vieler Provider, den Local Part *nicht* case-sensitive zu betrachten. Damit sind joe@example.com und JOE@example.com gleichwertig.
Der Domain Part ist sowieso case-insensitive.
- Nach dem letzten @ muß mindestens ein Punkt vorkommen, der nicht direkt am @ hängen darf.
Warum? Ist joe@localhost etwa keine gültige Mailadresse? - Zugegeben, keine die man in freier Wildbahn erwarten würde.
»» - zu 4.) Die Zeichen "<" und ">" müssen ausgeschlossen werden, sonst sind Mehrfachnennungen der Form "Eva Mustermann 123@example.com" und "Adam Mustermann 123@example.com" möglich.
Obacht: Bei der Notation "Klartextname <mailadresse>" muss man natürlich den ganzen Kram außerhalb der <> von technischen Plausibilitätsprüfungen ausnehmen, aber trotzdem auf Unerlaubtes (Zeilenumbrüche->Header Injection) testen.
Wenn man < und > allerdings ganz ausschließt ...
So long,
Martin
Hello,
Warum? Ist joe@localhost etwa keine gültige Mailadresse? - Zugegeben, keine die man in freier Wildbahn erwarten würde.
Wenn Du das so handhabst, dann ist 'joe' alleine auch gültig.
In der lokalen Zustellung wird bei allen mir bekannten Mailservern immer erst nach einem lokalen Konto geschaut. Da ist überhaupt keine Domain notwendig
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
echo $begrüßung;
für mein aktuelles Projekt ipv6-fuer-alle.de benötige ich eine Funktion, die prüft, ob die Adresse für die PHP-mail()-Funktion genutzt werden kann.
Meine Frage an euch ist nun: Fällt euch noch etwas dazu ein, das beachtet werden sollte?
Mir ist nicht bekannt, dass mail() mit Nicht-ASCII-Zeichen umgehen und diese in Punycode wandeln könnte. Wenn dein SMTP-Server das auch nicht kann, müsstest du diese Verwendung ebenfalls unterbinden oder selbst eingreifen.
echo "$verabschiedung $name";
Hallo dedlfix,
Mir ist nicht bekannt, dass mail() mit Nicht-ASCII-Zeichen umgehen und diese in Punycode wandeln könnte. Wenn dein SMTP-Server das auch nicht kann, müsstest du diese Verwendung ebenfalls unterbinden oder selbst eingreifen.
Das klingt logisch. Besteht hier eine Angriffsmöglichkeit? Wenn ja: Gibt es eine einfache Regel, um dies zu vermeiden? Das Verbieten aller Zeichencodes über 127 wird allerdings wohl auch dazu führen, dass E-Mail-Adressen der Form "mäxchen@example.com" nicht funktionieren - und die würde ich ungerne ausschließen wollen.
Wenn diese Regel eingefügt wird sieht meine Funktion übrigens derzeit wie folgt aus:
function testMail($str) {
if (!is_string($str) || strlen($str) > 255) {
// variable must be a string with a max. length of 255
return false;
} else if (strpos($str, '@') === false) {
// there must be an @
return false;
} else {
// check for invalid characters
for ($i = 0; $i < strlen($str); $i++) {
$c = $str[$i];
$cCode = ord($c);
if ($cCode < 32) {
// control characters not allowed
return false;
}
if (strpos('<>,;', $c) !== FALSE) {
// invalid characters
return false;
}
if ($cCode > 127) {
// non-ascii characters not allowed
return false;
}
}
}
return true;
}
Grüße
Marc Reichelt || http://www.marcreichelt.de/
Hello,
Das klingt logisch. Besteht hier eine Angriffsmöglichkeit?
Woraus könnten denn Angriffe bestehen?
Dass unter einem falschen Mailaccount gemailt wird.
Da hilft nur sasl oder ähnliches.
Dass eine Liste mit Empfängern eingeschleust wird und ein eigener Mailbody
Der ordentliche wird abgewürgt durch vergurktes Multipart/related oder ähnliches,
geht also mit, wird aber vom Client nicht mehr angezeigt...
??
Eingänge sind bei der PHP-Mail()-Funktion
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
echo $begrüßung;
» [Nicht-ASCII-Zeichen ... Punycode ... SMTP-Server]
Besteht hier eine Angriffsmöglichkeit?
Ist mir nichts bekannt, was aber nichts heißt, denn das Thema kommt nur passiv bei mir vorbei. Allerdings bekommst du dadurch unerreichbare Mailadressen, was Bounces und "Ich bekomme keine Mail"-Probleme nach sich ziehen wird.
Gibt es eine einfache Regel, um dies zu vermeiden? Das Verbieten aller Zeichencodes über 127 wird allerdings wohl auch dazu führen, dass E-Mail-Adressen der Form "mäxchen@example.com" nicht funktionieren - und die würde ich ungerne ausschließen wollen.
Du musst ja nur die Zeichen nach dem @ prüfen.
Wenn diese Regel eingefügt wird sieht meine Funktion übrigens derzeit wie folgt aus:
Hast du mal einen Performance-Vergleich mit einem Regulären Ausdruck gemacht? Der sollte sich exklusive der is_string()-Prüfung als Einzeiler notieren lassen.
echo "$verabschiedung $name";
Hallo nochmals,
vielen Dank für alle Antworten!
Meine Funktion zum Prüfen auf ungültige Zeichen sieht derzeit wie folgt aus:
function testMail($str) {
if (!is_string($str) || strlen($str) > 255) {
// variable must be a string with a max. length of 255
return false;
} else if (strpos($str, '@') === false) {
// there must be an @
return false;
} else {
// check for invalid characters
for ($i = 0; $i < strlen($str); $i++) {
$c = $str[$i];
$cCode = ord($c);
if ($cCode < 32 || $cCode > 127) {
// control characters and non-ascii characters not allowed
return false;
}
if (strpos('<>,; :\'"', $c) !== FALSE) {
// invalid characters
return false;
}
if ($i == (strlen($str) - 1) && $c == '.') {
// last character should be no dot
return false;
}
}
}
return true;
}
Ich habe zu den anderen Zeichen noch die drei Zeichen : ' und " mit in die Liste der verbotenen Zeichen eingefügt - da diese in der Praxis kaum vorkommen.
Alles in allem zeigt auch dieser Thread, dass die Syntax von E-Mail-Adressen ziemlich kompliziert ist und aufmerksam vor Verwendung in der mail()-Funktion geprüft werden sollte.
WICHTIG (für's Archiv): Wer diese Funktion nutzt, sollte sich darüber im Klaren sein, dass dies keine Funktion ist um zu prüfen ob eine E-Mail-Adresse valide ist, sondern lediglich eine einigermaßen akzeptable Prüfung für die Verwendung in der mail()-Funktion ist.
Grüße
Marc Reichelt || http://www.marcreichelt.de/
Moin Moin!
// check for invalid characters for ($i = 0; $i < strlen($str); $i++) { $c = $str[$i]; $cCode = ord($c); if ($cCode < 32 || $cCode > 127) { // control characters and non-ascii characters not allowed return false; } if (strpos('<>,; :\'"', $c) !== FALSE) { // invalid characters return false; } if ($i == (strlen($str) - 1) && $c == '.') { // last character should be no dot return false; }
Das Stückchen Code sieht für mich fürchterlich ineffizient aus.
1\. Die Prüfung auf den Punkt am Ende würde ich vor die Schleife ziehen, das spart für jedes einzelne Zeichen in $str einen Aufruf von strlen.
~~~php
if ($str[strlen($str)-1]=='.') {
return false; // Alternativ: $str um ein Zeichen verkürzen, denn der Punkt ist KORREKT, nur ungewöhnlich
}
Das sieht so fürchterlich nach C aus:
if (str[strlen(c)-1]=='.') {
return 0;
/* alternativ: */
str[strlen(c)-1]=0;
}
Kann PHP das nicht einfacher? Perl kann direkt auf das letzte Zeichen zugreifen, ohne strlen zu bemühen:
if (substr($str,-1) eq '.') {
return;
# oder:
substr($str,-1)='';
}
# oder gleich per RE:
$str=~s/\.$//;
2. Ich würde nicht jedes einzelne Zeichen in einer interpretierten Schleife darauf hin untersuchen, ob es legal oder illegal ist. Vor allem würde ich es mir verkneifen, für jedes einzelne Zeichen in $str nochmal strpos() aufzurufen, das eine weitere Schleife darstellt.
Du prüfst hier effektiv, ob $str ausschließlich aus einem vorgegebenen Satz von Zeichen besteht. Das ist ein Fall für die schnelle Regular Expression Engine.
Die Blacklist-Version in Perl (analog in PHP nachbaubar):
if ($str=~/[^\x00-\x20<>,;:'"\\\x7F-\xFF]/) {
# Explizit verboten:
# * ASCII-Steuerzeichen von 0x00=NUL bis einschließlich 0x20=Space
# * <>,;.'"\
# * ASCII-Zeichen ab 0x7F=DEL
return;
}
Ein einziges böses Zeichen bricht das Matching ab und rennt ins return.
Haken: $str muß Bytes enthalten, keine UTF-8-Characters.
Blacklist mit UTF-8:
if ($str=~/[^\x00-\x20<>,;:'"\\\x7F-\x{10FFFF}]/) {
# Explizit verboten:
# * ASCII-Steuerzeichen von 0x00=NUL bis einschließlich 0x20=Space
# * <>,;.'"\
# * ASCII-Zeichen ab 0x7F=DEL einschließlich aller Unicode-Planes
return;
}
Whitelist-Version in Perl, mit etwas weniger erlaubten Zeichen (aus Tippfaulheit):
# Funktioniert mit Bytes und Characters.
unless ($str=~/^[\@0-9A-Za-z._-]+$/) {
# Explizit erlaubt:
# * @ -- weil die gesamte Adresse gematcht wird
# * Ziffern, Buchstaben, und ausgesuchte Sonderzeichen (Minus muß aus technischen Gründen ganz hinten stehen)
# Der gesamte String muß aus diesen Zeichen bestehen. Die RE-Engine bricht beim ersten Mismatch ab, der Code rennt ins return.
return;
}
Ich würde die Whitelist-Version vorziehen, weil Du dann 100% garantieren kannst, welche Zeichen an die nicht escapende mail()-Funktion gehen.
Alexander
Hallo Alexander,
Das Stückchen Code sieht für mich fürchterlich ineffizient aus.
Er ist nicht sonderlich effizient, das stimmt - aber diese Funktion wird in meinem Projekt nicht so häufig aufgerufen, da kosten andere Dinge wesentlich mehr Laufzeit.
Nichtsdestotrotz kann - und sollte man - hier noch nachbessern. Dies kann ja im Verlauf der nächsten Tage geschehen, solange der Thread noch nicht archiviert ist.
- Die Prüfung auf den Punkt am Ende würde ich vor die Schleife ziehen, das spart für jedes einzelne Zeichen in $str einen Aufruf von strlen.
if ($str[strlen($str)-1]=='.') {
return false; // Alternativ: $str um ein Zeichen verkürzen, denn der Punkt ist KORREKT, nur ungewöhnlich
}
Jepp, hier sollte man nur aufpassen dass $str auch wirklich eine Länge > 0 hat.
> Kann PHP das nicht einfacher? Perl kann direkt auf das letzte Zeichen zugreifen, ohne strlen zu bemühen:
>
> ~~~perl
> if (substr($str,-1) eq '.') {
> return;
> # oder:
> substr($str,-1)='';
> }
> # oder gleich per RE:
> $str=~s/\.$//;
>
Bei PHP geht's ziemlich ähnlich, kann man also auch abändern.
- Ich würde nicht jedes einzelne Zeichen in einer interpretierten Schleife darauf hin untersuchen, ob es legal oder illegal ist. Vor allem würde ich es mir verkneifen, für jedes einzelne Zeichen in $str nochmal strpos() aufzurufen, das eine weitere Schleife darstellt.
Die Schleife mit strpos() ermittelt für jedes Zeichen $needle, ob es im illegalen Satz $haystack auftaucht. Das ist soweit ok - natürlich kann man hier ebenfalls tunen, aber es wird dem Aufwand bei mir nicht gerecht.
Zu den regulären Ausdrücken: Sicher kann man das alles mit einem Ausdruck lösen, aber den versteht man später nicht mehr so leicht.
Whitelist-Version in Perl, mit etwas weniger erlaubten Zeichen (aus Tippfaulheit):
Funktioniert mit Bytes und Characters.
unless ($str=~/[1]+$/) {
# Explizit erlaubt:
# * @ -- weil die gesamte Adresse gematcht wird
# * Ziffern, Buchstaben, und ausgesuchte Sonderzeichen (Minus muß aus technischen Gründen ganz hinten stehen)
# Der gesamte String muß aus diesen Zeichen bestehen. Die RE-Engine bricht beim ersten Mismatch ab, der Code rennt ins return.
return;
}
>
> Ich würde die Whitelist-Version vorziehen, weil Du dann 100% garantieren kannst, welche Zeichen an die nicht escapende mail()-Funktion gehen.
Eine solche Whitelist hatte ich bislang verwendet - die mochte Vinzenz aber nicht. ;)
Grüße
Marc Reichelt || <http://www.marcreichelt.de/>
--
DPRINTK("Last time you were disconnected, how about now?");
linux-2.6.6/drivers/net/tokenring/ibmtr.c
[Selfcode](http://emmanuel.dammerer.at/selfcode.html): ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
@0-9A-Za-z._- ↩︎