prevent password brute force (#4)
Prevent blocked IP addresses and accounts from returning anything other than a blocked error message. Previously, further attempts would first check the password which enabled brute force attacks to use the "invalid account/password" message as an oracle.
This commit is contained in:
parent
6aa13394a1
commit
d36b26307d
42
src/query.cc
42
src/query.cc
@ -518,17 +518,19 @@ static void CheckAccountPasswordTx(TDatabase *Database, TQuery *Query,
|
|||||||
TransactionScope Tx("CheckAccountPassword");
|
TransactionScope Tx("CheckAccountPassword");
|
||||||
QUERY_STOP_IF(!Tx.Begin(Database));
|
QUERY_STOP_IF(!Tx.Begin(Database));
|
||||||
|
|
||||||
|
// IMPORTANT(fusion): Disallow blocked IP addresses and accounts early to
|
||||||
|
// prevent error messages from being used to brute force passwords.
|
||||||
|
int FailedLoginAttempts;
|
||||||
|
QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
|
||||||
|
QUERY_ERROR_IF(FailedLoginAttempts > 20, 4);
|
||||||
|
QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, AccountID, 5 * 60, &FailedLoginAttempts));
|
||||||
|
QUERY_ERROR_IF(FailedLoginAttempts > 10, 3);
|
||||||
|
|
||||||
TAccount Account;
|
TAccount Account;
|
||||||
QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
|
QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
|
||||||
QUERY_ERROR_IF(Account.AccountID == 0, 1);
|
QUERY_ERROR_IF(Account.AccountID == 0, 1);
|
||||||
QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 2);
|
QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 2);
|
||||||
|
|
||||||
int FailedLoginAttempts;
|
|
||||||
QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, Account.AccountID, 5 * 60, &FailedLoginAttempts));
|
|
||||||
QUERY_ERROR_IF(FailedLoginAttempts > 10, 3);
|
|
||||||
QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
|
|
||||||
QUERY_ERROR_IF(FailedLoginAttempts > 20, 4);
|
|
||||||
|
|
||||||
QUERY_STOP_IF(!Tx.Commit());
|
QUERY_STOP_IF(!Tx.Commit());
|
||||||
QueryOk(Query);
|
QueryOk(Query);
|
||||||
}
|
}
|
||||||
@ -558,17 +560,19 @@ static void LoginAccountTx(TDatabase *Database, TQuery *Query,
|
|||||||
TransactionScope Tx("LoginAccount");
|
TransactionScope Tx("LoginAccount");
|
||||||
QUERY_STOP_IF(!Tx.Begin(Database));
|
QUERY_STOP_IF(!Tx.Begin(Database));
|
||||||
|
|
||||||
|
// IMPORTANT(fusion): Disallow blocked IP addresses and accounts early to
|
||||||
|
// prevent error messages from being used to brute force passwords.
|
||||||
|
int FailedLoginAttempts;
|
||||||
|
QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
|
||||||
|
QUERY_ERROR_IF(FailedLoginAttempts > 20, 4);
|
||||||
|
QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, AccountID, 5 * 60, &FailedLoginAttempts));
|
||||||
|
QUERY_ERROR_IF(FailedLoginAttempts > 10, 3);
|
||||||
|
|
||||||
TAccount Account;
|
TAccount Account;
|
||||||
QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
|
QUERY_STOP_IF(!GetAccountData(Database, AccountID, &Account));
|
||||||
QUERY_ERROR_IF(Account.AccountID == 0, 1);
|
QUERY_ERROR_IF(Account.AccountID == 0, 1);
|
||||||
QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 2);
|
QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 2);
|
||||||
|
|
||||||
int FailedLoginAttempts;
|
|
||||||
QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, Account.AccountID, 5 * 60, &FailedLoginAttempts));
|
|
||||||
QUERY_ERROR_IF(FailedLoginAttempts > 10, 3);
|
|
||||||
QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
|
|
||||||
QUERY_ERROR_IF(FailedLoginAttempts > 20, 4);
|
|
||||||
|
|
||||||
bool IsBanished;
|
bool IsBanished;
|
||||||
QUERY_STOP_IF(!IsAccountBanished(Database, Account.AccountID, &IsBanished));
|
QUERY_STOP_IF(!IsAccountBanished(Database, Account.AccountID, &IsBanished));
|
||||||
QUERY_ERROR_IF(IsBanished, 5);
|
QUERY_ERROR_IF(IsBanished, 5);
|
||||||
@ -628,6 +632,14 @@ static void LoginGameTx(TDatabase *Database, TQuery *Query,
|
|||||||
TransactionScope Tx("LoginGame");
|
TransactionScope Tx("LoginGame");
|
||||||
QUERY_STOP_IF(!Tx.Begin(Database));
|
QUERY_STOP_IF(!Tx.Begin(Database));
|
||||||
|
|
||||||
|
// IMPORTANT(fusion): Disallow blocked IP addresses and accounts early to
|
||||||
|
// prevent error messages from being used to brute force passwords.
|
||||||
|
int FailedLoginAttempts;
|
||||||
|
QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
|
||||||
|
QUERY_ERROR_IF(FailedLoginAttempts > 20, 9);
|
||||||
|
QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, AccountID, 5 * 60, &FailedLoginAttempts));
|
||||||
|
QUERY_ERROR_IF(FailedLoginAttempts > 10, 7);
|
||||||
|
|
||||||
TCharacterLoginData Character;
|
TCharacterLoginData Character;
|
||||||
QUERY_STOP_IF(!GetCharacterLoginData(Database, CharacterName, &Character));
|
QUERY_STOP_IF(!GetCharacterLoginData(Database, CharacterName, &Character));
|
||||||
QUERY_ERROR_IF(Character.CharacterID == 0, 1);
|
QUERY_ERROR_IF(Character.CharacterID == 0, 1);
|
||||||
@ -646,12 +658,6 @@ static void LoginGameTx(TDatabase *Database, TQuery *Query,
|
|||||||
QUERY_ERROR_IF(Account.Deleted, 8);
|
QUERY_ERROR_IF(Account.Deleted, 8);
|
||||||
QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 6);
|
QUERY_ERROR_IF(!TestPassword(Account.Auth, sizeof(Account.Auth), Password), 6);
|
||||||
|
|
||||||
int FailedLoginAttempts;
|
|
||||||
QUERY_STOP_IF(!GetAccountFailedLoginAttempts(Database, Account.AccountID, 5 * 60, &FailedLoginAttempts));
|
|
||||||
QUERY_ERROR_IF(FailedLoginAttempts > 10, 7);
|
|
||||||
QUERY_STOP_IF(!GetIPAddressFailedLoginAttempts(Database, IPAddress, 30 * 60, &FailedLoginAttempts));
|
|
||||||
QUERY_ERROR_IF(FailedLoginAttempts > 20, 9);
|
|
||||||
|
|
||||||
bool IsBanished;
|
bool IsBanished;
|
||||||
QUERY_STOP_IF(!IsAccountBanished(Database, Account.AccountID, &IsBanished));
|
QUERY_STOP_IF(!IsAccountBanished(Database, Account.AccountID, &IsBanished));
|
||||||
QUERY_ERROR_IF(IsBanished, 10);
|
QUERY_ERROR_IF(IsBanished, 10);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user