目前,我有以下代码用于阅读InputStream
。我将整个文件存储到StringBuilder
变量中,然后再处理此字符串。
public static String getContentFromInputStream(InputStream inputStream)
// public static String getContentFromInputStream(InputStream inputStream,
// int maxLineSize, int maxFileSize)
{
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String lineSeparator = System.getProperty("line.separator");
String fileLine;
boolean firstLine = true;
try {
// Expect some function which checks for line size limit.
// eg: reading character by character to an char array and checking for
// linesize in a loop until line feed is encountered.
// if max line size limit is passed then throw an exception
// if a line feed is encountered append the char array to a StringBuilder
// after appending check the size of the StringBuilder
// if file size exceeds the max file limit then throw an exception
fileLine = bufferedReader.readLine();
while (fileLine != null) {
if (!firstLine) stringBuilder.append(lineSeparator);
stringBuilder.append(fileLine);
fileLine = bufferedReader.readLine();
firstLine = false;
}
} catch (IOException e) {
//TODO : throw or handle the exception
}
//TODO : close the stream
return stringBuilder.toString();
}
该代码已向安全团队进行审查,并收到以下评论:
BufferedReader.readLine
容易受到DOS(拒绝服务)攻击(无限长的行,没有换行/回车的巨大文件)
StringBuilder
变量的资源耗尽(当文件包含的数据大于可用内存时)
以下是我能想到的解决方案:
创建readLine
方法(readLine(int limit)
)的替代实现,该方法检查否。读取的字节数,如果超过指定的限制,则抛出自定义异常。
逐行处理文件而不完整加载文件。(纯非Java解决方案:))
请建议是否有任何实现上述解决方案的库。还建议比拟议的解决方案提供更鲁棒性或更易于实施的任何替代解决方案。尽管性能也是主要要求,但安全性是第一位的。
您想避免各种DOS攻击(在线,文件大小等)。但是在函数的最后,您试图将整个文件转换为一个String
!假设您将行限制为8
KB,但是如果有人向您发送包含两个8 KB行的文件会怎样?行读取部分将通过,但是最终当您将所有内容组合到一个字符串中时,字符串将阻塞所有可用内存。
因此,既然最终您将所有内容都转换为一个String,那么限制行大小并不重要,也不安全。您必须限制文件的整个大小。
其次,您基本上想做的是,您正在尝试分块读取数据。因此,您正在BufferedReader
逐行使用和阅读它。但是,您想要做的事情以及最终真正想要的是一种逐段读取文件的方式。为什么不一次读取2
KB,而不是一次读取一行?
BufferedReader
-顾名思义,其中有一个缓冲区。您可以配置该缓冲区。假设您创建的BufferedReader
缓冲区大小为2 KB:
BufferedReader reader = new BufferedReader(..., 2048);
现在,如果InputStream
您传递给BufferedReader
的数据具有100 KB的数据,则一次BufferedReader
将自动读取2
KB。因此它将读取流50次,每次2 KB(50x2KB = 100 KB)。同样,如果创建的BufferedReader
缓冲区大小为10
KB,它将读取10次输入(10x10KB = 100 KB)。
BufferedReader
已经完成了逐块读取文件的工作。因此,您不想在其上方逐行添加额外的层。只关注最终结果-
如果结尾的文件太大(>可用RAM)-您将如何将其转换为String
结尾?
一种更好的方法是将事物作为一个整体传递CharSequence
。这就是Android的功能。在整个Android
API中,您将看到它们CharSequence
随处可见。由于StringBuilder
也是的子类CharSequence
,因此Android会根据输入的大小/性质在内部使用String
,或a
StringBuilder
或其他一些优化的字符串类。因此,您宁可StringBuilder
在阅读完所有内容后直接返回对象本身,而不是将其转换为String
。这将对大数据更安全。StringBuilder
它还在内部保留了相同的缓冲区概念,它将在内部为大字符串分配多个缓冲区,而不是一个长字符串。
因此总体而言:
使用Apache Commons IO,这是将a中的数据读取BoundedInputStream
为的方式StringBuilder
,该方式分为2
KB的块而不是行:
// import org.apache.commons.io.output.StringBuilderWriter;
// import org.apache.commons.io.input.BoundedInputStream;
// import org.apache.commons.io.IOUtils;
BoundedInputStream boundedInput = new BoundedInputStream(originalInput, <max-file-size>);
BufferedReader reader = new BufferedReader(new InputStreamReader(boundedInput), 2048);
StringBuilder output = new StringBuilder();
StringBuilderWriter writer = new StringBuilderWriter(output);
IOUtils.copy(reader, writer); // copies data from "reader" => "writer"
return output;
使用BoundedInputStream从Apache的百科全书IO库。您的工作变得更加轻松。
以下代码将执行您想要的操作:
public static String getContentFromInputStream(InputStream inputStream) {
inputStream = new BoundedInputStream(inputStream, <number-of-bytes>);
// Rest code are all same
您只需InputStream
用来包装,BoundedInputStream
然后指定最大尺寸。BoundedInputStream
将注意将读取限制为最大大小。
或者,您可以在创建阅读器时执行以下操作:
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(
new BoundedInputStream(inputStream, <no-of-bytes>)
)
);
基本上,我们在这里要做的是限制InputStream
层本身的读取大小,而不是在读取行时这样做。因此,您最终得到了一个可重用的组件,例如BoundedInputStream
它会限制InputStream层的读取,并且您可以在任何需要的地方使用它。
编辑:添加了脚注
编辑2:根据评论添加了更新的答案
本文向大家介绍C#使用文件流读取文件的方法,包括了C#使用文件流读取文件的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#使用文件流读取文件的方法。分享给大家供大家参考。具体如下: 希望本文所述对大家的C#程序设计有所帮助。
本文向大家介绍Java基于IO流读取文件的方法,包括了Java基于IO流读取文件的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java基于IO流读取文件的方法。分享给大家供大家参考,具体如下: 希望本文所述对大家Java程序设计有所帮助。
问题内容: 最近,我们对代码进行了安全审核,问题之一是我们的应用程序受到 Xml eXternal Entity (XXE)攻击。 基本上,该应用程序是一个计算器,可通过Web服务以XML形式接收输入。 这是对我们的应用程序进行此类XXE攻击的示例: 如您所见,我们可以引用指向外部文件()的实体。 关于XML输入本身(该部分)未与JAXB(v2.1)一起编组。Web服务部分基于jaxws- rt(
想知道如何使用Xstream API修复Xml外部实体(XXE)漏洞。 就像我们能做的一样 使用DocumentBuilderFactory。更多详细信息-https://www.owasp.org/index.php/XML_External_Entity_(XXE)\u预防\u备忘单 我的代码是这样的-
在Java中获得文件扩展名的可靠方法是什么? 我不是在讨论对执行/,因为它对复杂的扩展(如等)毫无用处。(这是所有的库(Commons IO、Guava等)似乎都在做的。我正在寻找一种更复杂/可靠的方法来返回真正的扩展。
本文向大家介绍Laravel5中防止XSS跨站攻击的方法,包括了Laravel5中防止XSS跨站攻击的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Laravel5中防止XSS跨站攻击的方法。分享给大家供大家参考,具体如下: Laravel 5本身没有这个能力来防止xss跨站攻击了,但是这它可以使用Purifier 扩展包集成 HTMLPurifier 防止 XSS 跨站攻击。 1、