Fixed NPE on invalid sessions + Improved security for premium logins

This commit is contained in:
games647
2015-11-04 19:41:47 +01:00
parent fa46dc690b
commit 834818bb7a
8 changed files with 45 additions and 25 deletions

View File

@@ -7,15 +7,30 @@ package com.github.games647.fastlogin;
*/
public class PlayerSession {
private final byte[] verifyToken;
private final String username;
private final String serverId;
private final byte[] verifyToken;
private boolean verified;
public PlayerSession(byte[] verifyToken, String username) {
public PlayerSession(String username, String serverId, byte[] verifyToken) {
this.username = username;
this.serverId = serverId;
this.verifyToken = verifyToken;
}
/**
* Gets the random generated server id. This makes sure the request
* sent from the client is just for this server.
*
* See this for details
* http://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/
*
* @return random generated server id
*/
public String getServerId() {
return serverId;
}
/**
* Gets the verify token the server sent to the client.
*

View File

@@ -34,17 +34,6 @@ public class PremiumCommand implements CommandExecutor {
return true;
}
if (sender.hasPermission(plugin.getName() + ".command." + command.getName() + ".others")) {
String playerName = args[0];
//todo check if valid username
plugin.getEnabledPremium().add(playerName);
sender.sendMessage(ChatColor.DARK_GREEN + "Added "
+ ChatColor.DARK_BLUE + ChatColor.BOLD + playerName
+ ChatColor.RESET + ChatColor.DARK_GREEN + " to the list of premium players");
} else {
sender.sendMessage(ChatColor.DARK_RED + "Not enough permissions");
}
return true;
}
}

View File

@@ -100,9 +100,13 @@ public class EncryptionPacketListener extends PacketAdapter {
return;
}
//this makes sure the request from the client is for us
//this might be relevant http://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/
String generatedId = session.getServerId();
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L193
//generate the server id based on client and server data
byte[] serverIdHash = EncryptionUtil.getServerIdHash("", plugin.getServerKey().getPublic(), loginKey);
byte[] serverIdHash = EncryptionUtil.getServerIdHash(generatedId, plugin.getServerKey().getPublic(), loginKey);
String serverId = (new BigInteger(serverIdHash)).toString(16);
String username = session.getUsername();
@@ -206,7 +210,7 @@ public class EncryptionPacketListener extends PacketAdapter {
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = reader.readLine();
if (!"null".equals(line)) {
if (line != null && !line.equals("null")) {
//validate parsing
//http://wiki.vg/Protocol_Encryption#Server
JSONObject userData = (JSONObject) JSONValue.parseWithException(line);
@@ -222,7 +226,7 @@ public class EncryptionPacketListener extends PacketAdapter {
}
} catch (Exception ex) {
//catch not only ioexceptions also parse and NPE on unexpected json format
plugin.getLogger().log(Level.WARNING, "Failed to verify if session is valid", ex);
plugin.getLogger().log(Level.WARNING, "Failed to verify session", ex);
}
//this connection doesn't need to be closed. So can make use of keep alive in java

View File

@@ -119,6 +119,10 @@ public class StartPacketListener extends PacketAdapter {
*/
PacketContainer newPacket = protocolManager.createPacket(PacketType.Login.Server.ENCRYPTION_BEGIN, true);
//randomized server id to make sure the request is for our server
//this could be relevant http://www.sk89q.com/2011/09/minecraft-name-spoofing-exploit/
String serverId = Long.toString(random.nextLong(), 16);
newPacket.getStrings().write(0, serverId);
newPacket.getSpecificModifier(PublicKey.class).write(0, plugin.getServerKey().getPublic());
//generate a random token which should be the same when we receive it from the client
byte[] verifyToken = new byte[VERIFY_TOKEN_LENGTH];
@@ -129,7 +133,7 @@ public class StartPacketListener extends PacketAdapter {
protocolManager.sendServerPacket(player, newPacket);
//cancel only if the player has a paid account otherwise login as normal offline player
plugin.getSessions().put(sessionKey, new PlayerSession(verifyToken, username));
plugin.getSessions().put(sessionKey, new PlayerSession(username, serverId, verifyToken));
packetEvent.setCancelled(true);
} catch (InvocationTargetException ex) {
plugin.getLogger().log(Level.SEVERE, "Cannot send encryption packet. Falling back to normal login", ex);