java安全编码指南之:堆污染Heap pollution
简介
什么是堆污染呢?堆污染是指当参数化类型变量引用的对象不是该参数化类型的对象时而发生的。
我们知道在JDK5中,引入了泛型的概念,我们可以在创建集合类的时候,指定该集合类中应该存储的对象类型。
如果在指定类型的集合中,引用了不同的类型,那么这种情况就叫做堆污染。
产生堆污染的例子
有同学可能会问了,既然JDK5引入了泛型,为什么还会出现堆污染呢?
这是一个好问题,让我们看一个例子:
public void heapPollution1(){
List normalList= Arrays.asList("www.flydean.com",100);
List<Integer> integerList= normalList;
}
上面的例子中,我们使用Arrays.asList创建了一个普通的List。
这个List中包含了int和String两种类型,当我们将List赋值给List的时候,java编译器并不会去判断赋值List中的类型,integerList中包含了非Integer的元素,最终导致在使用的时候会出现错误。
直接给List赋值不会进行类型检查,那么如果我们是直接向List中添加元素呢?
我们看下下面的例子:
private void addToList(List list, Object object){
list.add(object);
}
@Test
public void heapPollution2(){
List<Integer> integerList=new ArrayList<>();
addToList(integerList,"www.flydean.com");
}
上面的例子中,我们定义了一个addToList方法,这个方法的参数是一个普通的List,但是我们传入了一个List。
结果,我们发现list.add方法并没有进行参数类型校验。
上面的例子该怎么修改呢?
我们需要在addToList方法的List参数中,也添加上类型校验:
private void addToList(List<Integer> list, Object object){
list.add(object);
}
如果addToList是一个非常通用的方法怎么办呢?在addToList的参数中添加参数类型是现实的。
这个时候,我们可以考虑使用Collections.checkedList方法来将输入的List转换成为一个checkedList,从而只接收特定类型的元素。
public void heapPollutionRight(){
List<Integer> integerList=new ArrayList<>();
List<Integer> checkedIntegerList= Collections.checkedList(integerList, Integer.class);
addToList(checkedIntegerList,"www.flydean.com");
}
运行上面的代码,我们将会得到下面的异常:
java.lang.ClassCastException: Attempt to insert class java.lang.String element into collection with element type class java.lang.Integer
更通用的例子
上面我们定义了一个addToList方法,因为没有做类型判断,所以可能会出现堆污染的问题。
有没有什么办法既可以通用,又可以避免堆污染呢?
当然有的,我们看下面的实现:
private <T> void addToList2(List<T> list, T t) {
list.add(t);
}
public <T> void heapPollutionRight2(T element){
List<T> list = new ArrayList<>();
addToList2(list,element);
}
上面的例子中,我们在addToList方法中定义了一个参数类型T,通过这样,我们保证了List中的元素类型的一致性。
可变参数
事实上,方法参数可以是可变的,我们考虑下面的例子:
private void addToList3(List<Integer>... listArray){
Object[] objectArray = listArray;
objectArray[0]= Arrays.asList("www.flydean.com");
for(List<Integer> integerList: listArray){
for(Integer element: integerList){
System.out.println(element);
}
}
}
上面的例子中我们的参数是一个List的数组,虽然List中的元素类型固定了,但是我们可以重新赋值给参数数组,从而实际上修改掉参数类型。
如果上面addToList3的方法参数修改为下面的方式,就不会出现问题了:
private void addToList4(List<List<Integer>> listArray){
这种情况下,List的类型是固定的,我们无法通过重新赋值的方式来修改它。
本文的例子:
learn-java-base-9-to-20/tree/master/security
本文已收录于 http://www.flydean.com/java-security-code-line-heap-pollution/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
java安全编码指南之:堆污染Heap pollution的更多相关文章
- java安全编码指南之:基础篇
目录 简介 java平台本身的安全性 安全第一,不要写聪明的代码 在代码设计之初就考虑安全性 避免重复的代码 限制权限 构建可信边界 封装 写文档 简介 作为一个程序员,只是写出好用的代码是不够的,我 ...
- java安全编码指南之:Mutability可变性
目录 简介 可变对象和不可变对象 创建mutable对象的拷贝 为mutable类创建copy方法 不要相信equals 不要直接暴露可修改的属性 public static fields应该被置位f ...
- java安全编码指南之:字符串和编码
目录 简介 使用变长编码的不完全字符来创建字符串 char不能表示所有的Unicode 注意Locale的使用 文件读写中的编码格式 不要将非字符数据编码为字符串 简介 字符串是我们日常编码过程中使用 ...
- java安全编码指南之:输入校验
目录 简介 在字符串标准化之后进行校验 注意不可信字符串的格式化 小心使用Runtime.exec() 正则表达式的匹配 简介 为了保证java程序的安全,任何外部用户的输入我们都认为是可能有恶意攻击 ...
- java安全编码指南之:声明和初始化
目录 简介 初始化顺序 循环初始化 不要使用java标准库中的类名作为自己的类名 不要在增强的for语句中修改变量值 简介 在java对象和字段的初始化过程中会遇到哪些安全性问题呢?一起来看看吧. 初 ...
- java安全编码指南之:Number操作
目录 简介 Number的范围 区分位运算和算数运算 注意不要使用0作为除数 兼容C++的无符号整数类型 NAN和INFINITY 不要使用float或者double作为循环的计数器 BigDecim ...
- java安全编码指南之:可见性和原子性
目录 简介 不可变对象的可见性 保证共享变量的复合操作的原子性 保证多个Atomic原子类操作的原子性 保证方法调用链的原子性 读写64bits的值 简介 java类中会定义很多变量,有类变量也有实例 ...
- java安全编码指南之:异常处理
目录 简介 异常简介 不要忽略checked exceptions 不要在异常中暴露敏感信息 在处理捕获的异常时,需要恢复对象的初始状态 不要手动完成finally block 不要捕获NullPoi ...
- java安全编码指南之:死锁dead lock
目录 简介 不同的加锁顺序 使用private类变量 使用相同的Order 释放掉已占有的锁 简介 java中为了保证共享数据的安全性,我们引入了锁的机制.有了锁就有可能产生死锁. 死锁的原因就是多个 ...
随机推荐
- requests模块使用
一.python环境下安装requests Windows下使用win+r打开cmd命令提示符,输入pip install requests,回车. 二.requests模块导入 import req ...
- Linux文件权限-笔记
文件权限共10个字符,第一个字符表示该文件是[文件夹]或[文件]——如果是字符“d"则表示该文件是文件夹:如果是字符“-”则表示是文件. 后九个字符,三个一组,共三组,分别表示[所有者权限] ...
- go module 获取码云私有仓库代码
因为码云免费组织有5人限制,其他人想获得代码 只能通过别的方式 go mod 底层使用的git 获取代码, 所以首先解决如何通过git clone代码 思路为通过ssh密钥的方式获取 首先在码云仓库部 ...
- JavaScript学习系列博客_7_JavaScript中的逻辑运算符、三元运算符
逻辑运算符 ! 非 - 非运算可以对一个布尔值进行取反,true变false false边true - 当对非布尔值使用!时,会先将其转换为布尔值然后再取反 - 我们可以利用 !! 来将其他的数据类型 ...
- web渗透测试之sqlmap拿到数据库信息
通过扫描我们发现目标网站存在sql注入漏洞,我们访问该里面后发现该网站里面有个表格提交参数.确实存在没有过滤 使用sqlmap扫描发现漏洞的确存在,这里是布尔盲注 查看当前数据库名 查看表名得到以下信 ...
- Discovering Reinforcement Learning Algorithms
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! arXiv:2007.08794v1 [cs.LG] 17 Jul 2020 Abstract 强化学习(RL)算法根据经过多年研究手动发 ...
- HTTP基础 --响应
响应,由服务端返回给客户端,分为三部分:响应状态码(Response Status Code),响应头(Response Headers)和响应体(Response Body). 响应状态码 响应服务 ...
- 面经手册 · 第7篇《ArrayList也这么多知识?一个指定位置插入就把谢飞机面晕了!》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 数据结构是写好代码的基础! 说到数据结构基本包括:数组.链表.队列.红黑树等,但当你 ...
- Serializers组件详解
Serializers组件 使用背景 因为每个语言都有自己的数据类型,不同语言要想数据传输,就必须指定一种各种语言通用的数据类型,如json,xml等等 序列化器允许把像查询集和模型实例这样的复杂数据 ...
- oeasy教您玩转linux010102查看发行版
查看发行版distro 回忆上次内容 从帮助咱们可以知道 name -a 可以得到全部信息 uname -a 从中,咱们知道有ubuntu,他好像是一种发行版. 那么,什么是发行版呢? 什么是发行版?