mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-23 00:51:01 +03:00
[FEATURE] Защита от взлома лаунчера в LauncherRequest
This commit is contained in:
parent
a38853180b
commit
efd58d66c7
9 changed files with 56 additions and 11 deletions
|
@ -4,6 +4,7 @@
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
public class StdProtectHandler extends ProtectHandler {
|
public class StdProtectHandler extends ProtectHandler {
|
||||||
|
public boolean checkSecure = true;
|
||||||
@Override
|
@Override
|
||||||
public String generateSecureToken(AuthResponse.AuthContext context) {
|
public String generateSecureToken(AuthResponse.AuthContext context) {
|
||||||
return SecurityHelper.randomStringToken();
|
return SecurityHelper.randomStringToken();
|
||||||
|
@ -21,7 +22,7 @@ public boolean verifyClientSecureToken(String token, String secureKey) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
|
public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
|
||||||
return (context.authType == AuthResponse.ConnectTypes.CLIENT);
|
return (context.authType == AuthResponse.ConnectTypes.CLIENT) && (!checkSecure || context.client.isSecure);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -87,6 +87,10 @@ private void setStringField(String name, String value)
|
||||||
public void setGuardType(String key) {
|
public void setGuardType(String key) {
|
||||||
setStringField("guardType", key);
|
setStringField("guardType", key);
|
||||||
}
|
}
|
||||||
|
public void setSecureCheck(String hash, String salt) {
|
||||||
|
setStringField("secureCheckHash", hash);
|
||||||
|
setStringField("secureCheckSalt", salt);
|
||||||
|
}
|
||||||
|
|
||||||
private void push(final int value) {
|
private void push(final int value) {
|
||||||
if (value >= -1 && value <= 5)
|
if (value >= -1 && value <= 5)
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.SimpleFileVisitor;
|
import java.nio.file.SimpleFileVisitor;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
@ -133,6 +135,11 @@ public Path process(Path inputJar) throws IOException {
|
||||||
launcherConfigurator.setGuardType(server.config.launcher.guardType);
|
launcherConfigurator.setGuardType(server.config.launcher.guardType);
|
||||||
launcherConfigurator.setWarningMissArchJava(server.config.launcher.warningMissArchJava);
|
launcherConfigurator.setWarningMissArchJava(server.config.launcher.warningMissArchJava);
|
||||||
launcherConfigurator.setEnv(server.config.env);
|
launcherConfigurator.setEnv(server.config.env);
|
||||||
|
String launcherSalt = SecurityHelper.randomStringToken();
|
||||||
|
byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
|
||||||
|
server.runtime.clientCheckSecret.concat(".").concat(launcherSalt));
|
||||||
|
launcherConfigurator.setSecureCheck(Base64.getEncoder().encodeToString(launcherSecureHash), launcherSalt);
|
||||||
|
//LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash));
|
||||||
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
|
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
|
||||||
launcherConfigurator.setOemUnlockKey(server.runtime.oemUnlockKey);
|
launcherConfigurator.setOemUnlockKey(server.runtime.oemUnlockKey);
|
||||||
server.buildHookManager.registerAllClientModuleClass(launcherConfigurator);
|
server.buildHookManager.registerAllClientModuleClass(launcherConfigurator);
|
||||||
|
|
|
@ -7,13 +7,16 @@ public class LaunchServerRuntimeConfig {
|
||||||
public String clientToken;
|
public String clientToken;
|
||||||
public String oemUnlockKey;
|
public String oemUnlockKey;
|
||||||
public String registerApiKey;
|
public String registerApiKey;
|
||||||
|
public String clientCheckSecret;
|
||||||
|
|
||||||
public void verify() {
|
public void verify() {
|
||||||
if (clientToken == null) LogHelper.error("[RuntimeConfig] clientToken must not be null");
|
if (clientToken == null) LogHelper.error("[RuntimeConfig] clientToken must not be null");
|
||||||
|
if (clientCheckSecret == null) { LogHelper.warning("[RuntimeConfig] clientCheckSecret must not be null"); clientCheckSecret = SecurityHelper.randomStringToken(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
clientToken = SecurityHelper.randomStringToken();
|
clientToken = SecurityHelper.randomStringToken();
|
||||||
registerApiKey = SecurityHelper.randomStringToken();
|
registerApiKey = SecurityHelper.randomStringToken();
|
||||||
|
clientCheckSecret = SecurityHelper.randomStringToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||||
import pro.gravit.launcher.hwid.HWID;
|
import pro.gravit.launcher.hwid.HWID;
|
||||||
import pro.gravit.launcher.hwid.OshiHWID;
|
|
||||||
import pro.gravit.launcher.profiles.ClientProfile;
|
import pro.gravit.launcher.profiles.ClientProfile;
|
||||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||||
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
||||||
|
@ -72,7 +71,7 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
|
||||||
AuthProviderPair pair;
|
AuthProviderPair pair;
|
||||||
if (auth_id.isEmpty()) pair = server.config.getAuthProviderPair();
|
if (auth_id.isEmpty()) pair = server.config.getAuthProviderPair();
|
||||||
else pair = server.config.getAuthProviderPair(auth_id);
|
else pair = server.config.getAuthProviderPair(auth_id);
|
||||||
AuthContext context = new AuthContext(0, login, customText, client, null, ip, authType);
|
AuthContext context = new AuthContext(clientData, login, customText, client, hwid, ip, authType);
|
||||||
AuthProvider provider = pair.provider;
|
AuthProvider provider = pair.provider;
|
||||||
server.authHookManager.preHook.hook(context, clientData);
|
server.authHookManager.preHook.hook(context, clientData);
|
||||||
provider.preAuth(login, password, customText, ip);
|
provider.preAuth(login, password, customText, ip);
|
||||||
|
@ -131,24 +130,23 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AuthContext {
|
public static class AuthContext {
|
||||||
public AuthContext(long session, String login, String customText, String client, String hwid, String ip, ConnectTypes authType) {
|
public AuthContext(Client client, String login, String customText, String profileName, HWID hwid, String ip, ConnectTypes authType) {
|
||||||
this.session = session;
|
this.client = client;
|
||||||
this.login = login;
|
this.login = login;
|
||||||
this.customText = customText;
|
this.customText = customText;
|
||||||
this.client = client;
|
this.profileName = profileName;
|
||||||
this.hwid = hwid;
|
this.hwid = hwid;
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
this.authType = authType;
|
this.authType = authType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long session;
|
|
||||||
public String login;
|
public String login;
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public int password_length; //Use AuthProvider for get password
|
public int password_length; //Use AuthProvider for get password
|
||||||
public String client;
|
public String profileName;
|
||||||
public String hwid;
|
public HWID hwid;
|
||||||
public String customText;
|
public String customText;
|
||||||
public String ip;
|
public String ip;
|
||||||
public ConnectTypes authType;
|
public ConnectTypes authType;
|
||||||
|
public Client client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
import pro.gravit.utils.Version;
|
import pro.gravit.utils.Version;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
public class LauncherResponse extends SimpleResponse {
|
public class LauncherResponse extends SimpleResponse {
|
||||||
public Version version;
|
public Version version;
|
||||||
|
@ -15,6 +17,9 @@ public class LauncherResponse extends SimpleResponse {
|
||||||
public byte[] digest;
|
public byte[] digest;
|
||||||
public int launcher_type;
|
public int launcher_type;
|
||||||
|
|
||||||
|
public String secureHash;
|
||||||
|
public String secureSalt;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return "launcher";
|
return "launcher";
|
||||||
|
@ -33,6 +38,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
if (hash == null) service.sendObjectAndClose(ctx, new LauncherRequestEvent(true, server.config.netty.launcherURL));
|
if (hash == null) service.sendObjectAndClose(ctx, new LauncherRequestEvent(true, server.config.netty.launcherURL));
|
||||||
if (Arrays.equals(bytes, hash)) {
|
if (Arrays.equals(bytes, hash)) {
|
||||||
client.checkSign = true;
|
client.checkSign = true;
|
||||||
|
client.isSecure = checkSecure(secureHash, secureSalt);
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL));
|
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL));
|
||||||
} else {
|
} else {
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL));
|
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL));
|
||||||
|
@ -43,12 +49,21 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
if (hash == null) sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL));
|
if (hash == null) sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL));
|
||||||
if (Arrays.equals(bytes, hash)) {
|
if (Arrays.equals(bytes, hash)) {
|
||||||
client.checkSign = true;
|
client.checkSign = true;
|
||||||
|
client.isSecure = checkSecure(secureHash, secureSalt);
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL));
|
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL));
|
||||||
} else {
|
} else {
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL));
|
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL));
|
||||||
}
|
}
|
||||||
} else sendError("Request launcher type error");
|
} else sendError("Request launcher type error");
|
||||||
|
}
|
||||||
|
private boolean checkSecure(String hash, String salt)
|
||||||
|
{
|
||||||
|
if(hash == null || salt == null) return false;
|
||||||
|
byte[] normal_hash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
|
||||||
|
server.runtime.clientCheckSecret.concat(".").concat(salt));
|
||||||
|
byte[] launcher_hash = Base64.getDecoder().decode(hash);
|
||||||
|
//LogHelper.debug("[checkSecure] %s vs %s", Arrays.toString(normal_hash), Arrays.toString(launcher_hash));
|
||||||
|
return Arrays.equals(normal_hash, launcher_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ public class AutogenConfig {
|
||||||
public String guardLicenseName;
|
public String guardLicenseName;
|
||||||
public String guardLicenseKey;
|
public String guardLicenseKey;
|
||||||
public String guardLicenseEncryptKey;
|
public String guardLicenseEncryptKey;
|
||||||
|
public String secureCheckHash;
|
||||||
|
public String secureCheckSalt;
|
||||||
public int env;
|
public int env;
|
||||||
public boolean isWarningMissArchJava;
|
public boolean isWarningMissArchJava;
|
||||||
// 0 - Dev (дебаг включен по умолчанию, все сообщения)
|
// 0 - Dev (дебаг включен по умолчанию, все сообщения)
|
||||||
|
|
|
@ -43,10 +43,15 @@ public static AutogenConfig getAutogenConfig() {
|
||||||
public final String guardLicenseKey;
|
public final String guardLicenseKey;
|
||||||
public final String guardLicenseEncryptKey;
|
public final String guardLicenseEncryptKey;
|
||||||
public final String guardType;
|
public final String guardType;
|
||||||
|
|
||||||
|
public final String secureCheckHash;
|
||||||
|
public final String secureCheckSalt;
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException {
|
public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException {
|
||||||
publicKey = SecurityHelper.toPublicRSAKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
|
publicKey = SecurityHelper.toPublicRSAKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
|
||||||
|
secureCheckHash = config.secureCheckHash;
|
||||||
|
secureCheckSalt = config.secureCheckSalt;
|
||||||
projectname = config.projectname;
|
projectname = config.projectname;
|
||||||
clientPort = config.clientPort;
|
clientPort = config.clientPort;
|
||||||
secretKeyClient = config.secretKeyClient;
|
secretKeyClient = config.secretKeyClient;
|
||||||
|
@ -92,6 +97,8 @@ public LauncherConfig(String address, RSAPublicKey publicKey, Map<String, byte[]
|
||||||
isWarningMissArchJava = true;
|
isWarningMissArchJava = true;
|
||||||
isNettyEnabled = false;
|
isNettyEnabled = false;
|
||||||
environment = LauncherEnvironment.STD;
|
environment = LauncherEnvironment.STD;
|
||||||
|
secureCheckSalt = null;
|
||||||
|
secureCheckHash = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
|
@ -108,6 +115,8 @@ public LauncherConfig(String address, RSAPublicKey publicKey, Map<String, byte[]
|
||||||
isWarningMissArchJava = true;
|
isWarningMissArchJava = true;
|
||||||
isNettyEnabled = false;
|
isNettyEnabled = false;
|
||||||
environment = LauncherEnvironment.STD;
|
environment = LauncherEnvironment.STD;
|
||||||
|
secureCheckSalt = null;
|
||||||
|
secureCheckHash = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,10 @@ public final class LauncherRequest extends Request<LauncherRequestEvent> impleme
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public byte[] digest;
|
public byte[] digest;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
|
public String secureHash;
|
||||||
|
@LauncherNetworkAPI
|
||||||
|
public String secureSalt;
|
||||||
|
@LauncherNetworkAPI
|
||||||
public int launcher_type = EXE_BINARY ? 2 : 1;
|
public int launcher_type = EXE_BINARY ? 2 : 1;
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class);
|
public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class);
|
||||||
|
@ -89,6 +93,8 @@ public LauncherRequest() {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LogHelper.error(e);
|
LogHelper.error(e);
|
||||||
}
|
}
|
||||||
|
secureHash = Launcher.getConfig().secureCheckHash;
|
||||||
|
secureSalt = Launcher.getConfig().secureCheckSalt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue