mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-23 09:01:08 +03:00
[FEATURE] Command SecurityCheck
This commit is contained in:
parent
438133bce7
commit
78c0e0d54d
4 changed files with 217 additions and 1 deletions
|
@ -78,6 +78,7 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
||||||
service.registerCommand("clients", new ClientsCommand(server));
|
service.registerCommand("clients", new ClientsCommand(server));
|
||||||
service.registerCommand("signJar", new SignJarCommand(server));
|
service.registerCommand("signJar", new SignJarCommand(server));
|
||||||
service.registerCommand("signDir", new SignDirCommand(server));
|
service.registerCommand("signDir", new SignDirCommand(server));
|
||||||
|
service.registerCommand("securitycheck", new SecurityCheckCommand(server));
|
||||||
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
|
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
|
||||||
handler.registerCategory(serviceCategory);
|
handler.registerCategory(serviceCategory);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
package pro.gravit.launchserver.command.service;
|
||||||
|
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||||
|
import org.bouncycastle.util.Store;
|
||||||
|
import org.fusesource.jansi.Ansi;
|
||||||
|
import pro.gravit.launcher.profiles.ClientProfile;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.handler.MemoryAuthHandler;
|
||||||
|
import pro.gravit.launchserver.auth.protect.AdvancedProtectHandler;
|
||||||
|
import pro.gravit.launchserver.auth.protect.NoProtectHandler;
|
||||||
|
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||||
|
import pro.gravit.launchserver.auth.provider.AcceptAuthProvider;
|
||||||
|
import pro.gravit.launchserver.command.Command;
|
||||||
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
|
import pro.gravit.launchserver.helper.SignHelper;
|
||||||
|
import pro.gravit.utils.helper.FormatHelper;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
public class SecurityCheckCommand extends Command {
|
||||||
|
public SecurityCheckCommand(LaunchServer server) {
|
||||||
|
super(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getArgsDescription() {
|
||||||
|
return "[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsageDescription() {
|
||||||
|
return "check configuration";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(String... args) throws Exception {
|
||||||
|
LaunchServerConfig config = server.config;
|
||||||
|
config.auth.forEach((name, pair) -> {
|
||||||
|
if(pair.provider instanceof AcceptAuthProvider) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, String.format("auth.%s.provider", name), "Accept auth provider", false);
|
||||||
|
} else {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, String.format("auth.%s.provider", name), "", true);
|
||||||
|
}
|
||||||
|
if(pair.handler instanceof MemoryAuthHandler) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, String.format("auth.%s.handler", name), "MemoryAuthHandler test-only", false);
|
||||||
|
} else {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, String.format("auth.%s.handler", name), "", true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(config.protectHandler instanceof NoProtectHandler) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "protectHandler", "protectHandler none", false);
|
||||||
|
}
|
||||||
|
else if(config.protectHandler instanceof AdvancedProtectHandler) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "protectHandler", "", true);
|
||||||
|
if(!((AdvancedProtectHandler) config.protectHandler).enableHardwareFeature)
|
||||||
|
{
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "protectHandler.hardwareId", "you can improve security by using hwid provider", null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "protectHandler.hardwareId", "", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(config.protectHandler instanceof StdProtectHandler) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "protectHandler", "you can improve security by using advanced", null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "protectHandler", "unknown protectHandler", null);
|
||||||
|
}
|
||||||
|
if(config.netty.address.startsWith("ws://")) {
|
||||||
|
if(config.netty.ipForwarding)
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.ipForwarding", "ipForwarding may be used to spoofing ip", null);
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.address", "websocket connection not secure", false);
|
||||||
|
} else if(config.netty.address.startsWith("wss://")) {
|
||||||
|
if(!config.netty.ipForwarding)
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.ipForwarding", "ipForwarding not enabled. authLimiter may be get incorrect ip", null);
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.address", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config.netty.sendExceptionEnabled) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.sendExceptionEnabled", "recommend \"false\" in production", false);
|
||||||
|
} else {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.sendExceptionEnabled", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config.netty.launcherURL.startsWith("http://")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.launcherUrl", "launcher jar download connection not secure", false);
|
||||||
|
} else if(config.netty.launcherURL.startsWith("https://")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.launcherUrl", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config.netty.launcherEXEURL.startsWith("http://")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.launcherExeUrl", "launcher exe download connection not secure", false);
|
||||||
|
} else if(config.netty.launcherEXEURL.startsWith("https://")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.launcherExeUrl", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config.netty.downloadURL.startsWith("http://")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.downloadUrl", "assets/clients download connection not secure", false);
|
||||||
|
} else if(config.netty.downloadURL.startsWith("https://")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "netty.downloadUrl", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!config.sign.enabled) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "sign", "it is recommended to use a signature", null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*boolean bad = false;
|
||||||
|
KeyStore keyStore = SignHelper.getStore(new File(config.sign.keyStore).toPath(), config.sign.keyStorePass, config.sign.keyStoreType);
|
||||||
|
X509Certificate[] certChain = (X509Certificate[]) keyStore.getCertificateChain(config.sign.keyAlias);
|
||||||
|
X509Certificate cert = (X509Certificate) keyStore.getCertificate(config.sign.keyAlias);
|
||||||
|
cert.checkValidity();
|
||||||
|
if(certChain.length <= 1) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "sign", "certificate chain contains <2 element(recommend 2 and more)", false);
|
||||||
|
bad = true;
|
||||||
|
}
|
||||||
|
if((cert.getBasicConstraints() & 1) != 0) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "sign", "end certificate - CA", false);
|
||||||
|
bad = true;
|
||||||
|
}
|
||||||
|
for(X509Certificate certificate : certChain)
|
||||||
|
{
|
||||||
|
certificate.checkValidity();
|
||||||
|
}
|
||||||
|
if(!bad)*/
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "sign", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!config.launcher.enabledProGuard) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "launcher.enabledProGuard", "proguard not enabled", false);
|
||||||
|
} else {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "launcher.enabledProGuard", "", true);
|
||||||
|
}
|
||||||
|
if(!config.launcher.stripLineNumbers) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "launcher.stripLineNumbers", "stripLineNumbers not enabled", false);
|
||||||
|
} else {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "launcher.stripLineNumbers", "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (config.env)
|
||||||
|
{
|
||||||
|
|
||||||
|
case DEV:
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "env", "found env DEV", false);
|
||||||
|
break;
|
||||||
|
case DEBUG:
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "env", "found env DEBUG", false);
|
||||||
|
break;
|
||||||
|
case STD:
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "env", "you can improve security by using env PROD", null);
|
||||||
|
break;
|
||||||
|
case PROD:
|
||||||
|
printCheckResult(LogHelper.Level.INFO, "env", "", true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Profiles
|
||||||
|
for(ClientProfile profile : server.getProfiles())
|
||||||
|
{
|
||||||
|
boolean bad = false;
|
||||||
|
String profileModuleName = String.format("profiles.%s", profile.getTitle());
|
||||||
|
for(String exc : profile.getUpdateExclusions())
|
||||||
|
{
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(exc, "\\/");
|
||||||
|
if(exc.endsWith(".jar")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, profileModuleName, String.format("updateExclusions %s not safe. Cheats may be injected very easy!", exc), false);
|
||||||
|
bad = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(tokenizer.hasMoreTokens() && tokenizer.nextToken().equals("mods"))
|
||||||
|
{
|
||||||
|
if(!tokenizer.hasMoreTokens()) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, profileModuleName, String.format("updateExclusions %s not safe. Cheats may be injected very easy!", exc), false);
|
||||||
|
bad = true;
|
||||||
|
} else {
|
||||||
|
String nextToken = tokenizer.nextToken();
|
||||||
|
if(nextToken.equals("memory_repo") || nextToken.equals("1.12.2") || nextToken.equals("1.7.10")) {
|
||||||
|
printCheckResult(LogHelper.Level.INFO, profileModuleName, String.format("updateExclusions %s not safe. Cheats may be injected very easy!", exc), false);
|
||||||
|
bad = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!bad)
|
||||||
|
printCheckResult(LogHelper.Level.INFO, profileModuleName, "", true);
|
||||||
|
}
|
||||||
|
LogHelper.info("Check completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printCheckResult(LogHelper.Level level, String module, String comment, Boolean status)
|
||||||
|
{
|
||||||
|
LogHelper.rawLog(() -> FormatHelper.rawFormat(level, LogHelper.getDataTime(), false).concat(String.format("[%s] %s - %s", module, comment, status == null ? "WARN" : (status ? "OK" : "FAIL"))),
|
||||||
|
() -> FormatHelper.rawAnsiFormat(level, LogHelper.getDataTime(), false)
|
||||||
|
.fgBright(Ansi.Color.WHITE)
|
||||||
|
.a("[")
|
||||||
|
.fgBright(Ansi.Color.BLUE)
|
||||||
|
.a(module)
|
||||||
|
.fgBright(Ansi.Color.WHITE)
|
||||||
|
.a("] ".concat(comment).concat(" - "))
|
||||||
|
.fgBright(status == null ? Ansi.Color.YELLOW : (status ? Ansi.Color.GREEN : Ansi.Color.RED))
|
||||||
|
.a(status == null ? "WARN" : (status ? "OK" : "FAIL"))
|
||||||
|
.reset().toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,6 +75,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
|
|
||||||
newConfig.netty = new NettyConfig();
|
newConfig.netty = new NettyConfig();
|
||||||
newConfig.netty.fileServerEnabled = true;
|
newConfig.netty.fileServerEnabled = true;
|
||||||
|
newConfig.netty.sendExceptionEnabled = false;
|
||||||
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
||||||
newConfig.netty.performance = new NettyPerformanceConfig();
|
newConfig.netty.performance = new NettyPerformanceConfig();
|
||||||
try {
|
try {
|
||||||
|
@ -111,7 +112,6 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
regLimiterComponent.rateLimitMillis = 1000 * 60 * 60 * 10; //Блок на 10 часов
|
regLimiterComponent.rateLimitMillis = 1000 * 60 * 60 * 10; //Блок на 10 часов
|
||||||
regLimiterComponent.message = "Превышен лимит регистраций";
|
regLimiterComponent.message = "Превышен лимит регистраций";
|
||||||
newConfig.components.put("regLimiter", regLimiterComponent);
|
newConfig.components.put("regLimiter", regLimiterComponent);
|
||||||
newConfig.netty.sendExceptionEnabled = true;
|
|
||||||
return newConfig;
|
return newConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,10 @@ public String getAssetDir() {
|
||||||
return assetDir;
|
return assetDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getUpdateExclusions() {
|
||||||
|
return Collections.unmodifiableList(updateExclusions);
|
||||||
|
}
|
||||||
|
|
||||||
public FileNameMatcher getClientUpdateMatcher(/*boolean excludeOptional*/) {
|
public FileNameMatcher getClientUpdateMatcher(/*boolean excludeOptional*/) {
|
||||||
String[] updateArray = update.toArray(new String[0]);
|
String[] updateArray = update.toArray(new String[0]);
|
||||||
String[] verifyArray = updateVerify.toArray(new String[0]);
|
String[] verifyArray = updateVerify.toArray(new String[0]);
|
||||||
|
|
Loading…
Reference in a new issue