fix(Core): fix ip bans (#6519)

This commit is contained in:
Axel Cocat
2021-06-28 18:02:19 +02:00
committed by GitHub
parent 091b072be1
commit f1727b79d2
3 changed files with 43 additions and 23 deletions
+22 -16
View File
@@ -185,11 +185,15 @@ const AuthHandler table[] =
void AccountInfo::LoadResult(Field* fields) void AccountInfo::LoadResult(Field* fields)
{ {
// 0 1 2 3 4 5 6 // 0 1 2 3 4 5
//SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, // SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins,
// 7 8 // 6 7
// ab.unbandate = ab.bandate, aa.gmlevel (, more query-specific fields) // ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate,
//FROM account a LEFT JOIN account_access aa ON a.id = aa.AccountID LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ? // 8 9
// ipb.unbandate > UNIX_TIMESTAMP() OR ipb.unbandate = ipb.bandate, ipb.unbandate = ipb.bandate,
// 10
// aa.gmlevel (, more query-specific fields)
// FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 LEFT JOIN ip_banned ipb ON ipb.ip = ? WHERE a.username = ?
Id = fields[0].GetUInt32(); Id = fields[0].GetUInt32();
Login = fields[1].GetString(); Login = fields[1].GetString();
@@ -197,9 +201,9 @@ void AccountInfo::LoadResult(Field* fields)
LockCountry = fields[3].GetString(); LockCountry = fields[3].GetString();
LastIP = fields[4].GetString(); LastIP = fields[4].GetString();
FailedLogins = fields[5].GetUInt32(); FailedLogins = fields[5].GetUInt32();
IsBanned = fields[6].GetUInt64() != 0; IsBanned = fields[6].GetBool() || fields[8].GetBool();
IsPermanenetlyBanned = fields[7].GetUInt64() != 0; IsPermanentlyBanned = fields[7].GetBool() || fields[9].GetBool();
SecurityLevel = static_cast<AccountTypes>(fields[8].GetUInt8()) > SEC_CONSOLE ? SEC_CONSOLE : static_cast<AccountTypes>(fields[8].GetUInt8()); SecurityLevel = static_cast<AccountTypes>(fields[10].GetUInt8()) > SEC_CONSOLE ? SEC_CONSOLE : static_cast<AccountTypes>(fields[10].GetUInt8());
// Use our own uppercasing of the account name instead of using UPPER() in mysql query // Use our own uppercasing of the account name instead of using UPPER() in mysql query
// This is how the account was created in the first place and changing it now would result in breaking // This is how the account was created in the first place and changing it now would result in breaking
@@ -378,7 +382,8 @@ bool AuthSocket::_HandleLogonChallenge()
// Get the account details from the account table // Get the account details from the account table
// No SQL injection (prepared statement) // No SQL injection (prepared statement)
auto stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); auto stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE);
stmt->setString(0, login); stmt->setString(0, ipAddress);
stmt->setString(1, login);
PreparedQueryResult res2 = LoginDatabase.Query(stmt); PreparedQueryResult res2 = LoginDatabase.Query(stmt);
if (!res2) //no account if (!res2) //no account
@@ -428,7 +433,7 @@ bool AuthSocket::_HandleLogonChallenge()
// If the account is banned, reject the logon attempt // If the account is banned, reject the logon attempt
if (_accountInfo.IsBanned) if (_accountInfo.IsBanned)
{ {
if (_accountInfo.IsPermanenetlyBanned) if (_accountInfo.IsPermanentlyBanned)
{ {
pkt << uint8(WOW_FAIL_BANNED); pkt << uint8(WOW_FAIL_BANNED);
LOG_DEBUG("server.authserver.banned", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), port, _accountInfo.Login.c_str()); LOG_DEBUG("server.authserver.banned", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), port, _accountInfo.Login.c_str());
@@ -446,12 +451,12 @@ bool AuthSocket::_HandleLogonChallenge()
uint8 securityFlags = 0; uint8 securityFlags = 0;
// Check if a TOTP token is needed // Check if a TOTP token is needed
if (sConfigMgr->GetOption<bool>("EnableTOTP", false) && !fields[9].IsNull()) if (sConfigMgr->GetOption<bool>("EnableTOTP", false) && !fields[11].IsNull())
{ {
LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' using TOTP", _accountInfo.Login.c_str()); LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' using TOTP", _accountInfo.Login.c_str());
securityFlags = 4; securityFlags = 4;
_totpSecret = fields[9].GetBinary(); _totpSecret = fields[11].GetBinary();
if (auto const& secret = sSecretMgr->GetSecret(SECRET_TOTP_MASTER_KEY)) if (auto const& secret = sSecretMgr->GetSecret(SECRET_TOTP_MASTER_KEY))
{ {
bool success = Acore::Crypto::AEDecrypt<Acore::Crypto::AES>(*_totpSecret, *secret); bool success = Acore::Crypto::AEDecrypt<Acore::Crypto::AES>(*_totpSecret, *secret);
@@ -467,8 +472,8 @@ bool AuthSocket::_HandleLogonChallenge()
_srp6.emplace( _srp6.emplace(
_accountInfo.Login, _accountInfo.Login,
fields[10].GetBinary<Acore::Crypto::SRP6::SALT_LENGTH>(), fields[12].GetBinary<Acore::Crypto::SRP6::SALT_LENGTH>(),
fields[11].GetBinary<Acore::Crypto::SRP6::VERIFIER_LENGTH>()); fields[13].GetBinary<Acore::Crypto::SRP6::VERIFIER_LENGTH>());
// Fill the response packet with the result // Fill the response packet with the result
if (!AuthHelper::IsAcceptedClientBuild(_build)) if (!AuthHelper::IsAcceptedClientBuild(_build))
@@ -720,7 +725,8 @@ bool AuthSocket::_HandleReconnectChallenge()
return false; return false;
auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RECONNECTCHALLENGE); auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RECONNECTCHALLENGE);
stmt->setString(0, login); stmt->setString(0, socket().getRemoteAddress());
stmt->setString(1, login);
PreparedQueryResult result = LoginDatabase.Query(stmt); PreparedQueryResult result = LoginDatabase.Query(stmt);
// Stop if the account is not found // Stop if the account is not found
@@ -737,7 +743,7 @@ bool AuthSocket::_HandleReconnectChallenge()
// Restore string order as its byte order is reversed // Restore string order as its byte order is reversed
std::reverse(_os.begin(), _os.end()); std::reverse(_os.begin(), _os.end());
_sessionKey = fields[9].GetBinary<SESSION_KEY_LENGTH>(); _sessionKey = fields[11].GetBinary<SESSION_KEY_LENGTH>();
Acore::Crypto::GetRandomBytes(_reconnectProof); Acore::Crypto::GetRandomBytes(_reconnectProof);
///- All good, await client's proof ///- All good, await client's proof
+1 -1
View File
@@ -39,7 +39,7 @@ struct AccountInfo
std::string LastIP; std::string LastIP;
uint32 FailedLogins = 0; uint32 FailedLogins = 0;
bool IsBanned = false; bool IsBanned = false;
bool IsPermanenetlyBanned = false; bool IsPermanentlyBanned = false;
AccountTypes SecurityLevel = SEC_PLAYER; AccountTypes SecurityLevel = SEC_PLAYER;
}; };
@@ -11,12 +11,26 @@ void LoginDatabaseConnection::DoPrepareStatements()
if (!m_reconnecting) if (!m_reconnecting)
m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS); m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS);
PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " PrepareStatement(LOGIN_SEL_LOGONCHALLENGE,
"ab.unbandate = ab.bandate, aa.gmlevel, a.totp_secret, a.salt, a.verifier " "SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, "
"FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ?", CONNECTION_SYNCH); "ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate, "
PrepareStatement(LOGIN_SEL_RECONNECTCHALLENGE, "SELECT a.id, UPPER(a.username), a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " "ipb.unbandate > UNIX_TIMESTAMP() OR ipb.unbandate = ipb.bandate, ipb.unbandate = ipb.bandate, "
"ab.unbandate = ab.bandate, aa.gmlevel, a.session_key " "aa.gmlevel, a.totp_secret, a.salt, a.verifier "
"FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ? AND a.session_key IS NOT NULL", CONNECTION_SYNCH); "FROM account a "
"LEFT JOIN account_access aa ON a.id = aa.id "
"LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 "
"LEFT JOIN ip_banned ipb ON ipb.ip = ? "
"WHERE a.username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_RECONNECTCHALLENGE,
"SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, "
"ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate, "
"ipb.unbandate > UNIX_TIMESTAMP() OR ipb.unbandate = ipb.bandate, ipb.unbandate = ipb.bandate, "
"aa.gmlevel, a.session_key "
"FROM account a "
"LEFT JOIN account_access aa ON a.id = aa.id "
"LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 "
"LEFT JOIN ip_banned ipb ON ipb.ip = ? "
"WHERE a.username = ? AND a.session_key IS NOT NULL", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.session_key, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, a.totaltime, " PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.session_key, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, a.totaltime, "
"aa.gmlevel, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id FROM account a LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, ?) " "aa.gmlevel, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id FROM account a LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, ?) "
"LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account r ON a.id = r.recruiter WHERE a.username = ? " "LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account r ON a.id = r.recruiter WHERE a.username = ? "