fixes for spam-blocking

This commit is contained in:
paulwer 2024-04-07 16:08:34 +02:00
parent 4ac3289819
commit c1ec89b0a7
4 changed files with 28 additions and 17 deletions

View File

@ -287,7 +287,6 @@ class PostMarkController extends BaseController
$inboundEngine = new InboundMailEngine(); $inboundEngine = new InboundMailEngine();
if ($inboundEngine->isInvalidOrBlocked($input["From"], $input["To"])) { if ($inboundEngine->isInvalidOrBlocked($input["From"], $input["To"])) {
Log::info('Failed: Sender is blocked: ' . $input["From"] . " Recipient: " . $input["To"]);
return response()->json(['message' => 'Blocked.'], 403); return response()->json(['message' => 'Blocked.'], 403);
} }

View File

@ -31,7 +31,7 @@ class ProcessBrevoInboundWebhook implements ShouldQueue
public $tries = 1; public $tries = 1;
private InboundMailEngine $engine = new InboundMailEngine(); private InboundMailEngine $engine;
/** /**
* Create a new job instance. * Create a new job instance.
@ -111,6 +111,7 @@ class ProcessBrevoInboundWebhook implements ShouldQueue
*/ */
public function __construct(private array $input) public function __construct(private array $input)
{ {
$this->engine = new InboundMailEngine();
} }
/** /**
@ -128,8 +129,7 @@ class ProcessBrevoInboundWebhook implements ShouldQueue
// Spam protection // Spam protection
if ($this->engine->isInvalidOrBlocked($this->input["From"]["Address"], $recipient)) { if ($this->engine->isInvalidOrBlocked($this->input["From"]["Address"], $recipient)) {
Log::info('Failed: Sender is blocked: ' . $this->input["From"]["Address"] . " Recipient: " . $recipient); return;
throw new \Error('Sender is blocked');
} }
// match company // match company

View File

@ -29,7 +29,7 @@ class ProcessMailgunInboundWebhook implements ShouldQueue
public $tries = 1; public $tries = 1;
private InboundMailEngine $engine = new InboundMailEngine(); private InboundMailEngine $engine;
/** /**
* Create a new job instance. * Create a new job instance.
@ -37,6 +37,7 @@ class ProcessMailgunInboundWebhook implements ShouldQueue
*/ */
public function __construct(private string $input) public function __construct(private string $input)
{ {
$this->engine = new InboundMailEngine();
} }
/** /**
@ -173,8 +174,7 @@ class ProcessMailgunInboundWebhook implements ShouldQueue
// Spam protection // Spam protection
if ($this->engine->isInvalidOrBlocked($from, $to)) { if ($this->engine->isInvalidOrBlocked($from, $to)) {
Log::info('Failed: Sender is blocked: ' . $from . " Recipient: " . $to); return;
throw new \Error('Sender is blocked');
} }
// match company // match company

View File

@ -39,6 +39,8 @@ class InboundMailEngine
private ?bool $isUnknownRecipent = null; private ?bool $isUnknownRecipent = null;
private array $globalBlacklistDomains = []; private array $globalBlacklistDomains = [];
private array $globalBlacklistSenders = []; private array $globalBlacklistSenders = [];
private array $globalWhitelistDomains = []; // only for global validation, not for allowing to send something into the company, should be used to disabled blocking for mass-senders
private array $globalWhitelistSenders = []; // only for global validation, not for allowing to send something into the company, should be used to disabled blocking for mass-senders
public function __construct() public function __construct()
{ {
} }
@ -70,15 +72,25 @@ class InboundMailEngine
Log::info('E-Mail blocked, because from e-mail has the wrong format: ' . $from); Log::info('E-Mail blocked, because from e-mail has the wrong format: ' . $from);
return true; return true;
} }
if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
Log::info('E-Mail blocked, because to e-mail has the wrong format: ' . $from);
return true;
}
$parts = explode('@', $from); $parts = explode('@', $from);
$domain = array_pop($parts); $domain = array_pop($parts);
// global blacklist // global blacklist
if (in_array($from, $this->globalWhitelistDomains)) {
return false;
}
if (in_array($domain, $this->globalBlacklistDomains)) { if (in_array($domain, $this->globalBlacklistDomains)) {
Log::info('E-Mail blocked, because the domain was found on globalBlocklistDomains: ' . $from); Log::info('E-Mail blocked, because the domain was found on globalBlocklistDomains: ' . $from);
return true; return true;
} }
if (in_array($domain, $this->globalWhitelistSenders)) {
return false;
}
if (in_array($from, $this->globalBlacklistSenders)) { if (in_array($from, $this->globalBlacklistSenders)) {
Log::info('E-Mail blocked, because the email was found on globalBlocklistEmails: ' . $from); Log::info('E-Mail blocked, because the email was found on globalBlocklistEmails: ' . $from);
return true; return true;
@ -89,7 +101,7 @@ class InboundMailEngine
} }
// sender occured in more than 500 emails in the last 12 hours // sender occured in more than 500 emails in the last 12 hours
$senderMailCountTotal = Cache::get('inboundMailSender:' . $from, 0); $senderMailCountTotal = Cache::get('inboundMailCountSender:' . $from, 0);
if ($senderMailCountTotal >= 5000) { if ($senderMailCountTotal >= 5000) {
Log::info('E-Mail blocked permanent, because the sender sended more than ' . $senderMailCountTotal . ' emails in the last 12 hours: ' . $from); Log::info('E-Mail blocked permanent, because the sender sended more than ' . $senderMailCountTotal . ' emails in the last 12 hours: ' . $from);
$this->blockSender($from); $this->blockSender($from);
@ -103,7 +115,7 @@ class InboundMailEngine
} }
// sender sended more than 50 emails to the wrong mailbox in the last 6 hours // sender sended more than 50 emails to the wrong mailbox in the last 6 hours
$senderMailCountUnknownRecipent = Cache::get('inboundMailSenderUnknownRecipent:' . $from, 0); $senderMailCountUnknownRecipent = Cache::get('inboundMailCountSenderUnknownRecipent:' . $from, 0);
if ($senderMailCountUnknownRecipent >= 50) { if ($senderMailCountUnknownRecipent >= 50) {
Log::info('E-Mail blocked, because the sender sended more than ' . $senderMailCountUnknownRecipent . ' emails to the wrong mailbox in the last 6 hours: ' . $from); Log::info('E-Mail blocked, because the sender sended more than ' . $senderMailCountUnknownRecipent . ' emails to the wrong mailbox in the last 6 hours: ' . $from);
$this->saveMeta($from, $to); $this->saveMeta($from, $to);
@ -111,8 +123,8 @@ class InboundMailEngine
} }
// wrong recipent occurs in more than 100 emails in the last 12 hours, so the processing is blocked // wrong recipent occurs in more than 100 emails in the last 12 hours, so the processing is blocked
$mailCountUnknownRecipent = Cache::get('inboundMailUnknownRecipent:' . $to, 0); // @turbo124 maybe use many to save resources in case of spam with multiple to addresses each time $mailCountUnknownRecipent = Cache::get('inboundMailCountUnknownRecipent:' . $to, 0); // @turbo124 maybe use many to save resources in case of spam with multiple to addresses each time
if ($mailCountUnknownRecipent >= 100) { if ($mailCountUnknownRecipent >= 200) {
Log::info('E-Mail blocked, because anyone sended more than ' . $mailCountUnknownRecipent . ' emails to the wrong mailbox in the last 12 hours. Current sender was blocked as well: ' . $from); Log::info('E-Mail blocked, because anyone sended more than ' . $mailCountUnknownRecipent . ' emails to the wrong mailbox in the last 12 hours. Current sender was blocked as well: ' . $from);
$this->blockSender($from); $this->blockSender($from);
$this->saveMeta($from, $to); $this->saveMeta($from, $to);
@ -131,15 +143,15 @@ class InboundMailEngine
public function saveMeta(string $from, string $to, bool $isUnknownRecipent = false) public function saveMeta(string $from, string $to, bool $isUnknownRecipent = false)
{ {
// save cache // save cache
Cache::add('inboundMailSender:' . $from, 0, now()->addHours(12)); Cache::add('inboundMailCountSender:' . $from, 0, now()->addHours(12));
Cache::increment('inboundMailSender:' . $from); Cache::increment('inboundMailCountSender:' . $from);
if ($isUnknownRecipent) { if ($isUnknownRecipent) {
Cache::add('inboundMailSenderUnknownRecipent:' . $from, 0, now()->addHours(6)); Cache::add('inboundMailCountSenderUnknownRecipent:' . $from, 0, now()->addHours(6));
Cache::increment('inboundMailSenderUnknownRecipent:' . $from); // we save the sender, to may block him Cache::increment('inboundMailCountSenderUnknownRecipent:' . $from); // we save the sender, to may block him
Cache::add('inboundMailUnknownRecipent:' . $to, 0, now()->addHours(12)); Cache::add('inboundMailCountUnknownRecipent:' . $to, 0, now()->addHours(12));
Cache::increment('inboundMailUnknownRecipent:' . $to); // we save the sender, to may block him Cache::increment('inboundMailCountUnknownRecipent:' . $to); // we save the sender, to may block him
} }
} }