0%

什么是JNDI

什么是JNDI

J2SE,是java2的标准版,主要用于开发桌面的应用程序。

J2SE包含了构成java语言核心的类:数据库连接、接口定义、输入输出、网络编辑等。

J2EE, 是java2的企业版,主要用于分布式的网络程序的开发。

j2ee包含j2se中的类,还包含用于开发企业级应用的类,也包含企业应用中很多的API。例如:JDBC、JNDI、EJB等

不少专家认为,没有透彻理解JNDI的意义和作用,就没有真正掌握J2EE特别是EJB的知识

JNDI概念

JNDI全称Java Naming and Directory Interface 翻译过来就是Java命名和目录接口。这个概念搞出来就是为了方便人们来记录一些不容易记录都内容。有点类似于域名和ip的映射。所以如果要深入的学可能会被绕进去,现在你可以简单的理解为他是一个字典,给不同的对象和属性(value)取名(key)。到时候好找出来用。

JNDI作用

网上比较经典的例子就是JDBC连接数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class Scr {
public static void main(String[] args) {
//JDBC驱动名
String JDBC_DRIVER = "com.mysql.jdbc.Driver";
//数据库URL:这里的tt是数据库名称
String JDBC_URL = "jdbc:mysql://localhost:3306/tt?useSSL=false&serverTimezone=UTC";
// 数据库的用户名与密码
String USER = "root";
String PASS = "admin123";
//通过DriverManager类获得该连接对象才能访问数据库
Connection connection = null;
// 通过Connection获得该结果对象用于执行静态的SQL语句
Statement statement = null;
try {
// 注册JDBC驱动
Class.forName(JDBC_DRIVER);

// 数据库的连接:通过DriverManager类的getConnection方法,传入三个参数:数据库URL、用户名、用户密码,实例化connection对象
connection = DriverManager.getConnection(JDBC_URL,USER,PASS);
// 实例化statement对象
statement = (Statement) connection.createStatement();
// 定义数据库查询语句:查询aa表中的name、sex两列数据
String sql = "SELECT name,sex FROM aa";
// 执行查询语句
ResultSet rSet = statement.executeQuery(sql);
// 展开查询到的数据
while(rSet.next()) {
// 这里getString()方法中的参数对应的是数据库表中的列名
String get_name = rSet.getString("name");
String get_sex = rSet.getString("sex");
// 输出数据
System.out.println("名字:"+get_name);
System.out.print("性别:"+get_sex);
}
// 依次关闭对象
rSet.close();
statement.close();
connection.close();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

可以看到这是我们初学java时的代码,因为那时候我们都是一个人开发整个系统,如果有一天一家公司有成百上千的人开发同一套系统呢?是不是不应该所有的程序员都知道这个账号密码、url格式、后端的实现逻辑、数据库类型等等?这就是Java编程中重要的思想:解藕

解藕当然呢不只JNDI这一种方式。很多时候封装的越来越细小也算是解耦。但是JNDI提供了这种更方便的解藕概念。

比如上面这个链接数据库的代码我可以用JNDI这样做:

定义一个xml模版,mysql.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>  
<datasources>
<local-tx-datasource>
<jndi-name>mysqlconfigsouce</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>passwd</password>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>

然后我们在程序中引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Connection conn=null;  
try {
Context ctx=new InitialContext(); //获取上下文
Object datasourceRef=ctx.lookup("java:mysqlconfigsouce"); //引用数据源
DataSource ds=(Datasource)datasourceRef;
conn=ds.getConnection();
......
c.close();
} catch(Exception e) {
e.printStackTrace();
} finally {
if(conn!=null) {
try {
conn.close();
} catch(SQLException e) { }
}
}

当然JNDI只是一个概念,具体实现还有rmi和ldap等协议参与其中。上面只是举个例子。

这里补充一点:正如我们第一节所说的,JNDI是一个类似域名和ip的对应机制,那javax.naming 的包中就提供了Context接口,最重要的

就是两个方法:

1、 void bind( String name , Object object )
绑定
2、Object lookup( String name )
获取

JNDI在JAVA应用程序中的位置:

![image-20230130163311234](/Users/geez/Library/Application Support/typora-user-images/image-20230130163311234.png)

可以看到JNDI在应用程序和底层服务LADP、DNS、RMI等等之间,可以理解为JNDI封装了一套管理命名和目录的接口,通过JNDI我们可以使用rmi、LDAP等各种协议的命名和目录服务。当然如果JNDI的检索参数被控制,就会引发重大安全问题,这就是后面要写的JNDI注入的问题。

———–太忙了先不写了———

要分析的漏洞:fastjson、log4j、shiro、weblogic那些


采用署名-非商业性使用-相同方式共享 4.0(CC BY-NC-SA 4.0)许可协议
「分享也是一种学习」