多平台统一管理软件接口,如何实现多平台统一管理软件接口
390
2022-10-03
JAVA代码审计与安全编码(源代码安全审计)
Java代码审计系列课程
概述
本文重点介绍JAVA安全编码与代码审计基础知识,会以漏&洞及安全编码示例的方式介绍JAVA代码中常见Web漏&洞的形成及相应的修复方案,同时对一些常见的漏&洞函数进行例举。
XXE
介绍
引用外部DTD:
当允许引用外部实体时,恶意攻&击者即可构造恶意内容访问服务器资源,如读取passwd文件:
]>
漏&洞示例
此处以org.dom4j.io.SAXReader为例,仅展示部分代码片段:
String xmldata = request.getParameter("data");SAXReader sax=new SAXReader();//创建一个SAXReader对象Document document=sax.read(new ByteArrayInputStream(xmldata.getBytes()));//获取document对象,如果文档无节点,则会抛出Exception提前结束Element root=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.DocumentBuilderjavax.xml.stream.XMLStreamReaderorg.jdom.input.SAXBuilderorg.jdom2.input.SAXBuilderjavax.xml.parsers.SAXParserorg.dom4j.io.SAXReader org.xml.sax.XMLReaderjavax.xml.transform.sax.SAXSource javax.xml.transform.TransformerFactory javax.xml.transform.sax.SAXTransformerFactory javax.xml.validation.SchemaFactoryjavax.xml.bind.Unmarshallerjavax.xml.xpath.XPathExpression...
修复方案
使用XML解析器时需要设置其属性,禁止使用外部实体,以上例中SAXReader为例,安全的使用方式如下:
sax.setFeature("true);sax.setFeature("false);sax.setFeature("false);
其它XML解析器的安全使用可参考[OWASP XML External Entity (XXE) Prevention Cheat Sheet](Java 对象脱离 Java 运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。
Java程序使用ObjectInputStream对象的readObject方法将反序列化数据转换为java对象。但当输入的反序列化的数据可被用户控制,那么攻&击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。
漏&洞示例
漏&洞代码示例如下:
......//读取输入流,并转换对象InputStream in=request.getInputStream();ObjectInputStream ois = new ObjectInputStream(in);//恢复对象ois.readObject();ois.close();
上述代码中,程序读取输入流并将其反序列化为对象。此时可查看项目工程中是否引入可利用的commons-collections 3.1、commons-fileupload 1.3.1等第三方库,即可构造特定反序列化对象实现任意代码执行。相关三方库及利用工具可参考ysoserial、marshalsec。
审计函数
反序列化操作一般在导入模版文件、网络通信、数据传输、日志格式化存储、对象数据落磁盘或DB存储等业务场景,在代码审计时可重点关注一些反序列化操作函数并判断输入是否可控,如下:
ObjectInputStream.readObjectObjectInputStream.readUnsharedXMLDecoder.readObjectYaml.loadXStream.fromXMLObjectMapper.readValueJSON.parseObject...
修复方案
如果可以明确反序列化对象类的则可在反序列化时设置白名单,对于一些只提供接口的库则可使用黑名单设置不允许被反序列化类或者提供设置白名单的接口,可通过Hook函数resolveClass来校验反序列化的类从而实现白名单校验,示例如下:
public class AntObjectInputStream extends ObjectInputStream{ public AntObjectInputStream(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 new InvalidClassException( "Unauthorized deserialization attempt", desc.getName()); } return super.resolveClass(desc); }}
也可以使用Apache Commons IO Serialization包中的ValidatingObjectInputStream类的accept方法来实现反序列化类白/黑名单控制,如果使用的是第三方库则升级到最新版本。更多修复方案可参考浅谈Java反序列化漏&洞修复方案。
服务端请求为伪造
介绍
服务端请求为伪造,形成的原因大都是由于代码中提供了从其他服务器应用获取数据的功能但没有对目标地址做过滤与限制。比如从指定URL链接获取图片、下载等。
漏&洞示例
此处以HttpURLConnection为例,示例代码片段如下:
String url = request.getParameter("picurl"); StringBuffer response = new StringBuffer(); URL pic = new URL(url); HttpURLConnection con = (HttpURLConnection) pic.openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", "Mozilla/5.0"); BufferedReader in = new BufferedReader(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.executeHttpClient.executeMethodHttpURLConnection.connectHttpURLConnection.getInputStreamURL.openStream...
修复方案
使用白名单校验HTTP请求url地址避免将请求响应及错误信息返回给用户禁用不需要的协议及限制请求端口,仅仅允许* from books where id= ${id}
对于Mybatis框架下SQL注入漏&洞的审计可参考Mybatis框架下SQL注入漏&洞面面观
修复方案
Mybatis框架SQL语句安全写法应使用\#\{\},避免使用动态拼接形式\$\{\},ibatis则使用\#变量\#。安全写法如下:
select * from books where id= #{id}
文件上传漏&洞
介绍
文件上传过程中,通常因为未校验上传文件后缀类型,导致用户可上传jsp等一些webshell文件。代码审计时可重点关注对上传文件类型是否有足够安全的校验,以及是否限制文件大小等。
漏&洞示例
此处以MultipartFile为例,示例代码片段如下:
public String handleFileUpload(MultipartFile file){ String fileName = file.getOriginalFilename(); if (fileName==null) { return "file is error"; } String filePath = "/static/images/uploads/"+fileName; if (!file.isEmpty()) { try { byte[] bytes = file.getBytes(); BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(filePath))); stream.write(bytes); stream.close(); return "OK"; } catch (Exception e) { return e.getMessage(); } } else { return "You failed to upload " + file.getOriginalFilename() + " because the file was empty."; } }
审计函数
java程序中涉及到文件上传的函数,比如:
MultipartFile...
修复方案
使用白名单校验上传文件类型、大小限制
Autobinding
介绍
Autobinding-自动绑定漏&洞,根据不同语言/框架,该漏&洞有几个不同的叫法,如下:
Mass Assignment: Ruby on Rails, NodeJSAutobinding: Spring MVC, ASP.NET MVCObject injection: PHP(对象注入、反序列化漏&洞)
软件框架有时允许开发人员自动将HTTP请求参数绑定到程序代码变量或对象中,从而使开发人员更容易地使用该框架。这里攻&击者就可以利用这种方法通过构造up,Forgot password这4个页面组成。我们关注的点是密&码找回功能,即怎么样绕过安全问题验证并找回密&码。
1)首先看reset方法,把不影响代码逻辑的删掉。这样更简洁易懂:
@Controller@SessionAttributes("user")public class ResetPasswordController {private UserService userService;...@RequestMapping(value = "/reset", method = RequestMethod.POST)public String resetHandler(@RequestParam String username, Model model) { User user = userService.findByName(username); if (user == null) { return "reset"; } model.addAttribute("user", user); return "redirect: resetQuestion"; }
这里从参数获取username并检查有没有这个用户,如果有则把这个user对象放到Model中。因为这个Controller使用了@SessionAttributes("user"),所以同时也会自动把user对象放到session中。然后跳转到resetQuestion密&码找回安全问题校验页面。
2)resetQuestion密&码找回安全问题校验页面有resetViewQuestionHandler这个方法展现
@RequestMapping(value = "/resetQuestion", method = RequestMethod.GET) public String resetViewQuestionHandler(@ModelAttribute User user) { logger.info("Welcome resetQuestion ! " + user); return "resetQuestion"; }
这里使用了@ModelAttribute User user,实际上这里是从session中获取user对象。但存在问题是如果在请求中添加user对象的成员变量时则会更改user对象对应成员的值。
所以当我们给resetQuestionHandler发送GET请求的时候可以添加“answer=hehe”参数,这样就可以给session中的对象赋值,将原本密&码找回的安全问题答案修改成“hehe”。这样在最后一步校验安全问题时即可验证成功并找回密&码
审计函数
这种漏&洞一般在比较多步骤的流程中出现,比如转账、找密等场景,也可重点留意几个注解如下:
@SessionAttributes@ModelAttribute...
更多信息可参考Spring MVC Autobinding漏&洞实例初窥
修复方案
Spring MVC中可以使用@InitBinder注解,通过WebDataBinder的方法setAllowedFields、setDisallowedFields设置允许或不允许绑定的参数。
URL重定向
介绍
由于Web站点有时需要根据不同的逻辑将用户引向到不同的页面,如典型的登录接口就经常需要在认证成功之后将用户引导到登录之前的页面,整个过程中如果实现不好就可能导致URL重定向问题,攻&击者构造恶意跳转的链接,可以向用户发起钓鱼攻&击。
漏&洞示例
此处以Servlet的redirect 方式为例,示例代码片段如下:
String site = request.getParameter("url"); if(!site.isEmpty()){ response.sendRedirect(site); }
审计函数
java程序中URL重定向的方法均可留意是否对跳转地址进行校验、重定向函数如下:
sendRedirectsetHeaderforward...
修复方案
使用白名单校验重定向的url地址给用户展示安全风险提示,并由用户再次确认是否跳转
CSRF
介绍
跨站请求伪造(Cross-Site Request Forgery,CSRF)是一种使已登录用户在不知情的情况下执行某种动作的攻&击。因为攻&击者看不到伪造请求的响应结果,所以CSRF攻&击主要用来执行动作,而非窃取用户数据。当受害者是一个普通用户时,CSRF可以实现在其不知情的情况下转移用户资金、发送邮件等操作;但是如果受害者是一个具有管理员权限的用户时CSRF则可能威胁到整个Web系统的安全。
漏&洞示例
GET cmd = request.getParameter("cmd"); Runtime.getRuntime().exec(cmd);
审计函数
这种漏&洞原理上很简单,重点是找到执行系统命令的函数,看命令是否可控。在一些特殊的业务场景是能判断出是否存在此类功能,这里举个典型的实例场景,有的程序功能需求提供网页截图功能,笔者见过多数是使用phantomjs实现,那势必是需要调用系统命令执行phantomjs并传参实现截图。而参数大多数情况下应该是当前url或其中获取相关参数,此时很有可能存在命令执行漏&洞,还有一些其它比较特别的场景可自行脑洞。
java程序中执行系统命令的函数如下:
Runtime.execProcessBuilder.startGroovyShell.evaluate...
修复方案
避免命令用户可控如需用户输入参数,则对用户输入做严格校验,如&&、|、;等
权限控制
介绍
越权漏&洞可以分为水平、垂直越权两种,程序在处理用户请求时未对用户的权限进行校验,使的用户可访问、操作其他相同角色用户的数据,这种情况是水平越权;如果低权限用户可访问、操作高权限用户则的数据,这种情况为垂直越权。
漏&洞示例
@RequestMapping(value="/getUserInfo",method = RequestMethod.GET) public String getUserInfo(Model model, HttpServletRequest request) throws IOException { String userid = request.getParameter("userid"); if(!userid.isEmpty()){ String info=userModel.getuserInfoByid(userid); return info; } return ""; }
审计函数
水平、垂直越权不需关注特定函数,只要在处理用户操作请求时查看是否有对当前登陆用户权限做校验从而确定是否存在漏&洞
修复方案
获取当前登陆用户并校验该用户是否具有当前操作权限,并校验请求操作数据是否属于当前登陆用户,当前登陆用户标识不能从用户可控的请求参数中获取。
批量请求
介绍
业务中经常会有使用到发送短信校验码、短信通知、邮件通知等一些功能,这类请求如果不做任何限制,恶意攻&击者可能进行批量恶意请求轰炸,大量短信、邮件等通知对正常用户造成困扰,同时也是对公司的资源造成损耗。
除了短信、邮件轰炸等,还有一种情况也需要注意,程序中可能存在很多接口,用来查询账号是否存在、账号名与手机或邮箱、姓名等的匹配关系,这类请求如不做限制也会被恶意用户批量利用,从而获取用户数据关系相关数据。对这类请求在代码审计时可关注是否有对请求做鉴权、和限制即可大致判断是否存在风险。
漏&洞示例
@RequestMapping(value="/ifUserExit",method = RequestMethod.GET) public String ifUserExit(Model model, HttpServletRequest request) throws IOException { String phone = request.getParameter("phone"); if(! phone.isEmpty()){ boolean ifex=userModel.ifuserExitByPhone(phone); if (!ifex) return "用户不存在"; } return "用户已被注册"; }
修复方案
对同一个用户发起这类请求的频率、每小时及每天发送量在服务端做限制,不可在前端实现限制
第三方组件安全
介绍
这个比较好理解,诸如Struts2、不安全的编辑控件、XML解析器以及可被其它漏&洞利用的如commons-collections:3.1等第三方组件,这个可以在程序pom文件中查看是否有引入依赖。即便在代码中没有应用到或很难直接利用,也不应该使用不安全的版本,一个产品的周期很长,很难保证后面不会引入可被利用的漏&洞点。
修复方案
使用最新或安全版本的第三方组件
待续...
总结
除了上述相关的漏&洞,在代码审计的时候有时会遇到一些特别的漏&洞,比如开发为了测试方便关闭掉了一些安全校验函数、甚至未彻底清除的一些预留后门及测试管理接口等。除此,框架本身的安全问题也是可以深挖。一些安全校验、安全解决方案也未必就毫无破绽的,即便存在一些安全解决,但开发人员有没有使用以及是否正确使用安全方案都是可能存在问题的点。大公司都有成熟的框架,一些基本的安全问题并不是太多,但设计层面上的安全及流程相关的问题却基本依赖开发的经验。流程相关的漏&洞则有必要先熟悉应用本身的设计和逻辑,这块也是潜在的风险点。
不要指望给开发说一句“一切输入都是不可信的”,他就能编写出安全的代码。总之,Talk is cheap. Show me the code~
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~