Java 缓冲区的安全实现
我想使用BufferedReader读取上载到服务器的文件 该文件将被写入CSV文件,但我不能假设这一点,因此我编写了一些测试,其中该文件是图像或二进制文件(假设客户端向我发送了错误的文件或攻击者试图破坏我的服务),或者更糟糕的是,该文件是有效的CSV文件,但有一行100MB 我的应用程序可以处理此问题,但它必须读取文件的第一行:Java 缓冲区的安全实现,java,security,io,bufferedreader,Java,Security,Io,Bufferedreader,我想使用BufferedReader读取上载到服务器的文件 该文件将被写入CSV文件,但我不能假设这一点,因此我编写了一些测试,其中该文件是图像或二进制文件(假设客户端向我发送了错误的文件或攻击者试图破坏我的服务),或者更糟糕的是,该文件是有效的CSV文件,但有一行100MB 我的应用程序可以处理此问题,但它必须读取文件的第一行: ... String firstLine = bufferedReader.readLine(); //Perform some validations and re
...
String firstLine = bufferedReader.readLine();
//Perform some validations and reject the file if it's not a CSV file
...
但是,当我编写一些测试代码时,我发现了一个潜在的风险:BufferedReader在找到返回行之前不会对读取的字节数执行任何控制,因此它可能最终抛出OutOfMemoryError
这是我的测试:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import org.junit.Test;
public class BufferedReaderTest {
@Test(expected=OutOfMemoryError.class)
public void testReadFileWithoutReturnLineCharacter() throws IOException {
BufferedReader bf = new BufferedReader(getInfiniteReader());
bf.readLine();
bf.close();
}
private Reader getInfiniteReader() {
return new Reader(){
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return 'A';
}
@Override
public void close() throws IOException {
}
};
}
}
我一直在互联网上寻找一些安全的BufferedReader实现,但什么也找不到。我找到的唯一类是来自ApacheIO的BoundedInputStream
,它限制了输入流读取的字节数
我需要一个BufferedReader的实现,它知道如何限制每行中读取的字节/字符数
大概是这样的:
- 该应用程序调用“readLine()”
- BufferedReader读取字节,直到找到返回行字符或达到允许的最大字节数
- 如果它找到了返回行字符,则重置读取的字节(以便它可以读取下一行)并返回内容
- 如果已达到允许的最大字节数,则抛出异常
有人知道BufferedReader的实现具有这种行为吗?这不是检测文件是否为二进制文件的方法 下面是如何检查文件是否为真正的文本;请注意,这要求您事先知道编码:
final Charset cs = StandardCharsets.UTF_8; // or another
final CharsetDecoder decoder = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT); // default is REPLACE!
// Here, "in" is the input stream from the file
try (
final Reader reader = new InputStreamReader(in, decoder);
) {
final char[] buf = new char[4096]; // or other size
while (reader.read(buf) != -1)
; // nothing
} catch (MalformedInputException e) {
// cannot decode; binary, or wrong encoding
}
现在,由于可以通过读取器
初始化缓冲读取器
,因此可以使用:
try (
final Reader r = new InputStreamReader(in, decoder);
final BufferedReader reader = new BufferedReader(r);
) {
// Read lines normally
} catch (CharacterCodingException e) {
// Not a CSV, it seems
}
// etc
现在,再解释一下这是如何工作的。。。虽然这是阅读Java文本的基本部分,但它也是一个同样被误解的部分 当您使用
读取器
以文本形式读取文件时,必须指定字符编码;在Java中,这是一个字符集
内部情况是Java将从该字符集
创建字符集解码器
,读取字节
流并输出字符
流。处理错误的方法有三种:
(默认值)):不可映射的字节序列被替换为(它确实响了,对吧?)李>CodingErrorAction.REPLACE
:不可映射的字节序列不会触发CodingErrorAction.IGNORE
字符的发射李>
:不可映射的字节序列触发要抛出的CodingErrorAction.REPORT
,该异常继承了CharacterCodingException
;反过来,IOException
的两个子类是CharacterCodingException
和格式错误的putException
不可映射的characterexception
- 事先知道编码李>
- 使用配置了
的CodingErrorAction.REPORT
李>CharsetDecoder
- 在
中使用它InputStreamReader
CharsetDecoder
类似地,对于反向操作(
char
stream tobyte
stream),也有一个CharsetEncoder
),这就是Writer
家族所使用的。谢谢@fge的回答。我最终实现了一个安全的阅读器
,它可以处理行太长(或者根本没有行)的文件
如果有人想查看代码,可以在此处查看该项目(即使有许多测试,也非常小的项目):
等等,为什么要用
读取器
读取二进制数据?你说你可以在“图像和二进制文件”之间进行“选择”…对不起,我会尝试改进我的问题。我使用的是阅读器
,因为我的服务设计为只处理CSV文件。但我必须处理客户端向我发送二进制文件的情况(不管是否意外)。在这种情况下,我的服务可以拒绝该文件,但它需要读取第一行。好的,那么我已取消删除我的答案。基本上,您不需要“读取第一行”:只需适当配置读取器
,并在其上使用缓冲读取器
。更多细节请参见我的答案。这似乎根本没有解决问题。OP正在寻找一个实现,引用:“读取字节直到它[…]或者它达到允许的最大字节数”@Unihedro引用这样一个问题:“该文件将被写入CSV文件,但我不能假设这一点”这可能解决二进制文件的问题,但是如果该文件有一行100MB的字符,会发生什么?请看我的JUnit测试。它返回有效字符,但数量无限them@jfcorugedo如果您真的想这样做,那么不要使用BufferedReader
;使用一个简单的读取器
,一个字符数组缓冲区,并在阅读时附加到StringBuilder
。好的。我知道我可以编写一个解决方案,但我想使用一个经过良好验证的实现(Apache?),但我找不到任何东西。但是,非常感谢,我不知道编码错误操作
。