fix: session keys are 16 bytes sent as 32 hex characters

The key was a 32 bit number, sent to the client as the MD5 hash of its
decimal text. The client only stores the key and sends it back, so it
is now 16 bytes from the system entropy source written as 32 lowercase
hex characters, which fills the same 33 character field of the login
response.

The auth, master and world servers pass the key itself between them as
a 33 character string in place of the number: SET_SESSION_KEY,
SESSION_KEY_RESPONSE and NEW_SESSION_ALERT keep their IDs and carry the
string where the number was. The master server keeps one key for each
username, and a world server compares the key a client sends with the
one from the master server in constant time. A key stays valid until
the next login of its account replaces it, as before.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-11-10 15:37:08 -06:00
parent 66e6137a9f
commit 26b188852f
6 changed files with 145 additions and 36 deletions

View File

@@ -92,7 +92,8 @@ bool shutdownSequenceStarted = false;
int ShutdownSequence(int32_t signal = -1);
int32_t FinalizeShutdown(int32_t signal = -1);
void HandlePacket(Packet* packet);
std::map<uint32_t, std::string> activeSessions;
// The session key of each logged in account, by username
std::map<std::string, std::string> activeSessions;
SystemAddress authServerMasterPeerSysAddr;
SystemAddress chatServerMasterPeerSysAddr;
SystemAddress dashboardServerMasterPeerSysAddr;
@@ -830,37 +831,30 @@ namespace {
}
void OnSetSessionKey(const SetSessionKey& request, const SystemAddress& sysAddr) {
const uint32_t sessionKey = request.sessionKey;
const LUString& sessionKey = request.sessionKey;
const LUString& username = request.username;
for (auto it : activeSessions) {
if (it.second == username.string) {
activeSessions.erase(it.first);
NewSessionAlert alert;
alert.sessionKey = sessionKey;
alert.username = username;
alert.Broadcast();
break;
}
// A new login replaces the key, so tell the worlds to drop the old session
if (activeSessions.contains(username.string)) {
NewSessionAlert alert;
alert.sessionKey = sessionKey;
alert.username = username;
alert.Broadcast();
}
activeSessions.insert(std::make_pair(sessionKey, username.string));
activeSessions.insert_or_assign(username.string, sessionKey.string);
LOG("Got a session key for user %s", username.string.c_str());
}
void OnRequestSessionKey(const RequestSessionKey& request, const SystemAddress& sysAddr) {
const LUWString& username = request.username;
LOG("Requesting session key for %s", username.GetAsString().c_str());
for (auto key : activeSessions) {
if (key.second == username.GetAsString()) {
SessionKeyResponse response;
response.sessionKey = key.first;
response.username = username;
MasterPackets::SendTo(sysAddr, response);
break;
}
const auto session = activeSessions.find(username.GetAsString());
if (session != activeSessions.end()) {
SessionKeyResponse response;
response.sessionKey = LUString(session->second);
response.username = username;
MasterPackets::SendTo(sysAddr, response);
}
}