漏洞信息
CWE编号:CWE-476
空指针解引用,NULL Pointer Dereference
概念解析
刚开始我看到这个缺陷也是一脸懵,实际查资料之后才发现:哦!原来就是这玩意儿啊!
在搞清楚啥叫空指针解引用之前,我们应该明确组成这个词的2个基本概念所代表的含义:
1、空指针(Null Pointer)
Java不能直接操作指针,其数据类型可以分为基本类型(byte、short、int、long、float、double、char、boolean)和引用类型,基础类型直接存储实际的值,引用类型存储的是对象的引用,而不是对象本身,相当于C/C++中的指针。
在Java中,我们可以将空指针简单理解引用的对象不存在,返回地址为null
2、解引用
这是理解这个缺陷的最大障碍,很多人因为分不清楚引用(Reference) 和 解引用(Dereference) 的区别,导致对此缺陷不理解。
我们通过一个例子简单说明二者的区别
1 2 3 4 5
| String str = "Hello, World!";
System.out.println(str.length());
|
引用本身不会直接访问对象内容,只是一个“指向”的概念;(上述例子中声明了一个str变量)
通过引用去访问对象的内容(属性、方法等)的过程称为解引用。(上述例子中调用了length()方法)
明确了上述两个概念之后,我们就很容易理解什么叫空指针解引用了。
在访问对象内容(解引用)的时候,如果无法确保引用是有效的(非 null
),程序就会抛出空指针异常NullPointerException。
修复方案&案例
修复方案非常简单:在使用引用类型的数据前进行判空操作
eg1: 空指针解引用
1 2 3 4 5 6 7 8 9 10
| String str = null;
System.out.println(str.length());
if (str != null) { System.out.println(str.length()); } else { System.out.println("String is null, cannot get length."); }
|
eg2: 解引用未初始化的对象
不合规代码示例:
1 2 3 4 5 6 7 8 9 10
| public class UninitializedObjectExample { static class Person { String name; }
public static void main(String[] args) { Person person = null; System.out.println(person.name); } }
|
修复方案:确保在使用前正确初始化对象
1 2 3 4 5 6 7 8 9 10
| public class UninitializedObjectExample { static class Person { String name = "Default Name"; }
public static void main(String[] args) { Person person = new Person(); System.out.println(person.name); } }
|
eg3: 解引用已释放的资源
不合规代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException;
public class ClosedResourceExample { public static void main(String[] args) { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("example.txt")); reader.close(); System.out.println(reader.readLine()); } catch (IOException e) { e.printStackTrace(); } } }
|
合规代码:通过try-with-resources
确保资源在使用后自动关闭,避免手动操作的错误。
PS:try-with-resources
是Java7中引入的资源管理机制,用于在代码执行完毕后自动关闭实现了 AutoCloseable
接口的资源(如文件、数据库连接、网络流等)。资源声明在 try
的括号中,当 try
块执行完毕(无论是否抛出异常),资源会被自动关闭(调用 close()
方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException;
public class ClosedResourceExample { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) { System.out.println(reader.readLine()); } catch (IOException e) { e.printStackTrace(); } } }
|
审计思路
推荐工具审计。
人工审计的方式就比较笨,得花时间一个个看,难度很低,但没有必要。
参考链接
- Java 空指针在检查后解引用_mob64ca12d78ba3的技术博客_51CTO博客
- 深入理解 Java try-with-resource 语法糖深入理解 Java try-with-resource 语 - 掘金