每一个Java平台都有自己默认的编码方式。“Supported Encodings”文档中列举了一些可能出现的编码方式[Encodings 2006]。在字符和一组字节序列之间进行编码转换时,需要通过字符编码方式指定转换细节。当没有显式指定编码方式时,会使用系统默认的编码方式完成这种转换。首先将字符转换为一个字节数组,然后将数组送到输入设备,经过通信通道进行传输,由输入设备接收,最后转换为字符。在这两次转换中,要使用兼容并且一致的编码。如果没有使用一致的编码,会破坏数据。根据Java API[API 2006]对String类的描述:一个新的String的长度是与字符集有关的,并且由于这个原因,它可能会与字节数组的长度不同。当指定的字节不适用于指定的字符集时,String构造器表现出来的行为是不确定的。二进制数据被认为是合法的字符串,它会被读取并转换为字符串,这是规则FIO11-EX0特例。
下面的代码示例读取一个字节数组,然后使用平台默认的字符编码将其转换为字符串。当默认的字符编码和用来产生字节数据的编码不同的时候,产生的字符串可能是不正确的。当某些输入在默认的编码中没有有效的字符表示时,也会产生不确定的行为。
FileInputStream fis = null; try {? ??fis = new FileInputStream("SomeFile"); ??DataInputStream dis = new DataInputStream(fis); ??byte[] data = new byte[1024]; ??dis.readFully(data); ??String result = new String(data); } catch (IOException x) { ??// handle error } finally { ??if (fis != null) { ????try { ??????fis.close(); ????} catch (IOException x) { ??????// Forward to handler ????} ??} }该方案在String构造函数的第二个参数中明确指定了需要的字符编码。
FileInputStream fis = null; try { ??fis = new FileInputStream("SomeFile"); ??DataInputStream dis = new DataInputStream(fis); ??byte[] data = new byte[1024]; ??dis.readFully(data); ??String encoding = "SomeEncoding"; // for example, "UTF-16LE" ??String result = new String(data, encoding); } catch (IOException x) { ??// handle error } finally { ??if (fis != null) { ????try { ??????fis.close(); ????} catch (IOException x) { ??????// Forward to handler ????} ??} }IDS13-EX0:当Java应用使用相同平台和默认的字符编码来产生数据,并且通过一个加密的通信通道(详情请参考MSC00-J)进行传输时,可能会在接收侧忽略一个显式的字符编码。
对文件或者网络I/O进行操作时,如果没有明确指定字符编码,那么会导致数据被破坏。
自动化检测 通过自动检测来发现这个漏洞是不可行的。
[Encodings 2006]
相关资源:CIC-IDS-2017加拿大入侵检测数据集(.CSV)第二部分