Always require lobby authentication for lobby matches, refs #3549 / 0fd8aa2a77 / D897.

This is due to too many oversteppings of the lobby Terms of Use
following JS mods that implemented an UI for players to join lobby games
with arbitrary nicknames or 'replace' / impersonate other players in
lobby games.

Agreed with: user1, Dunedan
Code proofread by: Vladislav
Minor discussions with: Imarok, Hannibal_Barca, smiley, fpre, bb, nani
refs
https://wildfiregames.com/forum/index.php?/topic/24722-improving-mod-security/

This was SVN commit r21877.
This commit is contained in:
elexis 2018-08-25 14:34:30 +00:00
parent 1beb96cb20
commit 78d7702262
9 changed files with 45 additions and 25 deletions

View File

@ -421,7 +421,6 @@ xpartamupp = "wfgbot23" ; Name of the server-side XMPP-account that
echelon = "echelon23" ; Name of the server-side XMPP-account that manages ratings
buddies = "," ; Comma separated list of playernames that the current user has marked as buddies
rememberpassword = true ; Whether to store the encrypted password in the user config
secureauth = true ; Secure Lobby Authentication: This prevents the impersonation of other players. The lobby server confirms the identity of the player before they join.
[lobby.columns]
gamerating = false ; Show the average rating of the participating players in a column of the gamelist

View File

