Hello, i just noticed that Joomla tries to send emails twice when SMTP configuration is set to NONE.
Instead of sending email twice i suggest to use a consitent code which would either validate SMTP certificate or not validate certificate.
The problem is that phpMailer tries to use secure connection even for the localhost which doesn't have a valid certificate by it's nature.
Be checkout JMailer in Joomla 3 + Joomla 4 it is possible to adjust phpMailer behavior by using:
if (empty($this->SMTPOptions)) $this->SMTPOptions = array();
$this->SMTPOptions['ssl'] = array('verify_peer' => false,'verify_peer_name' => false,'allow_self_signed' => true);
$result = parent::send();
within \libraries\src\Mail\Mail.php
the SMTPOptions is picked up by stream_context_create within \libraries\vendor\phpmailer\phpmailer\class.smtp.php
my suggestion is to:
$this->SMTPOptions['ssl'] = array('verify_peer' => true,'verify_peer_name' => true,'allow_self_signed' => true);
maybe a general check for the Host input can be done (or Invalid Cert config can be added to the mail configuration)
if (empty($this->SMTPOptions)) $this->SMTPOptions = array();
$localhosts = array('127.0.0.1', 'localhost', $_SERVER['REMOTE_ADDR'], '::1');
if (in_array($this->Host, $localhosts)) {
//common localhost hosts:
$this->SMTPOptions['ssl'] = array(
'peer_name' => $this->Host,
'CN_match' => $this->Host,
'verify_peer' => false,
'verify_peer_name' => false,
'verify_depth' => 5,
'allow_self_signed' => true
);
}
else
if (filter_var($this->Host, FILTER_VALIDATE_IP)) {
//IP as host
$this->SMTPOptions['ssl'] = array(
'peer_name' => $this->Host,
'CN_match' => $this->Host,
'verify_peer' => false,
'verify_peer_name' => false,
'verify_depth' => 5,
'allow_self_signed' => true
);
}
else
if (empty($this->SMTPSecure)) {
//Security is set to NONE - ignore invalid or self signed cert
$this->SMTPOptions['ssl'] = array(
'peer_name' => $this->Host,
'CN_match' => $this->Host,
'verify_peer' => false,
'verify_peer_name' => false,
'verify_depth' => 5,
'allow_self_signed' => true
);
}
else {
//SMTP Secure is enabled and a normal domain is inputted - request highest level of security:
$this->SMTPOptions['ssl'] = array(
'peer_name' => $this->Host,
'CN_match' => $this->Host,
'verify_peer' => true,
'verify_peer_name' => true,
'verify_depth' => 5,
'allow_self_signed' => true
);
}
$result = parent::send();
I believe that current code in both j3 and j4 is not secure because it doesn't allow to set certificate validation policy strictly and it is possible that it fallbacks to no encryption. Furthermore the current code is not performance optimal because it does at least 2 remote calls to the SMTP server (plus DNS calls) which could be very slow.
please consider some of the code above into j3 or j4 - i don't know how to do the pull requests now and the code needs a bit of discussion and testing.
best regards, stan
Hello, i just noticed that Joomla tries to send emails twice when SMTP configuration is set to NONE.
Where do you see this in code?
hello, double attempt to send emails:
https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/Mail/Mail.php
and here:
https://github.com/joomla/joomla-cms/blob/staging/libraries/src/Mail/Mail.php
inside
function send()
The problem is that phpMailer tries to use secure connection even for the localhost which doesn't have a valid certificate by it's nature.
A wrong assumption to make. Its perfectly valid for a local SMTP server to have a valid certificate.
true, but using TLS and/or STARTTLS when it's disabled in Joomla global config is also bad - in security when you set it to SSL you expect it to go through SSL. if you set it to STARTTLS you expect it to go through STARTTLS and when you set it to NONE it is not accepted to start with SSL or STARTTLS which produces an error because most email servers when hosted on same machine/localhost are not able to provide a valid certificate for DNS resolved "localhost" of 120.0.0.1 which than doesn't match the CN of the certificate.
$this->SMTPOptions['ssl'] = array('verify_peer' => false,'verify_peer_name' => false,'allow_self_signed' => true);
Insecure and bad practice!
this is exactly what joomla does, but even worse - it does not encrypt the email at all once it fails first attempt of sending the email.
so please tell me - what's worse:
my approach is to:
when "SMTP security = None" at joomla global config, make sure to use the above ssl socket config
Absolutely not! That would mean Joomla would never check the certificates of a remote/local mail server.
why would joomla want to check certificates when it's set to None ? i agree that trying to send it encrypted first is a good aproach, but i don't agree on stopping this with invalid certificate and re-trying with non-encrypted email.
I believe that current code in both j3 and j4 is not secure because it doesn't allow to set certificate validation policy strictly
But yet you recommend disabling verification entirely! strange...
yes, for NONE+LOCALHOST it would make sense, for SSL+DOMAIN or STARTTLS+DOMAIN joomla does not really meet what's expected. for NONE+DOMAIN it's always a matter of discussion and will lead to unexpected behavior in not done in transparent way.
best regards, stan
to be more clear with the double attempt:
try
{
// Try sending with default settings
$result = parent::send();
}
throws an exception when using NONE+localhost (because public domain should be rather used with valid certificate path)
then second attempt is done inside catch with
this->SMTPAutoTLS = false;
$result = parent::send();
There is only a "double attempt" If
/Automatically enable TLS encryption if:
//* it's not disabled
//* we have openssl extension
//* we are not already using SSL
//* the server offers STARTTLS
This is by design of phpMailers as per
/**
* Whether to enable TLS encryption automatically if a server supports it,
* even if `SMTPSecure` is not set to 'tls'.
* Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
*
* @var bool
*/
public $SMTPAutoTLS = true;
so please tell me - what's worse:
1 ) sendng unencrypted email to smtp
2) or sending encrypted email to self signed cert of smtp
Firstly, the email is not being sent encrypted. Its ALWAYS being set plain text, just sometimes its sent over a secured TLS tunnel to a server that has provided a valid chained certificate
So, given these 2 options, the second one is drastically worse. If your network/server is compromised, connecting to, and transmitting data to, a server which has an invalid certificate is exponentially worse then sending to a server, which by design, doesnt have a certificate installed.
It is for this reason that web browsers will warn/not connect to your bank if your banks SSL certificate on their website is expired or invalid...
why would joomla want to check certificates when it's set to None
Because, like the docs said:
PHPMailer 5.2.10 introduced opportunistic TLS - if it sees that the server is advertising TLS encryption (after you have connected to the server), it enables encryption automatically, even if you have not set SMTPSecure. This might cause issues if the server is advertising TLS with an invalid certificate, but you can turn it off with $mail->SMTPAutoTLS = false;.
I dont think turning off opportunistic TLS is what Joomla will want to do.
Not my decision though. One for the @joomal/security team to be making.
If you carefully read the source code you will see that phpmailer has this autotls integrated and active per default, this your sentence "what's better no encryption or a unverified server". So phpmailer automatically tries the tls connection. But if this fails we fallback to unencrypted because we do not want to lull the user into a false sense of security. So it's better to fall back to nothing then simulate security. If you really want security then use the proper setting then you only get verified connections and nothing else.
I'm closing this because it's important to have proper encryption then fake encryption.
Thanks for your report and yes maybe we should communicate an unencrypted connection to the user.
Status | New | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2021-05-23 16:37:53 |
Closed_By | ⇒ | HLeithner |
Hello, maybe it would be nice to provide more options within the config same as most email clients do:
this way it is not needed to do the remote call twice, but follow just the config so the security is transparent. my main goal in this subject was to allow untrusted certificate on localhost which now does 2 calls and ends up with cleartext instead of accepting invalid certificate.
As you can see for "NONE" option it is now less secure as it uses unencrypted stream vs it could accept invalid certificate.
best regards, stan
Where do you see this in code?
A wrong assumption to make. Its perfectly valid for a local SMTP server to have a valid certificate.
Insecure and bad practice!
Absolutely not! That would mean Joomla would never check the certificates of a remote/local mail server.
But yet you recommend disabling verification entirely! strange...
@joomla/security