DE PL
Start->Artykuły->Sendmail przeciwko SPAM
2 użytkownik na stronie w 20.10.2014, 23:08:03


Lepsze czynne piekło niż bezczynny raj.

Biuletyn




Pokazać

Ankieta

Przyszło- ściowy jezyk internetu to

 Login

Sendmail przeciwko SPAM

Vor einiger Zeit wurde ich Opfer von Spamer. Ich dachte, daß würde mir doch nicht passieren, da meine Scripte zum Mailversand nicht erlauben sollten, die Zieladresse anzugeben.

Mein Kontakt-Script wurde jedoch für die Spamer zur leichter Beute. Aber normalerweise ist bei dem Script nicht möglich, eine Zieladresse anzugeben. Das Formular nimmt nur die Empfänger-Adreese entgegen und schickt diese Mail dann weiter an mich. Wie konnte das denn passieren?

Zuerst ein kleiner Exkurs zur Mailversand mit sendmail. Sendmail nimmt alle Angaben zur Mailadressen (Absender, Empfänger, CC, BCC) und Inhalt als Textstream auf. Hier ein kleines und unvollständiges Beispiel:

sub sendmail {
  my ($from, $to, $cc, $bcc, $subject, @body)=@_;
  
  # Pfad zu sendmail
  my $sendmail = "| /usr/sbin/sendmail -t -n -oi";
  # jetzt die Adressen fuer sendmail vorbereiten  
  my $head = "";
  
  $head .= "From: $from\n";         # Absender
  $head .= "To: $to\n";             # Empfaenger
  $head .= "Cc: $cc\n";             # CC
  $head .= "Bcc: $bcc\n";           # Blindcopy
  $head .= "Subject: $subject\n\n"; # Betreff

  open(sm,$sendmail);   # Sendmailqueue oeffnen
  print sm $head;       # Kopfdaten uebergeben
  print sm @body;       # Inhalt uebergeben
  close sm;             # Queue schliessen
}
Man könnte denken, alles sei in bester Ordnung. Man übergibt an die Funktion die Parameter (z.B. die Mailadresse aus dem Kontaktformular als CC) und diese erledigt die weitere Arbeit. Das tut sie auch, jedoch muß hier daran gedacht werden, wie sendmail die Kopfdaten verarbeitet. Im Kopf stehen dann z.B. (der Zeilenumbruch \n habe ich wegen der Übersichtlichkeit entfernt):
From: admin@webbe.de To: you@domain.tld Cc: she@domain.tld 
    Bcc: he@domain.tld Subject: Testmail
Das Problem hier ist, wenn man die übergebenen Mail-Adressen nicht prüft, ob diese auch zwei oder mehr Adressen in einem Parameterstring enthalten
# z.B. Aufruf der obengezeigte Funktion mit
sendmail('you\@domain.tld', 'admin\@webbe.de; copy\@webbe.de', 
  '', '', 'Testmail', 'Testmail von mir!');
oder die sendmail-Syntax enthalten
# z.B. Aufruf der obengezeigte Funktion mit
sendmail('From: bill\@gates.com 
 To: spam1@.domain.tld; spam2@.domain.tld; ... spam100@.domain.tld', 
 'admin@webbe.de', '', '', 'V I A G R A', 'Kaufen ...');
Eigentich ist der erste Parameter dafür vorgesehen den Absender z.B aus einem Kontaktformular festzulegen (siehe Funktionskopf) und der zweite kommt direkte aus dem Script und ist im Kontaktscript festvorgegeben:
sendmail($mailFromContactFormular, 'admin@webbe.de' , '', '', 
  $subjectFromContactFormular, $bodyFromContactFormular);
Diese Mail wäre ganz normal verschickt worden und zwar nicht nur an den vorgesehenen Empfänger, sondern an die ganzen SPAM-Adressen.
Man sieht hier was die sendmail-Syntax erlaubt. Also es emfiehlt sich alle Adressen, die man aus irgendwelchen freien Benutzereingaben enthält zu untersuchen und bestimmte Syntax zu verbieten.

