软件等保建设·JAVA安全编码与代码审计
导读:无论是自行开发还是外包开发的软件在等保安全建设管理都有对恶意代码的审查,在上线/交付前要做审查软件中可能存在的后门和隐藏信道,下面是针对JAVA代码的安全编码与代码审计基础知识,希望对大家的软件等保安全建设有一定帮助。
本文重点介绍JAVA安全编码与代码审计基础知识,会以漏洞及安全编码示例的方式介绍JAVA代码中常见Web漏洞的形成及相应的修复方案,同时对一些常见的漏洞函数进行例举,主要以Web渗透中常见的高危漏洞为主。
### XXE
##### 介绍
XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。文档类型定义(DTD)的作用是定义 XML 文档的合法构建模块。DTD 可以在XML 文档内声明,也可以外部引用。
* 内部声明DTD:
>
* 引用外部DTD:
>
当允许引用外部实体时,恶意攻击者即可构造恶意内容访问服务器资源,如读取passwd文件:
``` xml <?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE replace [ <!ENTITY test SYSTEM"file:///ect/passwd">]> <msg>&test;</msg> ``` |
##### 漏洞示例
此处以org.dom4j.io.SAXReader为例,仅展示部分代码片段:
``` String xmldata =request.getParameter("data"); SAXReader sax=newSAXReader();//创建一个SAXReader对象 Document document=sax.read(newByteArrayInputStream(xmldata.getBytes()));//获取document对象,如果文档无节点,则会抛出Exception提前结束 Elementroot=document.getRootElement();//获取根节点 List rowList =root.selectNodes("//msg"); Iterator<?> iter1 =rowList.iterator(); if (iter1.hasNext()) { Element beanNode = (Element)iter1.next(); modelMap.put("success",true); modelMap.put("resp",beanNode.getTextTrim()); } ... ``` |
##### 审计函数
XML解析一般在导入配置、数据传输接口等场景可能会用到,涉及到XML文件处理的场景可留意下XML解析器是否禁用外部实体,从而判断是否存在XXE。部分XML解析接口如下:
``` javax.xml.parsers.DocumentBuilder javax.xml.stream.XMLStreamReader org.jdom.input.SAXBuilder org.jdom2.input.SAXBuilder javax.xml.parsers.SAXParser org.dom4j.io.SAXReader org.xml.sax.XMLReader javax.xml.transform.sax.SAXSource javax.xml.transform.TransformerFactory javax.xml.transform.sax.SAXTransformerFactory javax.xml.validation.SchemaFactory javax.xml.bind.Unmarshaller javax.xml.xpath.XPathExpression ... ``` |
##### 修复方案
使用XML解析器时需要设置其属性,禁止使用外部实体,以上例中SAXReader为例,安全的使用方式如下:
``` sax.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true); sax.setFeature("http://xml.org/sax/features/external-general-entities",false); sax.setFeature("http://xml.org/sax/features/external-parameter-entities",false); ``` |
其它XML解析器的安全使用可参考[OWASP XML External Entity (XXE) Prevention CheatSheet](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#Java)
### 反序列化漏洞
##### 介绍
序列化是让 Java 对象脱离 Java 运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。
Java程序使用ObjectInputStream对象的readObject方法将反序列化数据转换为java对象。但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。
##### 漏洞示例
漏洞代码示例如下:
``` java ...... //读取输入流,并转换对象 InputStreamin=request.getInputStream(); ObjectInputStream ois = newObjectInputStream(in); //恢复对象 ois.readObject(); ois.close(); ``` |
上述代码中,程序读取输入流并将其反序列化为对象。此时可查看项目工程中是否引入可利用的commons-collections3.1、commons-fileupload1.3.1等第三方库,即可构造特定反序列化对象实现任意代码执行。相关三方库及利用工具可参考ysoserial、marshalsec。
##### 审计函数
反序列化操作一般在导入模版文件、网络通信、数据传输、日志格式化存储、对象数据落磁盘或DB存储等业务场景,在代码审计时可重点关注一些反序列化操作函数并判断输入是否可控,如下:
``` ObjectInputStream.readObject ObjectInputStream.readUnshared XMLDecoder.readObject Yaml.load XStream.fromXML ObjectMapper.readValue JSON.parseObject ... ``` |
##### 修复方案
如果可以明确反序列化对象类的则可在反序列化时设置白名单,对于一些只提供接口的库则可使用黑名单设置不允许被反序列化类或者提供设置白名单的接口,可通过Hook函数resolveClass来校验反序列化的类从而实现白名单校验,示例如下:
```java public class AntObjectInputStreamextends ObjectInputStream{ publicAntObjectInputStream(InputStream inputStream) throws IOException { super(inputStream); }
/** * 只允许反序列化SerialObject class */ @Override protected Class<?>resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { if(!desc.getName().equals(SerialObject.class.getName())) { throw newInvalidClassException( "Unauthorizeddeserialization attempt", desc.getName()); } returnsuper.resolveClass(desc); } } ``` |
也可以使用Apache Commons IOSerialization包中的ValidatingObjectInputStream类的accept方法来实现反序列化类白/黑名单控制,如果使用的是第三方库则升级到最新版本。更多修复方案可参考[浅谈Java反序列化漏洞修复方案](https://xianzhi.aliyun.com/forum/topic/41/)。
### SSRF
##### 介绍
SSRF形成的原因大都是由于代码中提供了从其他服务器应用获取数据的功能但没有对目标地址做过滤与限制。比如从指定URL链接获取图片、下载等。
##### 漏洞示例
此处以HttpURLConnection为例,示例代码片段如下:
``` java String url =request.getParameter("picurl"); StringBuffer response = newStringBuffer();
URL pic = new URL(url); HttpURLConnection con =(HttpURLConnection) pic.openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", "Mozilla/5.0"); BufferedReader in = newBufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; while ((inputLine =in.readLine()) != null) { response.append(inputLine); } in.close(); modelMap.put("resp",response.toString()); return "getimg.htm"; ``` |
##### 审计函数
程序中发起HTTP请求操作一般在获取远程图片、页面分享收藏等业务场景,在代码审计时可重点关注一些HTTP请求操作函数,如下:
``` HttpClient.execute HttpClient.executeMethod HttpURLConnection.connect HttpURLConnection.getInputStream URL.openStream ... ``` |
##### 修复方案
* 使用白名单校验HTTP请求url地址
* 避免将请求响应及错误信息返回给用户
* 禁用不需要的协议及限制请求端口,仅仅允许http和https请求等
本文转载自知识星球,版权归作者所有,转载的目的是为了专递更多信息,如有侵权请联系删除,文章内容和观点不代表本站。