Fixed SQL injection vulnerability in the MySQL logging feature. Using

Hikari library to automatically reconnect to database. Thanks to
metalshark setting this up.
This commit is contained in:
Aust1n46 2020-03-25 17:44:03 -04:00
parent 6b275a1cba
commit d7858a791a
79 changed files with 107 additions and 228 deletions

View File

@ -21,5 +21,6 @@
<classpathentry kind="lib" path="C:/Users/Austin/Desktop/Mineverse Network/Servers/Hub/spigot-1.13.2.jar"/>
<classpathentry kind="lib" path="C:/Users/Austin/Desktop/Mineverse Network/Servers/Hub/spigot-1.14.4.jar"/>
<classpathentry kind="lib" path="C:/Users/Austin/Desktop/Mineverse Network/Servers/Hub/spigot-1.15.jar"/>
<classpathentry kind="lib" path="lib"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -12,9 +12,6 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
@ -87,6 +84,7 @@ import mineverse.Aust1n46.chat.command.mute.Mute;
import mineverse.Aust1n46.chat.command.mute.Muteall;
import mineverse.Aust1n46.chat.command.mute.Unmute;
import mineverse.Aust1n46.chat.command.mute.Unmuteall;
import mineverse.Aust1n46.chat.database.Database;
import mineverse.Aust1n46.chat.database.MySQL;
import mineverse.Aust1n46.chat.database.PlayerData;
import mineverse.Aust1n46.chat.gui.GuiSlotInfo;
@ -99,6 +97,8 @@ import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
@ -136,13 +136,8 @@ public class MineverseChat extends JavaPlugin implements PluginMessageListener {
private MineverseCommandExecutor commandExecutor;
private Map<String, MineverseCommand> commands = new HashMap<String, MineverseCommand>();
// MySQL ------------------------------------
public Connection c = null;
public MySQL MySQL;
public boolean mysql = false;
// SQLite -------------------------------------
// public Connection lite = null;
// Database ------------------------------------
public Database db = null;
// Misc --------------------------------
public static AliasInfo aaInfo;
@ -179,6 +174,8 @@ public class MineverseChat extends JavaPlugin implements PluginMessageListener {
@Deprecated
public static ChatChannelInfo ccInfo;
public static void main(String[] args) {}
@Override
public void onEnable() {
ccInfo = new ChatChannelInfo();
@ -287,19 +284,16 @@ public class MineverseChat extends JavaPlugin implements PluginMessageListener {
onlinePlayers.add(mcp);
}
if(this.getConfig().getConfigurationSection("mysql").getBoolean("enabled")) {
this.MySQL = new MySQL(this, getConfig().getConfigurationSection("mysql").getString("host"), getConfig().getConfigurationSection("mysql").getString("port"), getConfig().getConfigurationSection("mysql").getString("database"), getConfig().getConfigurationSection("mysql").getString("user"), getConfig().getConfigurationSection("mysql").getString("password"));
this.mysql = true;
try {
c = MySQL.openConnection();
Statement statement = c.createStatement();
statement.executeUpdate("CREATE TABLE IF NOT EXISTS `VentureChat` (`rowid` INT(7) NOT NULL AUTO_INCREMENT, `ChatTime` TEXT(100), `UUID` TEXT(100), `Name` TEXT(100), `Server` TEXT(100), `Channel` TEXT(100), `Text` TEXT(300), `Type` TEXT(100), PRIMARY KEY (rowid));");
Bukkit.getConsoleSender().sendMessage(Format.FormatStringAll("&8[&eVentureChat&8]&e - Connecting to MySQL Database"));
}
catch(ClassNotFoundException | SQLException e) {
Bukkit.getConsoleSender().sendMessage(Format.FormatStringAll("&8[&eVentureChat&8]&e - &cFailed to connect to MySQL Database, Reason: " + e));
this.mysql = false;
}
FileConfiguration config = getConfig();
ConfigurationSection mysqlConfig = config.getConfigurationSection("mysql");
if (this.getConfig().getConfigurationSection("mysql").getBoolean("enabled")) {
String host = mysqlConfig.getString("host");
int port = mysqlConfig.getInt("port");
String database = mysqlConfig.getString("database");
String user = mysqlConfig.getString("user");
String password = mysqlConfig.getString("password");
db = new MySQL(host, port, database, user, password);
db.init();
}
commands.put("broadcast", new Broadcast("broadcast"));

View File

@ -1,27 +1,44 @@
package mineverse.Aust1n46.chat.database;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.bukkit.plugin.Plugin;
import org.bukkit.Bukkit;
import com.zaxxer.hikari.HikariDataSource;
import mineverse.Aust1n46.chat.MineverseChat;
//Parent class for both the MySQL and SQLite database classes.
public abstract class Database {
protected Plugin plugin;
protected Database(Plugin plugin) {
this.plugin = plugin;
protected HikariDataSource dataSource = null;
public abstract void init();
public void writeVentureChat(String time, String uuid, String name, String server, String channel, String text, String type) {
MineverseChat plugin = MineverseChat.getInstance();
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
final Connection conn = dataSource.getConnection();
conn.setAutoCommit(false);
final PreparedStatement statement = conn.prepareStatement(
"INSERT INTO VentureChat " +
"(ChatTime, UUID, Name, Server, Channel, Text, Type) " +
"VALUES (?, ?, ?, ?, ?, ?, ?)");
statement.setString(1, time);
statement.setString(2, uuid);
statement.setString(3, name);
statement.setString(4, server);
statement.setString(5, channel);
statement.setString(6, text);
statement.setString(7, type);
statement.executeUpdate();
conn.commit();
} catch(SQLException e) {
throw new RuntimeException(e);
}
});
}
public abstract Connection openConnection() throws SQLException, ClassNotFoundException;
public abstract boolean checkConnection() throws SQLException;
public abstract Connection getConnection();
public abstract boolean closeConnection() throws SQLException;
public abstract ResultSet querySQL(String query) throws SQLException, ClassNotFoundException;
public abstract int updateSQL(String query) throws SQLException, ClassNotFoundException;
}

View File

@ -1,29 +0,0 @@
package mineverse.Aust1n46.chat.database;
import java.sql.SQLException;
import mineverse.Aust1n46.chat.MineverseChat;
//This class opens the connection to the database if it's enabled.
public class DatabaseSender {
private static MineverseChat plugin = MineverseChat.getInstance();
public static void writeToMySQL(String time, String uuid, String name, String server, String channel, String text, String type, String timeValue, String uuidValue, String nameValue, String serverValue, String channelValue, String textValue, String typeValue) {
try {
if(plugin.c.isClosed()) {
try {
plugin.c = plugin.MySQL.openConnection();
}
catch(ClassNotFoundException e) {
e.printStackTrace();
return;
}
}
plugin.c.createStatement().executeUpdate("INSERT INTO `VentureChat` (`" + time + "`, `" + uuid + "`, `" + name + "`, `" + server + "`, `" + channel + "`, `" + text + "`, `" + type + "`) VALUES ('" + timeValue + "', '" + uuidValue + "', '" + nameValue + "', '" + serverValue + "', '" + channelValue + "', '" + textValue + "', '" + typeValue + "');");
}
catch(SQLException e) {
e.printStackTrace();
return;
}
}
}

View File

@ -1,74 +1,50 @@
package mineverse.Aust1n46.chat.database;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.bukkit.plugin.Plugin;
import mineverse.Aust1n46.chat.database.Database;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
//This class initializes the plugins connection to the MySQL database if it's enabled.
public class MySQL extends Database {
private final String user;
private final String database;
private final String password;
private final String port;
private final int port;
private final String hostname;
private Connection connection;
public MySQL(Plugin plugin, String hostname, String port, String database, String username, String password) {
super(plugin);
public MySQL(String hostname, int port, String database, String username, String password) {
this.hostname = hostname;
this.port = port;
this.database = database;
this.user = username;
this.password = password;
this.connection = null;
}
@Override
public Connection openConnection() throws SQLException, ClassNotFoundException {
if(checkConnection())
return connection;
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://" + this.hostname + ":" + this.port + "/" + this.database + "?autoReconnect=true", this.user, this.password);
return connection;
public void init() {
HikariConfig config = new HikariConfig();
//config.setDriverClassName(org.postgresql.Driver.class.getName());
//final String jdbcUrl = String.format("jdbc:postgresql://%s:%d/%s", hostname, port, database);
final String jdbcUrl = String.format("jdbc:mysql://%s:%d/%s", hostname, port, database);
config.setJdbcUrl(jdbcUrl);
config.setUsername(user);
config.setPassword(password);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
dataSource = new HikariDataSource(config);
try {
Connection conn = dataSource.getConnection();
conn.setAutoCommit(false);
Statement statement = conn.createStatement();
statement.executeUpdate("CREATE TABLE IF NOT EXISTS VentureChat " +
"(ID SERIAL PRIMARY KEY, ChatTime TEXT, UUID TEXT, Name TEXT, " +
"Server TEXT, Channel TEXT, Text TEXT, Type TEXT)");
} catch (SQLException e) {
throw new RuntimeException(e);
}
@Override
public boolean checkConnection() throws SQLException {
return connection != null && !connection.isClosed();
}
@Override
public Connection getConnection() {
return connection;
}
@Override
public boolean closeConnection() throws SQLException {
if(connection == null)
return false;
connection.close();
return true;
}
@Override
public ResultSet querySQL(String query) throws SQLException, ClassNotFoundException {
if(checkConnection())
openConnection();
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery(query);
return result;
}
@Override
public int updateSQL(String query) throws SQLException, ClassNotFoundException {
if(checkConnection())
openConnection();
Statement statement = connection.createStatement();
int result = statement.executeUpdate(query);
return result;
}
}

View File

@ -2,80 +2,33 @@ package mineverse.Aust1n46.chat.database;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import org.bukkit.plugin.Plugin;
import mineverse.Aust1n46.chat.database.Database;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import mineverse.Aust1n46.chat.MineverseChat;
//This class initializes the connection to a SQLite database, which has no implementations currently in the plugin.
public class SQLite extends Database {
private final String dbLocation;
private Connection connection;
public SQLite(Plugin plugin, String dbLocation) {
super(plugin);
public SQLite(String dbLocation) {
this.dbLocation = dbLocation;
this.connection = null;
}
@Override
public Connection openConnection() throws SQLException, ClassNotFoundException {
if(checkConnection())
return connection;
if(!plugin.getDataFolder().exists())
plugin.getDataFolder().mkdirs();
File file = new File(plugin.getDataFolder(), dbLocation);
if(!(file.exists())) {
public void init() {
File dataFolder = MineverseChat.getInstance().getDataFolder();
if (!dataFolder.exists()) dataFolder.mkdirs();
File databaseFile = new File(dataFolder, dbLocation);
try {
file.createNewFile();
if (!databaseFile.exists()) databaseFile.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
catch(IOException e) {
plugin.getLogger().log(Level.SEVERE, "Unable to create database!");
}
}
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:" + plugin.getDataFolder().toPath().toString() + "/" + dbLocation);
return connection;
}
@Override
public boolean checkConnection() throws SQLException {
return connection != null && !connection.isClosed();
}
@Override
public Connection getConnection() {
return connection;
}
@Override
public boolean closeConnection() throws SQLException {
if(connection == null) {
return false;
}
connection.close();
return true;
}
@Override
public ResultSet querySQL(String query) throws SQLException, ClassNotFoundException {
if(checkConnection())
openConnection();
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery(query);
return result;
}
@Override
public int updateSQL(String query) throws SQLException, ClassNotFoundException {
if(checkConnection())
openConnection();
Statement statement = connection.createStatement();
int result = statement.executeUpdate(query);
return result;
HikariConfig config = new HikariConfig();
final String jdbcUrl = String.format("jdbc:sqlite:%s", databaseFile);
config.setJdbcUrl(jdbcUrl);
dataSource = new HikariDataSource(config);
}
}

View File

@ -2,8 +2,6 @@ package mineverse.Aust1n46.chat.listeners;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Set;
@ -32,7 +30,6 @@ import mineverse.Aust1n46.chat.api.MineverseChatPlayer;
import mineverse.Aust1n46.chat.api.events.ChannelJoinEvent;
import mineverse.Aust1n46.chat.api.events.VentureChatEvent;
import mineverse.Aust1n46.chat.channel.ChatChannel;
import mineverse.Aust1n46.chat.database.DatabaseSender;
import mineverse.Aust1n46.chat.localization.LocalizedMessage;
import mineverse.Aust1n46.chat.utilities.Format;
import mineverse.Aust1n46.chat.versions.VersionHandler;
@ -158,11 +155,11 @@ public class ChatListener implements Listener {
mcp.setReplyPlayer(tp.getUUID());
tp.setReplyPlayer(mcp.getUUID());
Bukkit.getConsoleSender().sendMessage(mcp.getName() + " messages " + tp.getName() + ":" + ChatColor.valueOf(tellColor.toUpperCase()) + filtered);
if(plugin.mysql) {
if(plugin.db != null) {
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = formatter.format(currentDate.getTime());
DatabaseSender.writeToMySQL("ChatTime", "UUID", "Name", "Server", "Channel", "Text", "Type", date, mcp.getUUID().toString(), mcp.getName(), plugin.getServer().getName(), "Messaging_Component", chat.replace("'", "''"), "Chat");
plugin.db.writeVentureChat(date, mcp.getUUID().toString(), mcp.getName(), plugin.getServer().getName(), "Messaging_Component", chat.replace("'", "''"), "Chat");
}
}
return;
@ -194,18 +191,11 @@ public class ChatListener implements Listener {
}
}
Bukkit.getConsoleSender().sendMessage(partyformat);
if(plugin.mysql) {
Statement statement;
if(plugin.db != null) {
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = formatter.format(currentDate.getTime());
try {
statement = plugin.c.createStatement();
statement.executeUpdate("INSERT INTO `VentureChat` (`ChatTime`, `UUID`, `Name`, `Server`, `Channel`, `Text`, `Type`) VALUES ('" + date + "', '" + mcp.getUUID().toString() + "', '" + mcp.getName() + "', '" + plugin.getServer().getName() + "', 'Party_Component', '" + chat.replace("'", "''") + "', 'Chat');");
}
catch(SQLException e) {
e.printStackTrace();
}
plugin.db.writeVentureChat(date, mcp.getUUID().toString(), mcp.getName(), plugin.getServer().getName(), "Party_Component", chat.replace("'", "''"), "Chat");
}
return;
}
@ -481,18 +471,11 @@ public class ChatListener implements Listener {
int hash = event.getHash();
boolean bungee = event.isBungee();
if(plugin.mysql) {
Statement statement;
if(plugin.db != null) {
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = formatter.format(currentDate.getTime());
try {
statement = plugin.c.createStatement();
statement.executeUpdate("INSERT INTO `VentureChat` (`ChatTime`, `UUID`, `Name`, `Server`, `Channel`, `Text`, `Type`) VALUES ('" + date + "', '" + mcp.getUUID().toString() + "', '" + mcp.getName() + "', '" + plugin.getServer().getName() + "', '" + channel.getName() + "', '" + chat.replace("'", "''") + "', 'Chat');");
}
catch(SQLException e) {
e.printStackTrace();
}
plugin.db.writeVentureChat(date, mcp.getUUID().toString(), mcp.getName(), plugin.getServer().getName(), channel.getName(), chat.replace("'", "''"), "Chat");
}
if(!bungee) {

View File

@ -1,8 +1,6 @@
package mineverse.Aust1n46.chat.listeners;
import java.io.FileNotFoundException;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@ -96,18 +94,11 @@ public class CommandListener implements CommandExecutor, Listener {
* event.setCancelled(true); return; } }
*/
if(plugin.mysql) {
Statement statement;
if(plugin.db != null) {
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = formatter.format(currentDate.getTime());
try {
statement = plugin.c.createStatement();
statement.executeUpdate("INSERT INTO `VentureChat` (`ChatTime`, `UUID`, `Name`, `Server`, `Channel`, `Text`, `Type`) VALUES ('" + date + "', '" + mcp.getUUID().toString() + "', '" + mcp.getName() + "', '" + plugin.getServer().getName() + "', 'Command_Component', '" + event.getMessage().replace("'", "''") + "', 'Command');");
}
catch(SQLException error) {
error.printStackTrace();
}
plugin.db.writeVentureChat(date, mcp.getUUID().toString(), mcp.getName(), plugin.getServer().getName(), "Command_Component", event.getMessage().replace("'", "''"), "Command");
}
for(Alias a : aa.getAliases()) {
@ -205,18 +196,11 @@ public class CommandListener implements CommandExecutor, Listener {
//old 1.8 command map
@EventHandler
public void onServerCommand(ServerCommandEvent event) {
if(plugin.mysql) {
Statement statement;
if (plugin.db != null) {
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = formatter.format(currentDate.getTime());
try {
statement = plugin.c.createStatement();
statement.executeUpdate("INSERT INTO `VentureChat` (`ChatTime`, `UUID`, `Name`, `Server`, `Channel`, `Text`, `Type`) VALUES ('" + date + "', 'N/A', 'Console', '" + plugin.getServer().getName() + "', 'Command_Component', '" + event.getCommand().replace("'", "''") + "', 'Command');");
}
catch(SQLException error) {
error.printStackTrace();
}
plugin.db.writeVentureChat(date, "N/A", "Console", plugin.getServer().getName(), "Command_Component", event.getCommand().replace("'", "''") , "Command");
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.