@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Prevent inbound processing of the "void/placeholder" address and other reserved addresses

Summary:
Depends on D19952. Ref T13222. Never process mail targets if they match:

- The "default" address which we send mail "From".
- The "void" address which we use as a placholder "To" when we only have "CC" addresses.
- Any address from a list of reserved/administrative names.

The first two prevent loops. The third one prevents abuse.

There's a reasonably well-annotated list of reservations and reasons here:

https://webmasters.stackexchange.com/questions/104811/is-there-any-list-of-email-addresses-reserved-because-of-security-concerns-for-a

Stuff like `support@` seems fine; stuff like `ssladmin@` might let you get SSL certs issued for a domain you don't control.

Also, forbid users from creating application emails with these reserved addresses.

Finally, build the default and void addresses somewhat more cleverly.

Test Plan: Added unit tests, tried to configured reserved addresses, hit the default/void cases manually with `bin/mail receive-test`.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: olexiy.myronenko

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D19953

+112 -9
+1 -4
src/applications/config/option/PhabricatorMetaMTAConfigOptions.php
··· 191 191 $this->newOption('cluster.mailers', 'cluster.mailers', array()) 192 192 ->setHidden(true) 193 193 ->setDescription($mailers_description), 194 - $this->newOption( 195 - 'metamta.default-address', 196 - 'string', 197 - 'noreply@phabricator.example.com') 194 + $this->newOption('metamta.default-address', 'string', null) 198 195 ->setDescription(pht('Default "From" address.')), 199 196 $this->newOption( 200 197 'metamta.one-mail-per-recipient',
+10
src/applications/metamta/editor/PhabricatorMetaMTAApplicationEmailEditor.php
··· 104 104 pht('Invalid'), 105 105 pht('Email address is not formatted properly.')); 106 106 } 107 + 108 + $address = new PhutilEmailAddress($email); 109 + if (PhabricatorMailUtil::isReservedAddress($address)) { 110 + $errors[] = new PhabricatorApplicationTransactionValidationError( 111 + $type, 112 + pht('Reserved'), 113 + pht( 114 + 'This email address is reserved. Choose a different '. 115 + 'address.')); 116 + } 107 117 } 108 118 109 119 $missing = $this->validateIsEmptyTextField(
+26
src/applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php
··· 41 41 } 42 42 } 43 43 44 + public function testReservedAddresses() { 45 + $default_address = id(new PhabricatorMetaMTAMail()) 46 + ->newDefaultEmailAddress(); 47 + 48 + $void_address = id(new PhabricatorMetaMTAMail()) 49 + ->newVoidEmailAddress(); 50 + 51 + $map = array( 52 + 'alincoln@example.com' => false, 53 + 'sysadmin@example.com' => true, 54 + 'hostmaster@example.com' => true, 55 + '"Walter Ebmaster" <webmaster@example.com>' => true, 56 + (string)$default_address => true, 57 + (string)$void_address => true, 58 + ); 59 + 60 + foreach ($map as $raw_address => $expect) { 61 + $address = new PhutilEmailAddress($raw_address); 62 + 63 + $this->assertEqual( 64 + $expect, 65 + PhabricatorMailUtil::isReservedAddress($address), 66 + pht('Reserved: %s', $raw_address)); 67 + } 68 + } 69 + 44 70 }
+18 -3
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 713 713 $actors = $this->loadAllActors(); 714 714 $deliverable_actors = $this->filterDeliverableActors($actors); 715 715 716 - $default_from = PhabricatorEnv::getEnvConfig('metamta.default-address'); 716 + $default_from = (string)$this->newDefaultEmailAddress(); 717 717 if (empty($params['from'])) { 718 718 $mailer->setFrom($default_from); 719 719 } ··· 1463 1463 } 1464 1464 1465 1465 private function newMailDomain() { 1466 + $domain = PhabricatorEnv::getEnvConfig('metamta.reply-handler-domain'); 1467 + if (strlen($domain)) { 1468 + return $domain; 1469 + } 1470 + 1466 1471 $install_uri = PhabricatorEnv::getURI('/'); 1467 1472 $install_uri = new PhutilURI($install_uri); 1468 1473 1469 1474 return $install_uri->getDomain(); 1470 1475 } 1471 1476 1472 - public function newVoidEmailAddress() { 1477 + public function newDefaultEmailAddress() { 1478 + $raw_address = PhabricatorEnv::getEnvConfig('metamta.default-address'); 1479 + if (strlen($raw_address)) { 1480 + return new PhutilEmailAddress($raw_address); 1481 + } 1482 + 1473 1483 $domain = $this->newMailDomain(); 1474 - $address = "void-recipient@{$domain}"; 1484 + $address = "noreply@{$domain}"; 1485 + 1475 1486 return new PhutilEmailAddress($address); 1487 + } 1488 + 1489 + public function newVoidEmailAddress() { 1490 + return $this->newDefaultEmailAddress(); 1476 1491 } 1477 1492 1478 1493
+11 -2
src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php
··· 161 161 ->setFilterMethod('isEnabled') 162 162 ->execute(); 163 163 164 + $targets = $this->newTargetAddresses(); 165 + foreach ($targets as $key => $target) { 166 + // Never accept any reserved address as a mail target. This prevents 167 + // security issues around "hostmaster@" and bad behavior with 168 + // "noreply@". 169 + if (PhabricatorMailUtil::isReservedAddress($target)) { 170 + unset($targets[$key]); 171 + continue; 172 + } 173 + } 174 + 164 175 $any_accepted = false; 165 176 $receiver_exception = null; 166 - 167 - $targets = $this->newTargetAddresses(); 168 177 foreach ($receivers as $receiver) { 169 178 $receiver = id(clone $receiver) 170 179 ->setViewer($viewer);
+46
src/applications/metamta/util/PhabricatorMailUtil.php
··· 62 62 return ($u->getAddress() === $v->getAddress()); 63 63 } 64 64 65 + public static function isReservedAddress(PhutilEmailAddress $address) { 66 + $address = self::normalizeAddress($address); 67 + $local = $address->getLocalPart(); 68 + 69 + $reserved = array( 70 + 'admin', 71 + 'administrator', 72 + 'hostmaster', 73 + 'list', 74 + 'list-request', 75 + 'majordomo', 76 + 'postmaster', 77 + 'root', 78 + 'ssl-admin', 79 + 'ssladmin', 80 + 'ssladministrator', 81 + 'sslwebmaster', 82 + 'sysadmin', 83 + 'uucp', 84 + 'webmaster', 85 + 86 + 'noreply', 87 + 'no-reply', 88 + ); 89 + 90 + $reserved = array_fuse($reserved); 91 + 92 + if (isset($reserved[$local])) { 93 + return true; 94 + } 95 + 96 + $default_address = id(new PhabricatorMetaMTAMail()) 97 + ->newDefaultEmailAddress(); 98 + if (self::matchAddresses($address, $default_address)) { 99 + return true; 100 + } 101 + 102 + $void_address = id(new PhabricatorMetaMTAMail()) 103 + ->newVoidEmailAddress(); 104 + if (self::matchAddresses($address, $void_address)) { 105 + return true; 106 + } 107 + 108 + return false; 109 + } 110 + 65 111 }