Zuerst gilt es eine korrekte Mailadresse zu erkennen. Dies könnte man mit regulären Ausdrücke erledigen (Quelle: http://aktuell.de.selfhtml.org/tippstricks/programmiertechnik/email/ von Christian Kruse):

#!/usr/bin/perl -w

use strict;

### RegEx begin
my $nonascii      = "\x80-\xff"; # Non-ASCII-Chars are not allowed

my $nqtext        = "[^\\\\$nonascii\015\012\"]";
my $qchar         = "\\\\[^$nonascii]";

my $protocol      = '(?:mailto:)';

my $normuser      = '[a-zA-Z0-9][a-zA-Z0-9_.-]*';
my $quotedstring  = "\"(?:$nqtext|$qchar)+\"";
my $user_part     = "(?:$normuser|$quotedstring)";

my $dom_mainpart  = '[a-zA-Z0-9][a-zA-Z0-9._-]*\\.';
my $dom_subpart   = '(?:[a-zA-Z0-9][a-zA-Z0-9._-]*\\.)*';
my $dom_tldpart   = '[a-zA-Z]{2,5}';
my $domain_part   = "$dom_subpart$dom_mainpart$dom_tldpart";

# Der RegEx selbst
my $regex         = "$protocol?$user_part\@$domain_part";
### RegEx end

# Kleiner Test-Schnipsel:

my @emails = (
  'ckruse@wwwtech.de',
  '"Christian Kruse"@wwwtech.de',
  '"Christian \"CK\" Kruse"@wwwtech.de',
  '"Christian"ckruse@wwwtech.de'
);

foreach my $email (@emails) {
  if($email =~ /^$regex$/) {
    print "it is a valid email\n";
  }
  else {
    print "it isn't a valid email\n";
  }
}

# eof
Danach sollte man bestimmte Syntax für Mailadressen verbieten. Dazu gehören z.B. Zeilenumbruch oder die sendmail-Kommandos (To:, From:, Cc:, Bcc:): Das alles kann man zusammenfassen:
sub checkMail {
  my ($mail) = @_;

  # Zeilenumbruch entfernen
  chomp($mail);

  # SPAM-Schutz: keine NEWLINE und keine Anweisungen
  if (isEmail($mail) ne 1 || $mail =~ /\n/ || $mail =~ /(to|from|cc|bcc)\:\s+/i) 
  {
    $mail = '';
  }

  return ($mail);
}

sub isEmail {
  my ($mail) = @_;
  ### RegEx begin
  my $nonascii      = "\x80-\xff"; # Non-ASCII-Chars are not allowed
  
  my $nqtext        = "[^\\\\$nonascii\015\012\"]";
  my $qchar         = "\\\\[^$nonascii]";
  
  my $protocol      = '(?:mailto:)';
  
  my $normuser      = '[a-zA-Z0-9][a-zA-Z0-9_.-]*';
  my $quotedstring  = "\"(?:$nqtext|$qchar)+\"";
  my $user_part     = "(?:$normuser|$quotedstring)";
  
  my $dom_mainpart  = '[a-zA-Z0-9][a-zA-Z0-9._-]*\\.';
  my $dom_subpart   = '(?:[a-zA-Z0-9][a-zA-Z0-9._-]*\\.)*';
  my $dom_tldpart   = '[a-zA-Z]{2,5}';
  my $domain_part   = "$dom_subpart$dom_mainpart$dom_tldpart";
  
  my $MailRegEx        = "$user_part\@$domain_part";
  ### RegEx end

  return $mail =~ /^$MailRegEx$/o;
}
Die Funktion checkMail bekommt die zu prüfenden Mailadresse, entfernt, falls vorhanden, den Zeilenumbruch und prüft anschließend ob in der Mailadresse Zeilenumbrüche oder sendmail-Anweisungen vorhanden sind. Falls etwas zutrifft, wird die Mailadresse geleert.


$Plik: /index.shtml?CONTENT=article_sendmail
$Ostatnia zmiana: 01.01.1970 01:00:00