反序列化漏洞屡被黑客利用,危害巨大,代码怎样写才安全?
反序列化漏洞出现很久了,一直到现在都很流行,以致OWASP组织将“不安全的反序列化”列为2017年10项最严重的Web 应用程序安全风险榜的第8位。
就在2017年12月22日和24日,国家信息安全漏洞共享平台(CNVD)连续发布了《关于WebLogic Server WLS 组件存在远程命令执行漏洞的安全公告》第一版和第二版。漏洞编号为CNVD-2017-31499,对应CVE-2017-10271。
同时,在12月22日,各大安全网站都有报道称,黑客利用WebLogic 反序列化漏洞(CVE-2017-3248)和WebLogic WLS 组件漏洞(CVE-2017-10271)对企业服务器发起大范围远程攻击,有大量企业的服务器被攻陷。这两个漏洞都是反序列化漏洞,可见其危害之大。
因为网上已有大量的文章对这些漏洞进行了分析,并提供了修复方案,因此,我不再重复。
我这里关注的是,作为程序员,对反序列化代码要怎样写才安全?
序列化就是把对象转换成一种数据格式,如Json、XML等文本格式或二进制字节流格式,便于保存在内存、文件、数据库中或者在网络通信中进行传输。反序列化是序列化的逆过程,即由保存的文本格式或字节流格式还原成对象。
很多编程语言都提供了这一功能,但不幸的是,如果应用代码允许接受不可信的序列化数据,在进行反序列化操作时,可能会产生反序列化漏洞,黑客可以利用它进行拒绝服务攻击、访问控制攻击和远程命令执行攻击。
Java语言中实现安全地反序列化对象
Java中,ObjectOutputStream类的writeObject()方法实现序列化;ObjectInputStream类的readObject()方法用于反序列化。
(1)重载ObjectInputStream的resolveClass() 方法,只对允许的类进行反序列化操作。
代码示例如下:
public class LookAheadObjectInputStream extends ObjectInputStream /*** 只反序列化Bicycle类*/@Overrideprotected Class resolveClass(ObjectStreamClass desc) throws IOException,ClassNotFoundException return super.resolveClass(desc);}}
可以使用第三方提供的库,它们支持对className进行白名单、黑名单校验,如SerialKiller。
将你应用程序中类似下面的代码:
ObjectInputStream ois = new ObjectInputStream(is);String msg = (String) ois.readObject();
替换成类似下面的代码,即用SerialKiller类替换ObjectInputStream类:
ObjectInputStream ois = new SerialKiller(is, "/etc/serialkiller.conf");String msg = (String) ois.readObject();
serialkiller.conf文件中保存相关的配置信息,如黑名单、白名单等,示例如下:
6000
false true/tmp/serialkiller.log bsh.XThis$bsh.Interpreter$ com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase$ org.mozilla.javascript..*$[...]
org.apache.commons.collections.functors.InstantiateTransformerorg.apache.commons.collections.functors.ConstantTransformerorg.apache.commons.collections.functors.ChainedTransformerorg.apache.commons.collections.functors.InvokerTransformer[...].*
(2)防止反序列化域对象。
有些应用程序对象可能强制要求实现Serializable,为了保证这些应用程序对象不能被反序列化,可以将readObject()声明为final并且总是抛出异常。
private final void readObject(ObjectInputStream in) throws java.io.IOException
(3)使用Agent代理加固所有java.io.ObjectInputStream的操作
前面提到的方法是通过子类化java.io.ObjectInputStream实现安全的反序列化操作,但是,如果你不拥有相关的代码或者等不及相关的补丁,那么这时使用一个Agent代理是最好的方式。但是,要从全局的角度对ObjectInputStream进行安全加固,只能使用黑名单校验,因为不太可能确定应用程序允许反序列化的所有类的清单来作为白名单,并且,这个黑名单要经常更新。
要启用Agent代理,添加以下JVM参数即可:
-javaagent:name-of-agent.jar
同样,也有一些第三方的库实现这个功能,如contrast-rO0等。
语言无关的安全反序列化方法
(1)使用纯数据格式
避免使用反序列化是减少风险的最好方式。使用纯数据格式如Json、XML,使数据对象和业务对象分离,这样减少了出现反序列化漏洞的机会。当然,在处理纯数据时,也有可能会出现漏洞。
(2)对反序列化数据进行签名
不要反序列化不可信的数据。在序列化时,对相关的数据进行签名,对没有通过验证的数据不进行反序列化。
- .NET Core 实战笔记3 ASP.NET Core
- HTML页面中的lang属性
- JSP Cheat Sheet - JavaWeb基础学习速查表
- 把网站改成APP吧-Xamarin WebView
- 数据库E-R模型关系图
- 修改Visual Studio类模板添加版权注释信息
- Oracle 11g 安装教程
- ASP.NET MVC学习笔记07数据表和模型添加新字段
- 以太坊·电影院场景区块链应用探索
- 最全爬虫攻略:微博、APP、公众号一个不能少!
- 注册中心 Eureka 源码解析 —— Eureka-Client 初始化(一)之 EurekaInstanceConfig
- 无论人工智能发展到什么地步,都离不开这6段代码
- Dubbo源码解析 —— 逻辑层设计之服务降级
- 【死磕Java并发】-----J.U.C之Condition
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法