Replaced insecure Minecraft account authentication with server join technique

This commit is contained in:
CrushedPixel
2015-05-27 13:35:44 +02:00
parent f0f0f1aa86
commit 2744e7cf6c
6 changed files with 75 additions and 6 deletions

View File

@@ -4,12 +4,15 @@ import com.google.gson.Gson;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.mojang.authlib.exceptions.AuthenticationException;
import eu.crushedpixel.replaymod.api.mojang.MojangApiMethods; import eu.crushedpixel.replaymod.api.mojang.MojangApiMethods;
import eu.crushedpixel.replaymod.api.mojang.holders.Profile; import eu.crushedpixel.replaymod.api.mojang.holders.Profile;
import eu.crushedpixel.replaymod.api.replay.ReplayModApiMethods; import eu.crushedpixel.replaymod.api.replay.ReplayModApiMethods;
import eu.crushedpixel.replaymod.api.replay.SearchQuery; import eu.crushedpixel.replaymod.api.replay.SearchQuery;
import eu.crushedpixel.replaymod.api.replay.holders.*; import eu.crushedpixel.replaymod.api.replay.holders.*;
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHash;
import eu.crushedpixel.replaymod.utils.StreamTools; import eu.crushedpixel.replaymod.utils.StreamTools;
import net.minecraft.client.Minecraft;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import java.io.File; import java.io.File;
@@ -24,6 +27,7 @@ import java.util.UUID;
public class ApiClient { public class ApiClient {
private static final Minecraft mc = Minecraft.getMinecraft();
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();
private static final JsonParser jsonParser = new JsonParser(); private static final JsonParser jsonParser = new JsonParser();
@@ -36,18 +40,32 @@ public class ApiClient {
return auth; return auth;
} }
public AuthKey register(String username, String mail, String password, String uuid, String accessToken) public AuthKey register(String username, String mail, String password, String uuid)
throws IOException, ApiException { throws IOException, ApiException, AuthenticationException {
AuthenticationHash authenticationHash = sessionserverJoin();
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.register); QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.register);
builder.put("username", username); builder.put("username", username);
builder.put("email", mail); builder.put("email", mail);
builder.put("password", password); builder.put("password", password);
builder.put("uuid", uuid); builder.put("uuid", uuid);
builder.put("accesstoken", accessToken); builder.put("mcusername", authenticationHash.username);
builder.put("timelong", authenticationHash.currentTime);
builder.put("randomlong", authenticationHash.randomLong);
AuthKey auth = invokeAndReturn(builder, AuthKey.class); AuthKey auth = invokeAndReturn(builder, AuthKey.class);
return auth; return auth;
} }
private AuthenticationHash sessionserverJoin() throws AuthenticationException {
AuthenticationHash hash = new AuthenticationHash();
mc.getSessionService().joinServer(
mc.getSession().getProfile(), mc.getSession().getToken(), hash.hash);
return hash;
}
public AuthConfirmation checkAuthkey(String auth) { public AuthConfirmation checkAuthkey(String auth) {
try { try {
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.check_authkey); QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.check_authkey);

View File

@@ -3,5 +3,6 @@ package eu.crushedpixel.replaymod.api.mojang;
public class MojangApiMethods { public class MojangApiMethods {
public static final String userprofile = "https://sessionserver.mojang.com/session/minecraft/profile/"; public static final String userprofile = "https://sessionserver.mojang.com/session/minecraft/profile/";
public static final String joinServer = "https://sessionserver.mojang.com/session/minecraft/join";
} }

View File

@@ -1,5 +1,6 @@
package eu.crushedpixel.replaymod.gui.online; package eu.crushedpixel.replaymod.gui.online;
import com.mojang.authlib.exceptions.AuthenticationException;
import eu.crushedpixel.replaymod.api.ApiException; import eu.crushedpixel.replaymod.api.ApiException;
import eu.crushedpixel.replaymod.gui.GuiConstants; import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.gui.PasswordTextField; import eu.crushedpixel.replaymod.gui.PasswordTextField;
@@ -196,6 +197,9 @@ public class GuiRegister extends GuiScreen {
}); });
} catch(ApiException ae) { } catch(ApiException ae) {
message = ae.getLocalizedMessage(); message = ae.getLocalizedMessage();
} catch(AuthenticationException aue) {
aue.printStackTrace();
message = I18n.format("replaymod.gui.register.error.authfailed");
} catch(Exception e) { } catch(Exception e) {
e.printStackTrace(); e.printStackTrace();
message = I18n.format("replaymod.gui.login.connectionerror"); message = I18n.format("replaymod.gui.login.connectionerror");

View File

@@ -1,5 +1,6 @@
package eu.crushedpixel.replaymod.online.authentication; package eu.crushedpixel.replaymod.online.authentication;
import com.mojang.authlib.exceptions.AuthenticationException;
import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.api.ApiClient; import eu.crushedpixel.replaymod.api.ApiClient;
import eu.crushedpixel.replaymod.api.ApiException; import eu.crushedpixel.replaymod.api.ApiException;
@@ -36,10 +37,10 @@ public class AuthenticationHandler {
private static Minecraft mc = Minecraft.getMinecraft(); private static Minecraft mc = Minecraft.getMinecraft();
public static void register(String usrname, String mail, String password) throws IOException, ApiException { public static void register(String usrname, String mail, String password)
throws IOException, ApiException, AuthenticationException {
AuthKey auth = apiClient.register(usrname, mail, password, AuthKey auth = apiClient.register(usrname, mail, password,
mc.getSession().getProfile().getId().toString(), mc.getSession().getProfile().getId().toString());
Minecraft.getMinecraft().getSession().getToken());
username = usrname; username = usrname;
authkey = auth.getAuthkey(); authkey = auth.getAuthkey();
saveAuthkey(authkey); saveAuthkey(authkey);

View File

@@ -0,0 +1,44 @@
package eu.crushedpixel.replaymod.online.authentication;
import net.minecraft.client.Minecraft;
import java.util.Random;
public class AuthenticationHash {
private static final Random random = new Random();
public AuthenticationHash() {
username = Minecraft.getMinecraft().getSession().getUsername();
currentTime = System.currentTimeMillis();
randomLong = random.nextLong();
hash = getAuthenticationHash();
}
public final String username;
public final long currentTime;
public final long randomLong;
public final String hash;
private String getAuthenticationHash() {
StringBuilder builder = new StringBuilder();
builder.append(username);
builder.append(currentTime);
builder.append(randomLong);
String md5 = builder.toString();
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
byte[] array = md.digest(md5.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; ++i) {
sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
}
return sb.toString();
} catch (java.security.NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -112,6 +112,7 @@ replaymod.gui.register.confirmpw=Confirm Password
replaymod.gui.register.error.nomatch=Passwords don't match replaymod.gui.register.error.nomatch=Passwords don't match
replaymod.gui.register.error.shortusername=Username has to be at least 5 characters long replaymod.gui.register.error.shortusername=Username has to be at least 5 characters long
replaymod.gui.register.error.shortpw=Password has to be at least 5 characters long replaymod.gui.register.error.shortpw=Password has to be at least 5 characters long
replaymod.gui.register.error.authfailed=Could not authenticate your Minecraft account
#Replay Viewer GUI #Replay Viewer GUI