1
0

BungeeGuard style proxy security and OnlyAllowBungee config (#5291)

This commit is contained in:
Ethan Jones 2021-09-23 14:09:52 -06:00 committed by GitHub
parent 3b47eaadb8
commit 7b0872aecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 104 additions and 4 deletions

View File

@ -222,6 +222,28 @@ bool cClientHandle::IsUUIDOnline(const cUUID & a_UUID)
void cClientHandle::ProxyInit(const AString & a_IPString, const cUUID & a_UUID)
{
this->SetIPString(a_IPString);
this->SetUUID(a_UUID);
this->m_ProxyConnection = true;
}
void cClientHandle::ProxyInit(const AString & a_IPString, const cUUID & a_UUID, const Json::Value & a_Properties)
{
this->SetProperties(a_Properties);
this->ProxyInit(a_IPString, a_UUID);
}
void cClientHandle::ProcessProtocolOut()
{
decltype(m_OutgoingData) OutgoingData;
@ -264,6 +286,54 @@ void cClientHandle::Kick(const AString & a_Reason)
bool cClientHandle::BungeeAuthenticate()
{
if (!m_ProxyConnection && cRoot::Get()->GetServer()->OnlyAllowBungeeCord())
{
Kick("You can only connect to this server using a Proxy.");
return false;
}
cServer * Server = cRoot::Get()->GetServer();
// Proxy Shared Secret Check (BungeeGuard)
const AString & ForwardSecret = Server->GetProxySharedSecret();
const bool AllowBungee = Server->ShouldAllowBungeeCord();
const bool RequireForwardSecret = AllowBungee && !ForwardSecret.empty();
if (RequireForwardSecret)
{
for (auto & Node : GetProperties())
{
if (Node.get("name", "").asString() == "bungeeguard-token")
{
AString SentToken = Node.get("value", "").asString();
if (ForwardSecret.compare(SentToken) == 0)
{
return true;
}
break;
}
}
Kick("Unable to authenticate.");
return false;
}
else if (m_ProxyConnection)
{
LOG("A player connected through a proxy without requiring a forwarding secret. If open to the internet, this is very insecure!");
}
return true;
}
void cClientHandle::Authenticate(const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties)
{
{
@ -281,6 +351,11 @@ void cClientHandle::Authenticate(const AString & a_Name, const cUUID & a_UUID, c
ASSERT(m_Player == nullptr);
if (!BungeeAuthenticate())
{
return;
}
m_Username = a_Name;
// Only assign UUID and properties if not already pre-assigned (BungeeCord sends those in the Handshake packet):

View File

@ -101,6 +101,10 @@ public: // tolua_export
We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart. */
static bool IsUUIDOnline(const cUUID & a_UUID); // Exported in ManualBindings.cpp
/** Function to mark bungee / proxy connection on this client, and to add proxy-related data */
void ProxyInit(const AString & a_IPString, const cUUID & a_UUID);
void ProxyInit(const AString & a_IPString, const cUUID & a_UUID, const Json::Value & a_Properties);
/** Flushes all buffered outgoing data to the network. */
void ProcessProtocolOut();
@ -114,6 +118,9 @@ public: // tolua_export
void Kick(const AString & a_Reason); // tolua_export
/** Authenticates the specified user with the bungee proxy server */
bool BungeeAuthenticate();
/** Authenticates the specified user, called by cAuthenticator */
void Authenticate(const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties);
@ -470,6 +477,8 @@ private:
Otherwise, this contains an arbitrary value which should not be used. */
cChunkCoords m_CachedSentChunk;
bool m_ProxyConnection; ///< True if player connected from a proxy (Bungee / Velocity)
bool m_HasSentDC; ///< True if a Disconnect packet has been sent in either direction
// Chunk position when the last StreamChunks() was called; used to avoid re-streaming while in the same chunk

View File

@ -123,20 +123,18 @@ cProtocol_1_8_0::cProtocol_1_8_0(cClientHandle * a_Client, const AString & a_Ser
LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
m_Client->SetIPString(Params[1]);
cUUID UUID;
UUID.FromString(Params[2]);
m_Client->SetUUID(UUID);
Json::Value root;
if (!JsonUtils::ParseString(Params[3], root))
{
LOGERROR("Unable to parse player properties: '%s'", Params[3]);
m_Client->ProxyInit(Params[1], UUID);
}
else
{
m_Client->SetProperties(root);
m_Client->ProxyInit(Params[1], UUID, root);
}
}
else

View File

@ -192,11 +192,19 @@ bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_Shoul
// Check if both BungeeCord and online mode are on, if so, warn the admin:
m_ShouldAllowBungeeCord = a_Settings.GetValueSetB("Authentication", "AllowBungeeCord", false);
m_OnlyAllowBungeeCord = a_Settings.GetValueSetB("Authentication", "OnlyAllowBungeeCord", false);
m_ProxySharedSecret = a_Settings.GetValueSet("Authentication", "ProxySharedSecret", "");
if (m_ShouldAllowBungeeCord && m_ShouldAuthenticate)
{
LOGWARNING("WARNING: BungeeCord is allowed and server set to online mode. This is unsafe and will not work properly. Disable either authentication or BungeeCord in settings.ini.");
}
if (m_ShouldAllowBungeeCord && m_ProxySharedSecret.empty())
{
LOGWARNING("WARNING: There is not a Proxy Forward Secret set up, and any proxy server can forward a player to this server unless closed from the internet.");
}
m_ShouldAllowMultiWorldTabCompletion = a_Settings.GetValueSetB("Server", "AllowMultiWorldTabCompletion", true);
m_ShouldLimitPlayerBlockChanges = a_Settings.GetValueSetB("AntiCheat", "LimitPlayerBlockChanges", true);

View File

@ -149,6 +149,10 @@ public:
it makes the server vulnerable to identity theft through direct connections. */
bool ShouldAllowBungeeCord(void) const { return m_ShouldAllowBungeeCord; }
bool OnlyAllowBungeeCord(void) const { return m_OnlyAllowBungeeCord; }
const AString & GetProxySharedSecret(void) const { return m_ProxySharedSecret; }
/** Returns true if usernames should be completed across worlds. This is read
from the settings. */
bool ShouldAllowMultiWorldTabCompletion(void) const { return m_ShouldAllowMultiWorldTabCompletion; }
@ -240,6 +244,12 @@ private:
/** True if BungeeCord handshake packets (with player UUID) should be accepted. */
bool m_ShouldAllowBungeeCord;
/** True if BungeeCord handshake packets should be the only ones accepted. */
bool m_OnlyAllowBungeeCord;
/** Security string that the proxy server should send, compatible with BungeeGuard */
AString m_ProxySharedSecret;
/** True if usernames should be completed across worlds. */
bool m_ShouldAllowMultiWorldTabCompletion;