Bugfix: logger leaked some passwords

This commit is contained in:
the-djmaze 2022-11-01 17:02:49 +01:00
parent c7df5b9a3e
commit c6850c6c3d
5 changed files with 53 additions and 102 deletions

View file

@ -170,10 +170,8 @@ class ImapClient extends \MailSo\Net\NetClient
$sAuthzid = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), Enumerations\ResponseType::CONTINUATION); $sAuthzid = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), Enumerations\ResponseType::CONTINUATION);
$this->sendRaw($SASL->authenticate($sLogin, $sPassword/*, $sAuthzid*/), true); $this->sendRaw($SASL->authenticate($sLogin, $sPassword/*, $sAuthzid*/), true);
$sChallenge = $SASL->challenge($this->getResponseValue($this->getResponse(), Enumerations\ResponseType::CONTINUATION)); $sChallenge = $SASL->challenge($this->getResponseValue($this->getResponse(), Enumerations\ResponseType::CONTINUATION));
if ($this->oLogger) { $this->oLogger && $this->oLogger->AddSecret($sChallenge);
$this->oLogger->AddSecret($sChallenge); $this->sendRaw($sChallenge);
}
$this->sendRaw($sChallenge, true, '*******');
$oResponse = $this->getResponse(); $oResponse = $this->getResponse();
$SASL->verify($this->getResponseValue($oResponse)); $SASL->verify($this->getResponseValue($oResponse));
} }
@ -182,31 +180,26 @@ class ImapClient extends \MailSo\Net\NetClient
$sChallenge = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), Enumerations\ResponseType::CONTINUATION); $sChallenge = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), Enumerations\ResponseType::CONTINUATION);
$this->oLogger->Write('challenge: '.\base64_decode($sChallenge)); $this->oLogger->Write('challenge: '.\base64_decode($sChallenge));
$sAuth = $SASL->authenticate($sLogin, $sPassword, $sChallenge); $sAuth = $SASL->authenticate($sLogin, $sPassword, $sChallenge);
if ($this->oLogger) { $this->oLogger && $this->oLogger->AddSecret($sAuth);
$this->oLogger->AddSecret($sAuth); $this->sendRaw($sAuth);
}
$this->sendRaw($sAuth, true, '*******');
$oResponse = $this->getResponse(); $oResponse = $this->getResponse();
} }
else if ('PLAIN' === $type || 'OAUTHBEARER' === $type) else if ('PLAIN' === $type || 'OAUTHBEARER' === $type)
{ {
$sAuth = $SASL->authenticate($sLogin, $sPassword); $sAuth = $SASL->authenticate($sLogin, $sPassword);
if ($this->oLogger) { $this->oLogger && $this->oLogger->AddSecret($sAuth);
$this->oLogger->AddSecret($sAuth);
}
if ($this->IsSupported('SASL-IR')) { if ($this->IsSupported('SASL-IR')) {
$oResponse = $this->SendRequestGetResponse('AUTHENTICATE', array($type, $sAuth)); $oResponse = $this->SendRequestGetResponse('AUTHENTICATE', array($type, $sAuth));
} else { } else {
$this->SendRequestGetResponse('AUTHENTICATE', array($type)); $this->SendRequestGetResponse('AUTHENTICATE', array($type));
$this->sendRaw($sAuth, true, '*******'); $this->sendRaw($sAuth);
$oResponse = $this->getResponse(); $oResponse = $this->getResponse();
} }
} }
else if ('XOAUTH2' === $type) else if ('XOAUTH2' === $type || 'OAUTHBEARER' === $type)
{ {
$sAuth = $SASL->authenticate($sLogin, $sPassword); $sAuth = $SASL->authenticate($sLogin, $sPassword);
$this->SendRequest('AUTHENTICATE', array($type, $sAuth)); $oResponse = $this->SendRequestGetResponse('AUTHENTICATE', array($type, $sAuth));
$oResponse = $this->getResponse();
$oR = $oResponse->getLast(); $oR = $oResponse->getLast();
if ($oR && Enumerations\ResponseType::CONTINUATION === $oR->ResponseType) { if ($oR && Enumerations\ResponseType::CONTINUATION === $oR->ResponseType) {
if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1])) { if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1])) {
@ -223,19 +216,14 @@ class ImapClient extends \MailSo\Net\NetClient
$this->sendRaw($SASL->authenticate($sLogin, $sPassword, $sB64), true); $this->sendRaw($SASL->authenticate($sLogin, $sPassword, $sB64), true);
$this->getResponse(); $this->getResponse();
$sPass = $SASL->challenge(''/*UGFzc3dvcmQ6*/); $sPass = $SASL->challenge(''/*UGFzc3dvcmQ6*/);
if ($this->oLogger) { $this->oLogger && $this->oLogger->AddSecret($sPass);
$this->oLogger->AddSecret($sPass); $this->sendRaw($sPass);
}
$this->sendRaw($sPass, true, '*******');
$oResponse = $this->getResponse(); $oResponse = $this->getResponse();
} }
else else
{ {
$sPassword = $this->EscapeString(\mb_convert_encoding($sPassword, 'ISO-8859-1', 'UTF-8')); $sPassword = $this->EscapeString(\mb_convert_encoding($sPassword, 'ISO-8859-1', 'UTF-8'));
if ($this->oLogger) $this->oLogger && $this->oLogger->AddSecret($sPassword);
{
$this->oLogger->AddSecret($sPassword);
}
$oResponse = $this->SendRequestGetResponse('LOGIN', $oResponse = $this->SendRequestGetResponse('LOGIN',
array( array(
$this->EscapeString($sLogin), $this->EscapeString($sLogin),
@ -425,11 +413,8 @@ class ImapClient extends \MailSo\Net\NetClient
public function SendRequest(string $sCommand, array $aParams = array(), bool $bBreakOnLiteral = false) : string public function SendRequest(string $sCommand, array $aParams = array(), bool $bBreakOnLiteral = false) : string
{ {
$sCommand = \trim($sCommand); $sCommand = \trim($sCommand);
if (!\strlen($sCommand)) if (!\strlen($sCommand)) {
{ $this->writeLogException(new \InvalidArgumentException, \LOG_ERR, true);
$this->writeLogException(
new \InvalidArgumentException,
\LOG_ERR, true);
} }
$this->IsConnected(true); $this->IsConnected(true);
@ -438,42 +423,20 @@ class ImapClient extends \MailSo\Net\NetClient
$sRealCommand = $sTag.' '.$sCommand.$this->prepareParamLine($aParams); $sRealCommand = $sTag.' '.$sCommand.$this->prepareParamLine($aParams);
$sFakeCommand = '';
if ($aFakeParams = $this->secureRequestParams($sCommand, $aParams)) {
$sFakeCommand = $sTag.' '.$sCommand.$this->prepareParamLine($aFakeParams);
}
// $this->lastCommand = $sFakeCommand ?: $sRealCommand;
$this->aTagTimeouts[$sTag] = \microtime(true); $this->aTagTimeouts[$sTag] = \microtime(true);
if ($bBreakOnLiteral && !\preg_match('/\d\+\}\r\n/', $sRealCommand)) if ($bBreakOnLiteral && !\preg_match('/\d\+\}\r\n/', $sRealCommand)) {
{
$iPos = \strpos($sRealCommand, "}\r\n"); $iPos = \strpos($sRealCommand, "}\r\n");
if (false !== $iPos) if (false !== $iPos) {
{ $this->sendRaw(\substr($sRealCommand, 0, $iPos + 1));
$iFakePos = \strpos($sFakeCommand, "}\r\n");
$this->sendRaw(\substr($sRealCommand, 0, $iPos + 1), true,
false !== $iFakePos ? \substr($sFakeCommand, 0, $iFakePos + 3) : '');
return \substr($sRealCommand, $iPos + 3); return \substr($sRealCommand, $iPos + 3);
} }
} }
$this->sendRaw($sRealCommand, true, $sFakeCommand); $this->sendRaw($sRealCommand);
return ''; return '';
} }
protected function secureRequestParams(string $sCommand, array $aParams) : ?array
{
if ('LOGIN' === $sCommand && isset($aParams[1])) {
$aParams[1] = '"********"';
return $aParams;
}
return null;
}
/** /**
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @throws \MailSo\RuntimeException * @throws \MailSo\RuntimeException

View file

@ -66,8 +66,9 @@ class Logger extends \SplFixedArray
public function AddSecret(string $sWord) : void public function AddSecret(string $sWord) : void
{ {
$sWord = \strlen(\trim($sWord)); // $this->bShowSecrets && $this->Write("AddSecret '{$sWord}'", \LOG_INFO, '', false);
if ($sWord) { $sWord = \trim($sWord);
if (\strlen($sWord)) {
$this->aSecretWords[] = $sWord; $this->aSecretWords[] = $sWord;
$this->aSecretWords = \array_unique($this->aSecretWords); $this->aSecretWords = \array_unique($this->aSecretWords);
} }
@ -165,7 +166,7 @@ class Logger extends \SplFixedArray
$this->bUsed = true; $this->bUsed = true;
if ($bSearchSecretWords && !$this->bShowSecrets && \count($this->aSecretWords)) if ($bSearchSecretWords && !$this->bShowSecrets && $this->aSecretWords)
{ {
$sDesc = \str_replace($this->aSecretWords, '*******', $sDesc); $sDesc = \str_replace($this->aSecretWords, '*******', $sDesc);
} }

View file

@ -160,8 +160,7 @@ abstract class NetClient
} }
$this->iStartConnectTime = \microtime(true); $this->iStartConnectTime = \microtime(true);
$this->writeLog('Start connection to "'.$this->sConnectedHost.':'.$this->iConnectedPort.'"', $this->writeLog('Start connection to "'.$this->sConnectedHost.':'.$this->iConnectedPort.'"');
\LOG_INFO);
$aStreamContextSettings = array( $aStreamContextSettings = array(
'ssl' => $oSettings->ssl 'ssl' => $oSettings->ssl
@ -186,8 +185,7 @@ abstract class NetClient
\restore_error_handler(); \restore_error_handler();
$this->writeLog('Connect ('.($this->rConnect ? 'success' : 'failed').')', $this->writeLog('Connect ('.($this->rConnect ? 'success' : 'failed').')');
\LOG_INFO);
if (!$this->rConnect) if (!$this->rConnect)
{ {
@ -253,7 +251,7 @@ abstract class NetClient
$bResult = \fclose($this->rConnect); $bResult = \fclose($this->rConnect);
$this->writeLog('Disconnected from "'.$this->sConnectedHost.':'.$this->iConnectedPort.'" ('. $this->writeLog('Disconnected from "'.$this->sConnectedHost.':'.$this->iConnectedPort.'" ('.
(($bResult) ? 'success' : 'unsuccess').')', \LOG_INFO); (($bResult) ? 'success' : 'unsuccess').')');
if ($this->iStartConnectTime) if ($this->iStartConnectTime)
{ {
@ -301,21 +299,14 @@ abstract class NetClient
*/ */
protected function sendRaw(string $sRaw, bool $bWriteToLog = true, string $sFakeRaw = '') : void protected function sendRaw(string $sRaw, bool $bWriteToLog = true, string $sFakeRaw = '') : void
{ {
if ($this->bUnreadBuffer) if ($this->bUnreadBuffer) {
{
$this->writeLogException(new Exceptions\SocketUnreadBufferException, \LOG_ERR, true); $this->writeLogException(new Exceptions\SocketUnreadBufferException, \LOG_ERR, true);
} }
$bFake = \strlen($sFakeRaw);
$sRaw .= "\r\n"; $sRaw .= "\r\n";
if ($this->oLogger && $this->oLogger->ShowSecrets()) $bFake = \strlen($sFakeRaw) && $this->oLogger && !$this->oLogger->ShowSecrets();
{ if ($bFake) {
$bFake = false;
}
if ($bFake)
{
$sFakeRaw .= "\r\n"; $sFakeRaw .= "\r\n";
} }
@ -327,7 +318,7 @@ abstract class NetClient
} }
else if ($bWriteToLog) else if ($bWriteToLog)
{ {
$this->writeLogWithCrlf('> '.($bFake ? $sFakeRaw : $sRaw), \LOG_INFO); $this->writeLogWithCrlf('> '.($bFake ? $sFakeRaw : $sRaw));
} }
} }
@ -373,8 +364,7 @@ abstract class NetClient
} }
else else
{ {
$this->writeLog('Stream Meta: '. $this->writeLog('Stream Meta: '.\print_r($aSocketStatus, true), \LOG_ERR);
\print_r($aSocketStatus, true), \LOG_ERR);
$this->writeLogException( $this->writeLogException(
new Exceptions\SocketReadException, new Exceptions\SocketReadException,
@ -389,36 +379,31 @@ abstract class NetClient
$iLimit = 5000; // 5KB $iLimit = 5000; // 5KB
if ($iLimit < $iReadedLen) if ($iLimit < $iReadedLen)
{ {
$this->writeLogWithCrlf('[cutted:'.$iReadedLen.'] < '.\substr($this->sResponseBuffer, 0, $iLimit).'...', $this->writeLogWithCrlf('[cutted:'.$iReadedLen.'] < '.\substr($this->sResponseBuffer, 0, $iLimit).'...');
\LOG_INFO);
} }
else else
{ {
$this->writeLogWithCrlf('< '.$this->sResponseBuffer, //.' ['.$iReadedLen.']', // $this->writeLogWithCrlf('< '.$this->sResponseBuffer, //.' ['.$iReadedLen.']',
\LOG_INFO); $this->writeLogWithCrlf('< '.$this->sResponseBuffer);
} }
} }
else else
{ {
$this->writeLog('Received '.$iReadedLen.'/'.$iReadLen.' bytes.', $this->writeLog('Received '.$iReadedLen.'/'.$iReadLen.' bytes.');
\LOG_INFO);
} }
} }
} }
abstract function getLogName() : string; abstract function getLogName() : string;
protected function writeLog(string $sDesc, int $iDescType = \LOG_INFO, bool $bDiplayCrLf = false) : void protected function writeLog(string $sDesc, int $iDescType = \LOG_INFO) : void
{ {
if ($this->oLogger) $this->oLogger && $this->oLogger->Write($sDesc, $iDescType, $this->getLogName());
{
$this->oLogger->Write($sDesc, $iDescType, $this->getLogName(), true, $bDiplayCrLf);
}
} }
protected function writeLogWithCrlf(string $sDesc, int $iDescType = \LOG_INFO) : void protected function writeLogWithCrlf(string $sDesc) : void
{ {
$this->writeLog($sDesc, $iDescType, true); $this->oLogger && $this->oLogger->Write($sDesc, \LOG_INFO, $this->getLogName(), true, true);
} }
protected function writeLogException(\Throwable $oException, protected function writeLogException(\Throwable $oException,

View file

@ -143,10 +143,8 @@ class ManageSieveClient extends \MailSo\Net\NetClient
$sAuthzid = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION); $sAuthzid = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION);
$this->sendRaw($SASL->authenticate($sLogin, $sPassword/*, $sAuthzid* /), true); $this->sendRaw($SASL->authenticate($sLogin, $sPassword/*, $sAuthzid* /), true);
$sChallenge = $SASL->challenge($this->getResponseValue($this->getResponse(), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION)); $sChallenge = $SASL->challenge($this->getResponseValue($this->getResponse(), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION));
if ($this->oLogger) { $this->oLogger && $this->oLogger->AddSecret($sChallenge);
$this->oLogger->AddSecret($sChallenge); $this->sendRaw($sChallenge);
}
$this->sendRaw($sChallenge, true, '*******');
$oResponse = $this->getResponse(); $oResponse = $this->getResponse();
$SASL->verify($this->getResponseValue($oResponse)); $SASL->verify($this->getResponseValue($oResponse));
*/ */
@ -154,13 +152,11 @@ class ManageSieveClient extends \MailSo\Net\NetClient
else if ('PLAIN' === $type || 'OAUTHBEARER' === $type || 'XOAUTH2' === $type) else if ('PLAIN' === $type || 'OAUTHBEARER' === $type || 'XOAUTH2' === $type)
{ {
$sAuth = $SASL->authenticate($sLogin, $sPassword, $sLoginAuthKey); $sAuth = $SASL->authenticate($sLogin, $sPassword, $sLoginAuthKey);
$this->oLogger && $this->oLogger->AddSecret($sAuth);
if ($aCredentials['InitialAuthPlain']) if ($aCredentials['InitialAuthPlain']) {
{
$this->sendRaw("AUTHENTICATE \"{$type}\" \"{$sAuth}\""); $this->sendRaw("AUTHENTICATE \"{$type}\" \"{$sAuth}\"");
} } else {
else
{
$this->sendRaw("AUTHENTICATE \"{$type}\" {".\strlen($sAuth).'+}'); $this->sendRaw("AUTHENTICATE \"{$type}\" {".\strlen($sAuth).'+}');
$this->sendRaw($sAuth); $this->sendRaw($sAuth);
} }
@ -174,6 +170,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient
{ {
$sLogin = $SASL->authenticate($sLogin, $sPassword); $sLogin = $SASL->authenticate($sLogin, $sPassword);
$sPassword = $SASL->challenge(''); $sPassword = $SASL->challenge('');
$this->oLogger && $this->oLogger->AddSecret($sPassword);
$this->sendRaw('AUTHENTICATE "LOGIN"'); $this->sendRaw('AUTHENTICATE "LOGIN"');
$this->sendRaw('{'.\strlen($sLogin).'+}'); $this->sendRaw('{'.\strlen($sLogin).'+}');

View file

@ -185,19 +185,24 @@ class SmtpClient extends \MailSo\Net\NetClient
if (0 === \strpos($type, 'SCRAM-')) { if (0 === \strpos($type, 'SCRAM-')) {
// RFC 5802 // RFC 5802
$sResult = $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword, $sResult), 234, ''); $sResult = $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword, $sResult), 234, '');
$sResult = $this->sendRequestWithCheck($SASL->challenge($sResult), 235, '', true); $sChallenge = $SASL->challenge($sResult);
$SASL->verify($sResult); $this->oLogger && $this->oLogger->AddSecret($sChallenge);
$SASL->verify($this->sendRequestWithCheck($sChallenge, 235, '', true));
} else switch ($type) { } else switch ($type) {
// RFC 4616 // RFC 4616
case 'PLAIN': case 'PLAIN':
case 'XOAUTH2': case 'XOAUTH2':
case 'OAUTHBEARER': case 'OAUTHBEARER':
$this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword), 235, '', true); $sAuth = $SASL->authenticate($sLogin, $sPassword);
$this->oLogger && $this->oLogger->AddSecret($sAuth);
$this->sendRequestWithCheck($sAuth, 235, '', true);
break; break;
case 'LOGIN': case 'LOGIN':
$sResult = $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword, $sResult), 334, ''); $sResult = $this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword, $sResult), 334, '');
$this->sendRequestWithCheck($SASL->challenge($sResult), 235, '', true); $sPassword = $SASL->challenge($sResult);
$this->oLogger && $this->oLogger->AddSecret($sPassword);
$this->sendRequestWithCheck($sPassword, 235, '', true);
break; break;
// RFC 2195 // RFC 2195
@ -342,7 +347,7 @@ class SmtpClient extends \MailSo\Net\NetClient
$this->sendRequestWithCheck('DATA', 354); $this->sendRequestWithCheck('DATA', 354);
$this->writeLog('Message data.', \LOG_INFO); $this->writeLog('Message data.');
$this->bRunningCallback = true; $this->bRunningCallback = true;