简介

DOS不是那个windows的前身,而是Denial of Service,有做过系统安全方面的小伙伴可能对这个再相熟不过了,简略点讲,DOS就是服务型响应不过去,从而回绝了失常的服务申请。

明天本文不是要讲怎么发动一个DOS攻打,而是讲一下怎么在java的代码层面尽量减少DOS的可能性。

为什么会有DOS

为什么会有DOS呢?排除歹意攻打的状况下,DOS的起因就是资源的使用不当。个别意义上咱们所说的资源有CPU周期,内存,磁盘空间,和文件描述符等。

如果这些资源受到了歹意应用,那么很有可能会影响失常的零碎服务响应,从而产生DOS。

怎么在编码层面上,解决DOS问题呢?

不合理的资源应用

如果零碎有不合理的资源应用的话,就会造成资源紧缺,从而会产生问题。咱们这里举一些不合理应用资源的例子。

申请用于矢量图的SVG文件和字体文件

SVG (全称是 Scalable Vector Graphics) 是一个跟分辨率无关的图形格局。因为SVG是基于XML的,并且保留着大量的简单门路信息,所以它的体积个别比拟大。咱们在应用的时候要思考。

同时如果应用大量的字体文件也会减轻零碎的资源累赘。

字符串或二进制示意的图片转换

图片是一个文件,文件就能够应用二进制来示意,同样的如果咱们把二进制进行base64编码就失去了图片的字符串示意。

如果应用过webpack进行前端我的项目构建的同学应该晓得,对于我的项目中的小图像,个别是将其编码成为字符串间接嵌套在html中的。然而对于大图片,还是保留的原来的格局。

如果咱们在后盾对字符串或者二进制示意的图片进行转换的时候,可能会须要几倍于原image大小的内存。

看一个imageToBase64的例子:

   public String imageToBase64() {        File f = new File("/tmp/abc.jpg");        try {            BufferedImage bi = ImageIO.read(f);            ByteArrayOutputStream baos = new ByteArrayOutputStream();            ImageIO.write(bi, "jpg", baos);            byte[] bytes = baos.toByteArray();            return encoder.encodeBuffer(bytes).trim();        } catch (IOException e) {            e.printStackTrace();        }        return null;    }

zip炸弹

为了晋升数据传输的效率,很多时候咱们都会应用压缩算法,比方在HTTP中。然而一个压缩过的很小的zip文件,解压之后可能会变得十分十分大。

这里给大家介绍一个十分有名的zip炸弹。

42.zip 是很有名的zip炸弹。它的大小只有42KB,然而解压之后竟然有4.5PB之多。

怎么做的呢?

一个zip文件中又蕴含了16个zip文件,每一个zip文件又蕴含了16个zip文件,这样循环5次,产生了16的5次方个文件,每个文件的大小是4.3GB,最初导致你的硬盘爆炸了。

感兴趣的敌人能够从http://www.unforgettable.dk/4... 下载,本人尝试一下。

怎么防止zip炸弹呢?

第一种做法在解压过程中检测解压过后的文件大小,如果超出肯定的限度就完结解压。

另一种做法,就是判断压缩文件中是否还有压缩文件,尽量减少这种压缩套压缩的做法。

billion laughs attack

billion laughs attack是解析XML文件产生的DOS攻打。

先上代码:

<?xml version="1.0"?><!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ELEMENT lolz (#PCDATA)> <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]><lolz>&lol9;</lolz>

下面的代码定义了10个entities,每个entity又蕴含了10个后面定义的entity,从而实现了指数级的字符串增长。最初生成了蕴含10亿个字符串的xml文件。

个别状况下,咱们会将xml放在内存中保留,这么多的字符串最初会耗尽咱们的内存,最终导致DOS。

咱们能够通过设置 XMLConstants.FEATURE_SECURE_PROCESSING 来避免这种攻打。

hashMap中插入太多雷同hashcode的元素

咱们晓得java中hashMap是用拆散链表来解决hash抵触的,如果插入了太多雷同hashcode的元素,就会导致这个hashcode对应的链表变得很长,从而查问效率升高,影响程序性能。

正则表达式乐观回溯

什么是乐观回溯呢?

咱们举个例子,如果大家对正则表达式曾经很相熟了。

如果咱们应用/^(x*)y$/ 来和字符串xxxxxxy来进行匹配。

匹配之后第一个分组(也就是括号外面的匹配值)是xxxxxx。

如果咱们把正则表达式改写为 /^(x*)xy$/ 再来和字符串xxxxxxy来进行匹配。 匹配的后果就是xxxxx。

这个过程是怎么样的呢?

首先(x)会尽可能的匹配更多的x,晓得遇到字符y。 这时候(x)曾经匹配了6个x。

接着正则表达式继续执行(x)之后的xy,发现不能匹配,这时候(x)须要从曾经匹配的6个x中,吐出一个x,而后从新执行正则表达式中的xy,发现可能匹配,正则表达式完结。

这个过程就是一个回溯的过程。

如果正则表达式写的不好,那么就有可能会呈现乐观回溯。

还是下面的例子,然而这次咱们用/^(x*)y$/ 来和字符串xxxxxx来进行匹配。

依照下面的流程,咱们晓得正则表达式须要进行6次回溯,最初匹配失败。

思考一些极其的状况,可能会导致回溯一个十分大的次数,从而导致CPU占用率飙升。

序列化和序列化

咱们将java对象存进文件或者进行网络传输的时候,都须要应用到序列化和反序列化。

如果咱们在对一个java对象进行反序列化的时候,很可能就会加载恶意代码。

因而咱们须要在反序列化的时候进行住够的安全控制。

大量的输入日志

通常咱们为了调试程序或者寻找问题都会输入大量的日志,如果日志文件太大会影响到磁盘空间的应用。

同时,日志写入操作也会对同一个硬盘上的其余写入操作产生影响。所以日志输入要抓住重点。

有限循环

在应用循环的时候肯定要留神,不要产生有限循环的状况。

应用第三方jar包

古代的java程序都会应用第三方jar包,然而第三方jar包的安全性还是须要咱们留神的。如果某些第三方jar包中蕴含有恶意代码,那么会对咱们的零碎造成十分重大的影响。

Xpath攻打

XPath 解析器是用来解析XML构造的工具,然而在应用XPath 解析器的时候,咱们须要留神避免注入攻打。

举个例子:

<users>     <user>         <name>张三</name>         <username>zhangsan</username>         <password>123</password>     </user>     <user>         <name>李四</name>         <username>lisi</username>         <password>456</password>     </user>

如果应用xpath,咱们须要这样来验证一个用户是否存在:

//users/user[username/text()='lisi'and password/text()='456']

如果用户传入username = 'lisi' 和 password = '456', 那么能够匹配胜利,证实用户存在。

然而如果用户输出相似 ' or 1=1 or ''=' 的值,咱们看下xpath的解析后果:

//users/user[username/text()=''or 1=1 or ''='' and password/text()='' or 1=1 or ''='']

后果产生和SQL注入一样的后果。

开释所有资源

通常来说,咱们在进行文件操作,锁获取操作的的时候会申请相应的资源,在应用完这些资源过后,千万要记得开释他们。

在JDK7 之后,引入了try with表达式,咱们能够将要开释的资源放入try语句内,在程序执行结束,资源会主动开释。

举个例子:

public R readFileBuffered(            InputStreamHandler handler        ) throws IOException {            try (final InputStream in = Files.newInputStream(path)) {                handler.handle(new BufferedInputStream(in));            }        }

下面的InputStream会主动开释。

本文已收录于 http://www.flydean.com/java-security-code-line-dos/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!