@ -48,7 +48,6 @@ function init(attribs)
case "host":
{
Engine.GetGUIObjectByName("hostSTUNWrapper").hidden = !Engine.HasXmppClient();
Engine.GetGUIObjectByName("hostLobbyAuthWrapper").hidden = !Engine.HasXmppClient();
if (Engine.HasXmppClient())
{
Engine.GetGUIObjectByName("hostPlayerName").caption = attribs.name;
@ -56,7 +55,6 @@ function init(attribs)
sprintf(translate("%(name)s's game"), { "name": attribs.name });
Engine.GetGUIObjectByName("useSTUN").checked = Engine.ConfigDB_GetValue("user", "lobby.stun.enabled") == "true";
Engine.GetGUIObjectByName("useLobbyAuth").checked = Engine.ConfigDB_GetValue("user", "lobby.secureauth") == "true";
}
switchSetupPage("pageHost");
@ -269,7 +267,7 @@ function switchSetupPage(newPage)
if (newPage == "pageJoin" || newPage == "pageHost")
{
let pageSize = multiplayerPages.size;
let halfHeight = newPage == "pageJoin" ? 130 : Engine.HasXmppClient() ? 145 : 110;
let halfHeight = newPage == "pageJoin" ? 130 : Engine.HasXmppClient() ? 125 : 110;
pageSize.top = -halfHeight;
pageSize.bottom = halfHeight;
multiplayerPages.size = pageSize;
@ -313,10 +311,9 @@ function startHost(playername, servername, port)
}
}
let useLobbyAuth = Engine.HasXmppClient() && Engine.GetGUIObjectByName("useLobbyAuth").checked;
try
{
Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port, playername, useLobbyAuth);
Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port, playername);
}
catch (e)
{

View File

@ -114,16 +114,6 @@
<translatableAttribute id="caption">Use STUN to work around firewalls</translatableAttribute>
</object>
</object>
<object name="hostLobbyAuthWrapper" size="120 141 100% 181">
<object name="useLobbyAuth" size="0 10 32 100%" type="checkbox" style="ModernTickBox">
<action on="Press">saveSettingAndWriteToUserConfig("lobby.secureauth", String(this.checked));</action>
</object>
<object type="text" size="26 0 100% 100%" style="ModernLeftLabelText">
<translatableAttribute id="caption">Require Lobby Authentication</translatableAttribute>
<translatableAttribute id="tooltip">This prevents the impersonation of other players. The lobby server confirms the identity of the player before they join.</translatableAttribute>
</object>
</object>
</object>
<object name="hostFeedback" type="text" style="ModernLabelText" size="50 100%-80 100%-50 100%-45" textcolor="red"/>

View File

@ -22,13 +22,17 @@
#include "gui/GUIManager.h"
#include "lib/utf8.h"
#include "lobby/IXmppClient.h"
#include "network/NetServer.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "ps/Profile.h"
#include "ps/Util.h"
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/ScriptVal.h"
#include "third_party/encryption/pkcs5_pbkdf2.h"
#include <string>
void JSI_Lobby::RegisterScriptFunctions(const ScriptInterface& scriptInterface)
{
// Lobby functions
@ -154,6 +158,13 @@ void JSI_Lobby::SendRegisterGame(ScriptInterface::CxPrivate* pCxPrivate, JS::Han
if (!g_XmppClient)
return;
// Prevent JS mods to register matches in the lobby that were started with lobby authentication disabled
if (!g_NetServer || !g_NetServer->UseLobbyAuth())
{
LOGERROR("Registering games in the lobby requires lobby authentication to be enabled!");
return;
}
g_XmppClient->SendIqRegisterGame(*(pCxPrivate->pScriptInterface), data);
}

View File

@ -20,7 +20,8 @@
#include "lib/config2.h"
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/ScriptVal.h"
#include <string>
namespace JSI_Lobby
{

View File

@ -26,11 +26,13 @@
#include "NetStats.h"
#include "lib/external_libraries/enet.h"
#include "lib/types.h"
#include "network/StunClient.h"
#include "ps/CLogger.h"
#include "ps/ConfigDB.h"
#include "ps/GUID.h"
#include "ps/Profile.h"
#include "ps/ThreadUtil.h"
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/ScriptRuntime.h"
#include "simulation2/Simulation2.h"
@ -43,6 +45,8 @@
#include <miniupnpc/upnperrors.h>
#endif
#include <string>
/**
* Number of peers to allocate for the enet host.
* Limited by ENET_PROTOCOL_MAXIMUM_PEER_ID (4096).
@ -1556,7 +1560,8 @@ void CNetServerWorker::SendHolePunchingMessage(const CStr& ipStr, u16 port)
CNetServer::CNetServer(bool useLobbyAuth, int autostartPlayers) :
m_Worker(new CNetServerWorker(useLobbyAuth, autostartPlayers))
m_Worker(new CNetServerWorker(useLobbyAuth, autostartPlayers)),
m_LobbyAuth(useLobbyAuth)
{
}
@ -1565,6 +1570,11 @@ CNetServer::~CNetServer()
delete m_Worker;
}
bool CNetServer::UseLobbyAuth() const
{
return m_LobbyAuth;
}
bool CNetServer::SetupConnection(const u16 port)
{
return m_Worker->SetupConnection(port);

View File

@ -20,11 +20,13 @@
#include "NetFileTransfer.h"
#include "NetHost.h"
#include "lib/config2.h"
#include "lib/types.h"
#include "ps/ThreadUtil.h"
#include "scriptinterface/ScriptTypes.h"
#include <string>
#include <utility>
#include <vector>
class CNetServerSession;
@ -137,12 +139,15 @@ public:
*/
void SetTurnLength(u32 msecs);
bool UseLobbyAuth() const;
void OnLobbyAuth(const CStr& name, const CStr& token);
void SendHolePunchingMessage(const CStr& ip, u16 port);
private:
CNetServerWorker* m_Worker;
const bool m_LobbyAuth;
};
/**
@ -298,7 +303,11 @@ private:
JS::PersistentRootedValue m_GameAttributes;
int m_AutostartPlayers;
bool m_LobbyAuth;
/**
* Whether this match requires lobby authentication.
*/
const bool m_LobbyAuth;
ENetHost* m_Host;
std::vector<CNetServerSession*> m_Sessions;

View File

@ -21,6 +21,7 @@
#include "lib/external_libraries/enet.h"
#include "lib/external_libraries/libsdl.h"
#include "lib/types.h"
#include "lobby/IXmppClient.h"
#include "network/NetClient.h"
#include "network/NetMessage.h"
@ -50,13 +51,14 @@ JS::Value JSI_Network::FindStunEndpoint(ScriptInterface::CxPrivate* pCxPrivate,
return StunClient::FindStunEndpointHost(*(pCxPrivate->pScriptInterface), port);
}
void JSI_Network::StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const u16 serverPort, const CStr& hostLobbyName, bool useLobbyAuth)
void JSI_Network::StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const u16 serverPort, const CStr& hostLobbyName)
{
ENSURE(!g_NetClient);
ENSURE(!g_NetServer);
ENSURE(!g_Game);
g_NetServer = new CNetServer(useLobbyAuth);
// Always use lobby authentication for lobby matches to prevent impersonation and smurfing, in particular through mods that implemented an UI for arbitrary or other players nicknames.
g_NetServer = new CNetServer(static_cast<bool>(g_XmppClient));
if (!g_NetServer->SetupConnection(serverPort))
{
pCxPrivate->pScriptInterface->ReportError("Failed to start server");
@ -228,7 +230,7 @@ void JSI_Network::RegisterScriptFunctions(const ScriptInterface& scriptInterface
scriptInterface.RegisterFunction<bool, &HasNetServer>("HasNetServer");
scriptInterface.RegisterFunction<bool, &HasNetClient>("HasNetClient");
scriptInterface.RegisterFunction<JS::Value, int, &FindStunEndpoint>("FindStunEndpoint");
scriptInterface.RegisterFunction<void, CStrW, u16, CStr, bool, &StartNetworkHost>("StartNetworkHost");
scriptInterface.RegisterFunction<void, CStrW, u16, CStr, &StartNetworkHost>("StartNetworkHost");
scriptInterface.RegisterFunction<void, CStrW, CStr, u16, bool, CStr, &StartNetworkJoin>("StartNetworkJoin");
scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
scriptInterface.RegisterFunction<CStr, &GetPlayerGUID>("GetPlayerGUID");

View File

@ -18,6 +18,7 @@
#ifndef INCLUDED_JSI_NETWORK
#define INCLUDED_JSI_NETWORK
#include "lib/types.h"
#include "ps/CStr.h"
#include "scriptinterface/ScriptInterface.h"
@ -28,7 +29,7 @@ namespace JSI_Network
bool HasNetClient(ScriptInterface::CxPrivate* pCxPrivate);
void StartNetworkGame(ScriptInterface::CxPrivate* pCxPrivate);
void SetNetworkGameAttributes(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue attribs1);
void StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const u16 serverPort, const CStr& hostLobbyName, bool useLobbyAuth);
void StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const u16 serverPort, const CStr& hostLobbyName);
void StartNetworkJoin(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const CStr& serverAddress, u16 serverPort, bool useSTUN, const CStr& hostJID);
JS::Value FindStunEndpoint(ScriptInterface::CxPrivate* pCxPrivate, int port);
void DisconnectNetworkGame(ScriptInterface::CxPrivate* pCxPrivate);