mirror of https://github.com/MISP/MISP
Merge pull request #9466 from JakubOnderka/logging
fix: [internal] ECS: Invalid port checking in metadatapull/9481/head
commit
7309e1218c
|
@ -444,8 +444,7 @@ class AppController extends Controller
|
|||
// User found in the db, add the user info to the session
|
||||
if (Configure::read('MISP.log_auth')) {
|
||||
$this->loadModel('Log');
|
||||
$this->UserLoginProfile = ClassRegistry::init('UserLoginProfile');
|
||||
$change = $this->UserLoginProfile->_getUserProfile();
|
||||
$change = $this->User->UserLoginProfile->_getUserProfile();
|
||||
$change['http_method'] = $_SERVER['REQUEST_METHOD'];
|
||||
$change['target'] = $this->request->here;
|
||||
$this->Log->createLogEntry(
|
||||
|
@ -568,8 +567,7 @@ class AppController extends Controller
|
|||
if ($user['disabled'] || (isset($user['logged_by_authkey']) && $user['logged_by_authkey']) && !$this->User->checkIfUserIsValid($user)) {
|
||||
if ($this->_shouldLog('disabled:' . $user['id'])) {
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$this->UserLoginProfile = ClassRegistry::init('UserLoginProfile');
|
||||
$change = $this->UserLoginProfile->_getUserProfile();
|
||||
$change = $this->User->UserLoginProfile->_getUserProfile();
|
||||
$this->Log->createLogEntry($user, 'auth_fail', 'User', $user['id'], 'Login attempt by disabled user.', json_encode($change));
|
||||
}
|
||||
|
||||
|
@ -589,9 +587,9 @@ class AppController extends Controller
|
|||
if ($user['authkey_expiration'] < $time) {
|
||||
if ($this->_shouldLog('expired:' . $user['authkey_id'])) {
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$this->UserLoginProfile = ClassRegistry::init('UserLoginProfile');
|
||||
$change = $this->UserLoginProfile->_getUserProfile();
|
||||
$this->Log->createLogEntry($user, 'auth_fail', 'User', $user['id'], "Login attempt by expired auth key {$user['authkey_id']}.", json_encode($change)); }
|
||||
$change = $this->User->UserLoginProfile->_getUserProfile();
|
||||
$this->Log->createLogEntry($user, 'auth_fail', 'User', $user['id'], "Login attempt by expired auth key {$user['authkey_id']}.", json_encode($change));
|
||||
}
|
||||
$this->Auth->logout();
|
||||
throw new ForbiddenException('Auth key is expired');
|
||||
}
|
||||
|
@ -608,9 +606,9 @@ class AppController extends Controller
|
|||
if (!$cidrTool->contains($remoteIp)) {
|
||||
if ($this->_shouldLog('not_allowed_ip:' . $user['authkey_id'] . ':' . $remoteIp)) {
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$this->UserLoginProfile = ClassRegistry::init('UserLoginProfile');
|
||||
$change = $this->UserLoginProfile->_getUserProfile();
|
||||
$this->Log->createLogEntry($user, 'auth_fail', 'User', $user['id'], "Login attempt from not allowed IP address {$remoteIp} for auth key {$user['authkey_id']}.", json_encode($change)); }
|
||||
$change = $this->User->UserLoginProfile->_getUserProfile();
|
||||
$this->Log->createLogEntry($user, 'auth_fail', 'User', $user['id'], "Login attempt from not allowed IP address {$remoteIp} for auth key {$user['authkey_id']}.", json_encode($change));
|
||||
}
|
||||
$this->Auth->logout();
|
||||
throw new ForbiddenException('It is not possible to use this Auth key from your IP address');
|
||||
}
|
||||
|
@ -1153,8 +1151,7 @@ class AppController extends Controller
|
|||
$this->Session->write(AuthComponent::$sessionKey, $user['User']);
|
||||
if (Configure::read('MISP.log_auth')) {
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$this->UserLoginProfile = ClassRegistry::init('UserLoginProfile');
|
||||
$change = $this->UserLoginProfile->_getUserProfile();
|
||||
$change = $this->User->UserLoginProfile->_getUserProfile();
|
||||
$change['http_method'] = $_SERVER['REQUEST_METHOD'];
|
||||
$change['target'] = $this->request->here;
|
||||
$this->Log->createLogEntry(
|
||||
|
@ -1170,8 +1167,7 @@ class AppController extends Controller
|
|||
// User not authenticated correctly
|
||||
// reset the session information
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$this->UserLoginProfile = ClassRegistry::init('UserLoginProfile');
|
||||
$change = $this->UserLoginProfile->_getUserProfile();
|
||||
$change = $this->User->UserLoginProfile->_getUserProfile();
|
||||
$this->Log->createLogEntry(
|
||||
'SYSTEM',
|
||||
'auth_fail',
|
||||
|
@ -1438,14 +1434,13 @@ class AppController extends Controller
|
|||
|
||||
/**
|
||||
* @return string|null
|
||||
* @deprecated Use User::_remoteIp() instead
|
||||
*/
|
||||
protected function _remoteIp()
|
||||
{
|
||||
$ipHeader = Configure::read('MISP.log_client_ip_header') ?: 'REMOTE_ADDR';
|
||||
return isset($_SERVER[$ipHeader]) ? trim($_SERVER[$ipHeader]) : $_SERVER['REMOTE_ADDR'];
|
||||
return $this->User->_remoteIp();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool Returns true if the same log defined by $key was not stored in last hour
|
||||
|
|
|
@ -4022,9 +4022,9 @@ class AppModel extends Model
|
|||
*/
|
||||
public function _remoteIp()
|
||||
{
|
||||
$ipHeader = Configure::read('MISP.log_client_ip_header') ?: null;
|
||||
if ($ipHeader && isset($_SERVER[$ipHeader])) {
|
||||
return trim($_SERVER[$ipHeader]);
|
||||
$clientIpHeader = Configure::read('MISP.log_client_ip_header');
|
||||
if ($clientIpHeader && isset($_SERVER[$clientIpHeader])) {
|
||||
return trim($_SERVER[$clientIpHeader]);
|
||||
}
|
||||
return $_SERVER['REMOTE_ADDR'] ?? null;
|
||||
}
|
||||
|
|
|
@ -439,24 +439,25 @@ class Log extends AppModel
|
|||
return;
|
||||
}
|
||||
|
||||
$action = $data['Log']['action'];
|
||||
$type = 'info';
|
||||
if (isset($action)) {
|
||||
if (in_array($action, self::ERROR_ACTIONS, true)) {
|
||||
$type = 'error';
|
||||
} else if (in_array($action, self::WARNING_ACTIONS, true)) {
|
||||
$type = 'warning';
|
||||
}
|
||||
$log = $data['Log'];
|
||||
|
||||
$action = $log['action'];
|
||||
if (in_array($action, self::ERROR_ACTIONS, true)) {
|
||||
$type = 'error';
|
||||
} else if (in_array($action, self::WARNING_ACTIONS, true)) {
|
||||
$type = 'warning';
|
||||
} else {
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
$message = $action;
|
||||
if (!empty($data['Log']['title'])) {
|
||||
$message .= " -- {$data['Log']['title']}";
|
||||
if (!empty($log['title'])) {
|
||||
$message .= " -- {$log['title']}";
|
||||
}
|
||||
if (!empty($data['Log']['description'])) {
|
||||
$message .= " -- {$data['Log']['description']}";
|
||||
} else if (!empty($data['Log']['change'])) {
|
||||
$message .= " -- " . JsonTool::encode($data['Log']['change']);
|
||||
if (!empty($log['description'])) {
|
||||
$message .= " -- {$log['description']}";
|
||||
} else if (!empty($log['change'])) {
|
||||
$message .= " -- " . (is_string($log['change']) ? $log['change'] : JsonTool::encode($log['change']));
|
||||
}
|
||||
|
||||
EcsLog::writeApplicationLog($type, $action, $message);
|
||||
|
|
|
@ -127,7 +127,7 @@ class UserLoginProfile extends AppModel
|
|||
$data = array_merge($data, JsonTool::decode($logEntry['change']) ?? []);
|
||||
$data['ip'] = $logEntry['ip'];
|
||||
$data['timestamp'] = $logEntry['created'];
|
||||
if ($data['user_agent'] == "") {
|
||||
if ($data['user_agent'] === "") {
|
||||
return false;
|
||||
}
|
||||
return $data;
|
||||
|
@ -141,48 +141,48 @@ class UserLoginProfile extends AppModel
|
|||
if (!$a['ua_browser'])
|
||||
return false;
|
||||
// really similar session, from same browser, region, but different IP
|
||||
if ($a['ua_browser'] == $b['ua_browser'] &&
|
||||
$a['ua_platform'] == $b['ua_platform'] &&
|
||||
$a['accept_lang'] == $b['accept_lang'] &&
|
||||
$a['geoip'] == $b['geoip']) {
|
||||
if ($a['ua_browser'] === $b['ua_browser'] &&
|
||||
$a['ua_platform'] === $b['ua_platform'] &&
|
||||
$a['accept_lang'] === $b['accept_lang'] &&
|
||||
$a['geoip'] === $b['geoip']) {
|
||||
return true;
|
||||
}
|
||||
// similar browser pattern, OS and region
|
||||
if ($a['ua_pattern'] == $b['ua_pattern'] &&
|
||||
$a['ua_platform'] == $b['ua_platform'] &&
|
||||
$a['accept_lang'] == $b['accept_lang'] &&
|
||||
$a['geoip'] == $b['geoip']) {
|
||||
if ($a['ua_pattern'] === $b['ua_pattern'] &&
|
||||
$a['ua_platform'] === $b['ua_platform'] &&
|
||||
$a['accept_lang'] === $b['accept_lang'] &&
|
||||
$a['geoip'] === $b['geoip']) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function _isIdentical($a, $b)
|
||||
public function _isIdentical(array $a, array $b)
|
||||
{
|
||||
if ($a['ip'] == $b['ip'] &&
|
||||
$a['ua_browser'] == $b['ua_browser'] &&
|
||||
$a['ua_platform'] == $b['ua_platform'] &&
|
||||
$a['accept_lang'] == $b['accept_lang'] &&
|
||||
$a['geoip'] == $b['geoip']) {
|
||||
if ($a['ip'] === $b['ip'] &&
|
||||
$a['ua_browser'] === $b['ua_browser'] &&
|
||||
$a['ua_platform'] === $b['ua_platform'] &&
|
||||
$a['accept_lang'] === $b['accept_lang'] &&
|
||||
$a['geoip'] === $b['geoip']) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function _getTrustStatus($userProfileToCheck, $user_id = null)
|
||||
public function _getTrustStatus(array $userProfileToCheck, $userId = null)
|
||||
{
|
||||
if (!$user_id) {
|
||||
$user_id = AuthComponent::user('id');
|
||||
if (!$userId) {
|
||||
$userId = AuthComponent::user('id');
|
||||
}
|
||||
// load Singleton / caching
|
||||
if (!isset($this->knownUserProfiles[$user_id])) {
|
||||
$this->knownUserProfiles[$user_id] = $this->find('all', [
|
||||
'conditions' => ['UserLoginProfile.user_id' => $user_id],
|
||||
'recursive' => 0]
|
||||
);
|
||||
if (!isset($this->knownUserProfiles[$userId])) {
|
||||
$this->knownUserProfiles[$userId] = $this->find('all', [
|
||||
'conditions' => ['UserLoginProfile.user_id' => $userId],
|
||||
'recursive' => 0
|
||||
]);
|
||||
}
|
||||
// perform check on all entries, and stop when check OK
|
||||
foreach ($this->knownUserProfiles[$user_id] as $knownUserProfile) {
|
||||
foreach ($this->knownUserProfiles[$userId] as $knownUserProfile) {
|
||||
// when it is the same
|
||||
if ($this->_isIdentical($knownUserProfile['UserLoginProfile'], $userProfileToCheck)) {
|
||||
return $knownUserProfile['UserLoginProfile']['status'];
|
||||
|
@ -240,12 +240,7 @@ class UserLoginProfile extends AppModel
|
|||
$body->set('misp_org', Configure::read('MISP.org'));
|
||||
$body->set('date_time', $date_time);
|
||||
// Fetch user that contains also PGP or S/MIME keys for e-mail encryption
|
||||
$result = $this->User->sendEmail($user, $body, false, "[" . Configure::read('MISP.org') . " MISP] New sign in.");
|
||||
if ($result) {
|
||||
// all is well, email sent to user
|
||||
} else {
|
||||
// email flow system already logs errors
|
||||
}
|
||||
$this->User->sendEmail($user, $body, false, "[" . Configure::read('MISP.org') . " MISP] New sign in.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,17 +257,12 @@ class UserLoginProfile extends AppModel
|
|||
$org_admins = $this->User->getOrgAdminsForOrg($user['User']['org_id']);
|
||||
$admins = $this->User->getSiteAdmins();
|
||||
$all_admins = array_unique(array_merge($org_admins, $admins));
|
||||
foreach($all_admins as $admin_email) {
|
||||
foreach ($all_admins as $admin_email) {
|
||||
$admin = $this->User->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => ['User.email' => $admin_email]
|
||||
));
|
||||
$result = $this->User->sendEmail($admin, $body, false, "[" . Configure::read('MISP.org') . " MISP] Suspicious login reported.");
|
||||
if ($result) {
|
||||
// all is well, email sent to user
|
||||
} else {
|
||||
// email flow system already logs errors
|
||||
}
|
||||
$this->User->sendEmail($admin, $body, false, "[" . Configure::read('MISP.org') . " MISP] Suspicious login reported.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,12 +279,8 @@ class UserLoginProfile extends AppModel
|
|||
$body->set('date_time', $date_time);
|
||||
$body->set('suspiciousness_reason', $suspiciousness_reason);
|
||||
// inform the user
|
||||
$result = $this->User->sendEmail($user, $body, false, "[" . Configure::read('MISP.org') . " MISP] Suspicious login with your account.");
|
||||
if ($result) {
|
||||
// all is well, email sent to user
|
||||
} else {
|
||||
// email flow system already logs errors
|
||||
}
|
||||
$this->User->sendEmail($user, $body, false, "[" . Configure::read('MISP.org') . " MISP] Suspicious login with your account.");
|
||||
|
||||
// inform the org admin
|
||||
$body = new SendEmailTemplate('userloginprofile_suspicious_orgadmin');
|
||||
$body->set('userLoginProfile', $this->_getUserProfile());
|
||||
|
@ -303,18 +289,14 @@ class UserLoginProfile extends AppModel
|
|||
$body->set('misp_org', Configure::read('MISP.org'));
|
||||
$body->set('date_time', $date_time);
|
||||
$body->set('suspiciousness_reason', $suspiciousness_reason);
|
||||
|
||||
$org_admins = $this->User->getOrgAdminsForOrg($user['User']['org_id']);
|
||||
foreach($org_admins as $org_admin_email) {
|
||||
foreach ($org_admins as $org_admin_email) {
|
||||
$org_admin = $this->User->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => ['User.email' => $org_admin_email]
|
||||
));
|
||||
$result = $this->User->sendEmail($org_admin, $body, false, "[" . Configure::read('MISP.org') . " MISP] Suspicious login detected.");
|
||||
if ($result) {
|
||||
// all is well, email sent to user
|
||||
} else {
|
||||
// email flow system already logs errors
|
||||
}
|
||||
$this->User->sendEmail($org_admin, $body, false, "[" . Configure::read('MISP.org') . " MISP] Suspicious login detected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class EcsLog implements CakeLogInterface
|
|||
public function write($type, $message)
|
||||
{
|
||||
$message = [
|
||||
'@timestamp' => self::timestamp(),
|
||||
'@timestamp' => self::now(),
|
||||
'ecs' => [
|
||||
'version' => self::ECS_VERSION,
|
||||
],
|
||||
|
@ -59,7 +59,7 @@ class EcsLog implements CakeLogInterface
|
|||
}
|
||||
|
||||
$message = [
|
||||
'@timestamp' => self::timestamp(),
|
||||
'@timestamp' => self::now(),
|
||||
'ecs' => [
|
||||
'version' => self::ECS_VERSION,
|
||||
],
|
||||
|
@ -98,7 +98,7 @@ class EcsLog implements CakeLogInterface
|
|||
public static function writeEmailLog($logTitle, array $emailResult, $replyTo = null)
|
||||
{
|
||||
$message = [
|
||||
'@timestamp' => self::timestamp(),
|
||||
'@timestamp' => self::now(),
|
||||
'ecs' => [
|
||||
'version' => self::ECS_VERSION,
|
||||
],
|
||||
|
@ -157,7 +157,7 @@ class EcsLog implements CakeLogInterface
|
|||
$clientIp = static::clientIp();
|
||||
$client = [
|
||||
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||
'port' => $_SERVER['REMOTE_PORT'],
|
||||
'port' => (int) $_SERVER['REMOTE_PORT'],
|
||||
];
|
||||
|
||||
if ($clientIp === $_SERVER['REMOTE_ADDR']) {
|
||||
|
@ -168,20 +168,8 @@ class EcsLog implements CakeLogInterface
|
|||
'nat' => $client,
|
||||
];
|
||||
}
|
||||
$meta['url'] = self::createUrlMeta();
|
||||
|
||||
if (strpos($_SERVER['HTTP_HOST'], ':') !== 0) {
|
||||
list($domain, $port) = explode(':', $_SERVER['HTTP_HOST'], 2);
|
||||
$meta['url'] = [
|
||||
'domain' => $domain,
|
||||
'port' => (int) $port,
|
||||
'path' => $_SERVER['REQUEST_URI'],
|
||||
];
|
||||
} else {
|
||||
$meta['url'] = [
|
||||
'domain' => $_SERVER['HTTP_HOST'],
|
||||
'path' => $_SERVER['REQUEST_URI'],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$meta['process']['argv'] = $_SERVER['argv'];
|
||||
}
|
||||
|
@ -194,6 +182,32 @@ class EcsLog implements CakeLogInterface
|
|||
return self::$meta = $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private static function createUrlMeta()
|
||||
{
|
||||
if (strpos($_SERVER['REQUEST_URI'], '?') !== false) {
|
||||
list($path, $query) = explode('?', $_SERVER['REQUEST_URI'], 2);
|
||||
$url = [
|
||||
'path' => $path,
|
||||
'query' => $query,
|
||||
];
|
||||
} else {
|
||||
$url = ['path' => $_SERVER['REQUEST_URI']];
|
||||
}
|
||||
|
||||
if (strpos($_SERVER['HTTP_HOST'], ':') !== false) {
|
||||
list($domain, $port) = explode(':', $_SERVER['HTTP_HOST'], 2);
|
||||
$url['domain'] = $domain;
|
||||
$url['port'] = (int) $port;
|
||||
} else {
|
||||
$url['domain'] = $_SERVER['HTTP_HOST'];
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user metadata (use unique id and email address)
|
||||
* @return array|null
|
||||
|
@ -233,11 +247,12 @@ class EcsLog implements CakeLogInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* ISO 8601 timestamp with microsecond precision
|
||||
* @return string
|
||||
*/
|
||||
public static function timestamp()
|
||||
public static function now()
|
||||
{
|
||||
return date('Y-m-d\TH:i:s.uP');
|
||||
return (new DateTime())->format('Y-m-d\TH:i:s.uP');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -522,8 +522,7 @@ class Oidc
|
|||
private function log($username, $message)
|
||||
{
|
||||
$sessionId = substr(session_id(), 0, 6);
|
||||
$ipHeader = Configure::read('MISP.log_client_ip_header') ?: 'REMOTE_ADDR';
|
||||
$ip = isset($_SERVER[$ipHeader]) ? trim($_SERVER[$ipHeader]) : $_SERVER['REMOTE_ADDR'];
|
||||
$ip = $this->User->_remoteIp();
|
||||
|
||||
if ($username) {
|
||||
$message = "OIDC user `$username` [$ip;$sessionId] – $message";
|
||||
|
|
Loading…
Reference in New Issue