Résolu Cacher les identifiants SQL au client ?
-
Bonjour,
Dans mon mod, j’ai besoin de me connecter à ma base SQL pour récupérer des infos sur le joueur.
J’aimerai savoir comment faire pour faire en sorte que le joueur ne puisse pas voir les identifiants de la base de données si il décompile le mod ?Voici ce que j’ai fais :
Classe principale
@EventHandler public void preInit(FMLPreInitializationEvent event) { logger = event.getModLog(); proxy.preInit(event.getSuggestedConfigurationFile()); this.sql = new SQL("jdbc:mysql://","url","hote","user","pass"); this.sql.connection(); } @EventHandler public void init(FMLInitializationEvent event) { proxy.init(); }
Classe SQL
public class SQL { private Connection connection; private String urlbase, host, database, user, pass; public String result; public SQL(String urlbase, String host, String database, String user, String pass){ this.urlbase = urlbase; this.host = host; this.database = database; this.user = user; this.pass = pass; } public Connection connection() { if(!this.isConnected()) { try { connection = DriverManager.getConnection(urlbase + host + "/" + database, user, pass); System.out.println("Successfully connected to database"); } catch (SQLException err) { System.out.println(err.getMessage()); } } return null; } public Connection deconnection() { if(this.isConnected()) { try { this.connection.close(); System.out.println("Disconnected from database"); } catch (SQLException err) { System.out.println(err.getMessage()); } } return null; } }
Merci d’avance !
-
Bonjour,
Le mieux est de ne pas distribuer la partie SQL au client.
Cette partie doit être uniquement sur le .jar du serveur.Et dans tous les cas, les identifiants ne doivent pas être en dur dans le code, il faut les charger depuis un fichier de configuration.
-
@robin4002 D’accord merci pour la réponse.
Alors justement, comment puis-je faire en sorte que ce ne soit que sur le .jar du serveur ? Y-a-t-il des tutos sur internet ? -
Ton code créant la connexion sql:
this.sql = new SQL("jdbc:mysql://","url","hote","user","pass"); this.sql.connection();
devrait être dans le serveur proxy plutôt que dans la classe principale.
Ensuite il suffira de supprimer la classe server proxy du .jar distribué au client (elle n’est jamais chargé en solo, donc aucun problème a qu’elle ne soit pas présente). -
Merci beaucoup.
Si je souhaite récupérer une valeur contenue dans la base, comment je dois m’y prendre pour que le client la recoive ? -
Il faut envoyer la valeur au client avec un paquet.
Le client ne doit jamais avoir un accès directe à la base. -
Par exemple, j’ai cette fonction dans ma classe SQLDatabase qui me permet de récupérer une valeur.
Comment dois-je faire pour que le client recoive la valeur ?public static void getValue(String table, String sectionRecover, String stringRecover, String recoverSection) { String returnString = null; try { Connection con = DriverManager.getConnection(urlbase + host + "/" + database, user, pass); Statement q = con.createStatement(); String sql = "SELECT * FROM " + table + " WHERE " + recoverSection + " = '" + stringRecover + "'"; ResultSet rs = q.executeQuery(sql); while (rs.next()) { returnString = rs.getString(sectionRecover); } q.close(); con.close(); result = returnString; } catch (SQLException err) { System.out.println(err.getMessage()); } }
-
Tu dois faire un paquet permettant au client de demander le variable et un paquet de réponse qui renvoie la variable une fois récupéré.
Par contre attention à tes variables, si le client a le contrôle sur table, recoverSection ou stringRecover tu as une grosse faille de sécurité.
-
J’ai essayé de faire quelque chose mais bon… je ne suis pas sûr du tout, ça ne fonctionne pas le jeu crash lorsque je fais la commande
EDIT : non en fait le jeu ne crash pas, j’ai cette erreur dans la console :
No suitable driver found for nullnull/null
Alors qu’au niveau de la connexion dans le ServerProxy ça a l’air de bien fonctionner
Classe principale
@EventHandler public void preInit(FMLPreInitializationEvent event) { logger = event.getModLog(); proxy.preInit(event.getSuggestedConfigurationFile()); network = NetworkRegistry.INSTANCE.newSimpleChannel(MODID); network.registerMessage(PacketSimpleCommand.Handler.class, PacketSimpleCommand.class, 0, Side.CLIENT); network.registerMessage(PacketSQLGetResult.Handler.class, PacketSQLGetResult.class, 1, Side.SERVER); }
Commande
public class SimpleCommand extends CommandBase { @Override public String getName() { return "getplayerdata"; } @Override public String getUsage(ICommandSender sender) { return null; } @Override public boolean checkPermission(MinecraftServer server, ICommandSender sender) { return true; } @Override public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { if(sender instanceof EntityPlayer) { Main.network.sendTo(new PacketSimpleCommand("getplayerdata"), (EntityPlayerMP) sender); } } }
Packet commande
public class PacketSimpleCommand implements IMessage { private static String command_name; public PacketSimpleCommand() { } public PacketSimpleCommand(String command_name) { this.command_name = command_name; } @Override public void fromBytes(ByteBuf buf) { command_name = ByteBufUtils.readUTF8String(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeUTF8String(buf, command_name); } public static class Handler implements IMessageHandler<PacketSimpleCommand, IMessage> { public SQLDatabase sql; @SideOnly(Side.CLIENT) @Override public IMessage onMessage(PacketSimpleCommand message, MessageContext ctx) { if (command_name.equals("getplayerdata")) { SQLDatabase.getValue("users", "grade", "" + Minecraft.getMinecraft().player.getDisplayNameString(), "pseudo"); } return null; } } }
Fonction SQL
public static void getValue(String table, String sectionRecover, String stringRecover, String recoverSection) { String returnString = null; try { Connection con = DriverManager.getConnection(urlbase + host + "/" + database, user, pass); System.out.println("Successfully connected to database"); Statement q = con.createStatement(); String sql = "SELECT * FROM " + table + " WHERE " + recoverSection + " = '" + stringRecover + "'"; ResultSet rs = q.executeQuery(sql); while (rs.next()) { returnString = rs.getString(sectionRecover); } q.close(); con.close(); Main.network.sendToServer(new PacketSQLGetResult(returnString)); } catch (SQLException err) { System.out.println(err.getMessage()); } }
Packet fonction SQL
public class PacketSQLGetResult implements IMessage { private static String result; public PacketSQLGetResult() { } public PacketSQLGetResult(String result) { this.result = result; } @Override public void fromBytes(ByteBuf buf) { result = ByteBufUtils.readUTF8String(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeUTF8String(buf, result); } public static class Handler implements IMessageHandler<PacketSQLGetResult, IMessage> { @SideOnly(Side.CLIENT) @Override public IMessage onMessage(PacketSQLGetResult message, MessageContext ctx) { System.out.println(message.result); return null; } } }
-
Tes variables urlbase, host, + database, user et pass ne semble pas initialisé.
Impossible de savoir pourquoi avec le morceau de code que tu as envoyé. -
Voici la classe complète que j’ai modifiée, et en dessous le ServerProxy + le morceau qui correspond sur la classe principale
public class SQLDatabase { private Connection connection; public static String urlbase, host, database, user, pass; public static String result; public SQLDatabase(String urlbase, String host, String database, String user, String pass){ this.urlbase = urlbase; this.host = host; this.database = database; this.user = user; this.pass = pass; System.out.println("Database successfully attached"); } public static void getValue(String table, String sectionRecover, String stringRecover, String recoverSection) { String returnString = null; try { Connection con = DriverManager.getConnection(urlbase + host + "/" + database, user, pass); System.out.println("Successfully connected to database"); Statement q = con.createStatement(); String sql = "SELECT * FROM " + table + " WHERE " + recoverSection + " = '" + stringRecover + "'"; ResultSet rs = q.executeQuery(sql); while (rs.next()) { returnString = rs.getString(sectionRecover); } q.close(); con.close(); Main.network.sendToServer(new PacketSQLGetResult(returnString)); } catch (SQLException err) { System.out.println(err.getMessage()); } } }
ServerProxy
public class ServerProxy extends CommonProxy { public SQLDatabase sql; public static String host, database, user, pass; @Override public void preInit(File configFile) { super.preInit(configFile); System.out.println("ServerProxy loaded"); } @Override public void init() { this.sql = new SQLDatabase("jdbc:mysql://", Main.host, Main.database, Main.user, Main.pass); super.init(); } }
Classe principale
@SideOnly(Side.SERVER) @EventHandler public void loadConfig(FMLPreInitializationEvent event) { Configuration cfg = new Configuration(event.getSuggestedConfigurationFile()); try { cfg.load(); host = cfg.get("MySQL", "host", "").getString(); database = cfg.get("MySQL", "database", "").getString(); user = cfg.get("MySQL", "user", "").getString(); pass = cfg.get("MySQL", "pass", "").getString(); System.out.println("Configuration loaded"); } catch(Exception ex) { System.out.println("Failed to load configuration"); } finally { if(cfg.hasChanged()) { cfg.save(); } } }
-
Tes variables host, database, user, pass de ta classe ServerProxy ne sont pas les mêmes que celle dans la classe principale.
Là tes variables dans le serveur proxy sont null et jamais initialisé …Le mieux serait de charger les config en rapport avec mysql dans le serveur proxy également.
-
J’ai fais ceci pour le ServerProxy, ça a l’air d’être ok :
public class ServerProxy extends CommonProxy { public SQLDatabase sql; public static String host, database, user, pass; public static Configuration config; private static String file = "config/" + Main.MODID + ".cfg"; @Override public void preInit(File configFile) { super.preInit(configFile); System.out.println("ServerProxy loaded"); Configuration cfg = new Configuration(new File(file)); try { cfg.load(); host = cfg.get("MySQL", "host", "").getString(); database = cfg.get("MySQL", "database", "").getString(); user = cfg.get("MySQL", "user", "").getString(); pass = cfg.get("MySQL", "pass", "").getString(); System.out.println("Configuration loaded"); this.sql = new SQLDatabase("jdbc:mysql://", host, database, user, pass); } catch(Exception ex) { System.out.println("Failed to load configuration"); } finally { if(cfg.hasChanged()) { cfg.save(); } } } @Override public void init() { super.init(); }
Par contre j’ai un autre soucis maintenant, lorsque je veux print par exemple le résultat de la requête, rien n’apparait et le paquet ne marche pas. Voici la partie concernée :
private Connection connection; public static String urlbase, host, database, user, pass; public static String result; public SQLDatabase(String urlbase, String host, String database, String user, String pass){ this.urlbase = urlbase; this.host = host; this.database = database; this.user = user; this.pass = pass; System.out.println("Database successfully attached with : " + urlbase + " " + host + " " + database + " " + user + " " + pass); } public static void getValue(String table, String sectionRecover, String stringRecover, String recoverSection) { String returnString = null; try { Connection con = DriverManager.getConnection(urlbase + host + "/" + database, user, pass); System.out.println("Successfully connected to database"); Statement q = con.createStatement(); String sql = "SELECT * FROM " + table + " WHERE " + recoverSection + " = '" + stringRecover + "'"; ResultSet rs = q.executeQuery(sql); while (rs.next()) { returnString = rs.getString(sectionRecover); } q.close(); con.close(); System.out.println("test"); System.out.println(returnString); Main.network.sendToServer(new PacketSQLGetResult(returnString)); } catch (SQLException err) { System.out.println(err.getMessage()); } }
Commande
public class SimpleCommand extends CommandBase { @Override public String getName() { return "getplayerdata"; } @Override public String getUsage(ICommandSender sender) { return null; } @Override public boolean checkPermission(MinecraftServer server, ICommandSender sender) { return true; } @Override public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { if(sender instanceof EntityPlayer) { Main.network.sendTo(new PacketSimpleCommand("getplayerdata"), (EntityPlayerMP) sender); } } }
Packet de la commande
public class PacketSimpleCommand implements IMessage { private static String command_name; public PacketSimpleCommand() { } public PacketSimpleCommand(String command_name) { this.command_name = command_name; } @Override public void fromBytes(ByteBuf buf) { command_name = ByteBufUtils.readUTF8String(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeUTF8String(buf, command_name); } public static class Handler implements IMessageHandler<PacketSimpleCommand, IMessage> { public SQLDatabase sql; @SideOnly(Side.CLIENT) @Override public IMessage onMessage(PacketSimpleCommand message, MessageContext ctx) { if (command_name.equals("getplayerdata")) { SQLDatabase.getValue("users", "grade", "" + Minecraft.getMinecraft().player.getDisplayNameString(), "pseudo"); } return null; } } }
Packet résultat SQL
public class PacketSQLGetResult implements IMessage { private static String result; public PacketSQLGetResult() { } public PacketSQLGetResult(String result) { this.result = result; } @Override public void fromBytes(ByteBuf buf) { result = ByteBufUtils.readUTF8String(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeUTF8String(buf, result); } public static class Handler implements IMessageHandler<PacketSQLGetResult, IMessage> { @SideOnly(Side.CLIENT) @Override public IMessage onMessage(PacketSQLGetResult message, MessageContext ctx) { System.out.println(message.result); return null; } } }
-
Quand tu tapes une commande, l’exécution se fait sur le serveur.
Donc pour ce cas, il faut que tu appels la fonction sql directement dans la fonction exécute de ta commande puis que tu envoies la réponse par paquet. -
J’obtiens cette erreur :
[21:19:19] [main/INFO] [minecraft/GuiNewChat]: [CHAT] Cette commande a échoué suite à une erreur inconnue
Commande :
public class SimpleCommand extends CommandBase { @Override public String getName() { return "getplayerdata"; } @Override public String getUsage(ICommandSender sender) { return null; } @Override public boolean checkPermission(MinecraftServer server, ICommandSender sender) { return true; } @Override public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { if(sender instanceof EntityPlayer) { SQLDatabase.getValue("users", "grade", "" + Minecraft.getMinecraft().player.getDisplayNameString(), "pseudo"); } } }
-
Rien d’autre dans la console ?
Si oui, mets l’appel de ta fonction getValue dans un try catch et log l’exception. -
Effectivement, l’erreur contient ceci également :
[21:59:00] [Server thread/WARN] [minecraft/CommandHandler]: Couldn't process command: getplayerdata java.lang.NoClassDefFoundError: net/minecraft/client/Minecraft at fr.minewarfare.commands.SimpleCommand.execute(SimpleCommand.java:35) ~[SimpleCommand.class:?] at net.minecraft.command.CommandHandler.tryExecute(CommandHandler.java:126) [CommandHandler.class:?] at net.minecraft.command.CommandHandler.executeCommand(CommandHandler.java:98) [CommandHandler.class:?] at net.minecraft.network.NetHandlerPlayServer.handleSlashCommand(NetHandlerPlayServer.java:1003) [NetHandlerPlayServer.class:?] at net.minecraft.network.NetHandlerPlayServer.processChatMessage(NetHandlerPlayServer.java:979) [NetHandlerPlayServer.class:?] at net.minecraft.network.play.client.CPacketChatMessage.processPacket(CPacketChatMessage.java:47) [CPacketChatMessage.class:?] at net.minecraft.network.play.client.CPacketChatMessage.processPacket(CPacketChatMessage.java:8) [CPacketChatMessage.class:?] at net.minecraft.network.PacketThreadUtil$1.run(PacketThreadUtil.java:21) [PacketThreadUtil$1.class:?] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_201] at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [?:1.8.0_201] at java.util.concurrent.FutureTask.run(FutureTask.java) [?:1.8.0_201] at net.minecraft.util.Util.runTask(Util.java:53) [Util.class:?] at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:798) [MinecraftServer.class:?] at net.minecraft.server.dedicated.DedicatedServer.updateTimeLightAndEntities(DedicatedServer.java:415) [DedicatedServer.class:?] at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:743) [MinecraftServer.class:?] at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:592) [MinecraftServer.class:?] at java.lang.Thread.run(Thread.java:748) [?:1.8.0_201] Caused by: java.lang.ClassNotFoundException: net.minecraft.client.Minecraft at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:191) ~[launchwrapper-1.12.jar:?] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_201] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_201] ... 17 more Caused by: net.minecraftforge.fml.common.asm.ASMTransformerWrapper$TransformerException: Exception in class transformer net.minecraftforge.fml.common.asm.transformers.SideTransformer@59bbb974 from coremod FMLCorePlugin at net.minecraftforge.fml.common.asm.ASMTransformerWrapper$TransformerWrapper.transform(ASMTransformerWrapper.java:260) ~[forgeSrc-1.12.2-14.23.5.2768.jar:?] at net.minecraft.launchwrapper.LaunchClassLoader.runTransformers(LaunchClassLoader.java:279) ~[launchwrapper-1.12.jar:?] at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:176) ~[launchwrapper-1.12.jar:?] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_201] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_201] ... 17 more Caused by: java.lang.RuntimeException: Attempted to load class net/minecraft/client/Minecraft for invalid side SERVER at net.minecraftforge.fml.common.asm.transformers.SideTransformer.transform(SideTransformer.java:62) ~[forgeSrc-1.12.2-14.23.5.2768.jar:?] at net.minecraftforge.fml.common.asm.ASMTransformerWrapper$TransformerWrapper.transform(ASMTransformerWrapper.java:256) ~[forgeSrc-1.12.2-14.23.5.2768.jar:?] at net.minecraft.launchwrapper.LaunchClassLoader.runTransformers(LaunchClassLoader.java:279) ~[launchwrapper-1.12.jar:?] at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:176) ~[launchwrapper-1.12.jar:?] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_201] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_201] ... 17 more
-
Ah oui, c’est à cause du
Minecraft.getMinecraft().player
dans ta fonction execute. Il n’est pas possible d’utiliser la classe Minecraft côté serveur.
Et dans ton cas il suffit de faire(EntityPlayer)sender
pour récupérer le joueur qui a exécuté la commande. -
C’est bon, j’ai une autre erreur maintenant, ça doit venir du (EntityPlayer)sender, ça doit fausser la requête SQL.
J’ai essayé avec (EntityPlayer)sender.getDisplayName() ça ne fonctionne pas non plus (ça correspond au stringRecover)[22:18:24] [Server thread/INFO] [STDOUT]: [fr.minewarfare.SQLDatabase:getValue:26]: Successfully connected to database [22:18:24] [Server thread/INFO] [STDOUT]: [fr.minewarfare.SQLDatabase:getValue:42]: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Cobra45'/200, l='world', x=259,30, y=76,00, z=-114,15]'' at line 1
public static void getValue(String table, String sectionRecover, String stringRecover, String recoverSection) { String returnString = null; try { Connection con = DriverManager.getConnection(urlbase + host + "/" + database, user, pass); System.out.println("Successfully connected to database"); Statement q = con.createStatement(); String sql = "SELECT * FROM " + table + " WHERE " + recoverSection + " = '" + stringRecover + "'"; ResultSet rs = q.executeQuery(sql); while (rs.next()) { returnString = rs.getString(sectionRecover); } q.close(); con.close(); Main.network.sendToServer(new PacketSQLGetResult(returnString)); } catch (SQLException err) { System.out.println(err.getMessage()); } }
-
C’est comme ça la bonne syntaxe pour appeler une fonction d’une variable cast :
((EntityPlayer)sender).getDisplayName()
Ou alors :
EntityPlayer player = (EntityPlayer)sender; player.getDisplayName()