1.12.2 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 !


  • Moddeurs confirmés Rédacteurs Administrateurs

    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 ?


  • Moddeurs confirmés Rédacteurs Administrateurs

    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 ?


  • Moddeurs confirmés Rédacteurs Administrateurs

    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());
            }
        }
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    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;
            }
        }
    }
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    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();
                }
            }
        }
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    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;
            }
        }
    }
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    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");
            }
        }
    }
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    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
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    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());
            }
        }
    

  • Moddeurs confirmés Rédacteurs Administrateurs

    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()
    

Log in to reply