一、限制传递给ZipInputStream的文件的大小
通过对java.util.ZiplnputStream的输入进行检查可以防止消耗过多的系统资源。当资源使用大大多于输入数据所使用的资源的时候,就会出现拒绝服务问题。
(一)、不符合的示例代码
static final int BUFFER = 512;
BufferedOutputStream dest = null;
FileInputStream fis =new FileInputStream(filename);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
while ((entry zis.getNextEntry()) != null) (
int count;
byte data[]= new byte[BUFFER];
FileOutputstream fos = new FileOutputstream(entry,getName());
dest = new BufferedOutputStream(fos, BUFFER);
while ((count = zis.read(data,0,BUFFER)) !=-1)
{
dest.write(data. 0.count);
}
dest.flush();
dest.close);
}
zis.close();
(二)、符合的示例代码
在这个方案中,while 循环中的代码会通过使用 ZipEntry.getSize0 方法在解压之前,得到zip文档中需解压文件的大小。如果该解压文件过大,比如说超过 100MB,那么抛出异常。
static final int TOOBIG=0x6400000: //100MB
if (entry.getsize() > TOOBIG)(
throw new IllegalStateException("File to be unzipped is huge,");
}
if (entry.getSize()- -1) {
throw new IllegalStateException("File to be unzipped might be huge.");
}
FileOutputStream fos = new FileOutputStream(entry.getName());
dest = new BufferedOutputstream(fos,BUFFER);
while((count =zis.read(data,0,BUFFER))!--1){
dest.write(data, 0,count);
}
二、使用ASCII 字符集的子集作为文件名和路径名
如果文件名和路径名中包含了特殊字符,就会有问题,并且它会引起不可预期的系统行为,从而导致安全漏洞。在构建文件名或者路径名的时候,下面的字符和模式是有问题的。
1、以破折号开头:当调用一个程序时,使用的是它的文件名,若文件名以破折号开头,那么会导致问题,因为这样的文件名的第一个字符会被解析为选项标志。
2、控制字符,例如换行符、回车与 Esc: 在执行 shell 脚本和记录日志的时候,如果在文件名中采用控制字符,那么可能会导致意想不到的问题。
3、空格:脚本中的空格会导致问题,在没用双引号包围文件名的时候空格也会引发问题。
4、不合法的字符编码:字符编码会使正常验证文件名和路径名变得困难 (参见规则IDS11-J)。
5、命名空间分隔符:文件名和路径名中包括了命名空间分隔符,会引起潜在的安全问题和不可预期的后果。
6、命令行解释器、脚本和解析器:某些字符对于命令行解释器、shell 或者解析器来说,是有特殊含义的。应该避免使用它们。
(一)、不符合的示例代码
File f=new File("A\uD8AB");
OutputStream out = new FileOutputStream(f);
(二)、符合的示例代码
File f=new File("name.ext")
Outputstream out = new FileOutputstream(f);
三、使用ASCII 字符集的子集作为文件名和路径名
当 locale 没有明确指定的时候,使用 locale 相关的方法处理与 lcale 相关的数据会产生意想不到的后果。编程语言的标示符、协议关键字以及 HTML 标签通常会指定 Locale.ENGLISH作为一个特定的 locale。当改变默认的 locale 的时候,很有可能使数据绕过检查,从而改变 locale相关方法的行为。比如,当把一个字符串转换为大写字符时,可认为它是合法的,然而,当把它接着转换回小写字符时,可能就会产生黑名单字符串。
任何一个程序调用 locale 相关方法时,如果使用非受信数据,必须显式指明使用这些方法的locale。
(一)、不符合的示例代码
这个代码示例中使用了locale相关的String.toUpperCase()方法来将HTML标签转换为大写字符。在英文locale中,会将“title”转换为“TITLE”在土耳其locale中,会将“title”转换为“T?TLE”其中的“?”是拉丁文字母“I"
title.toUpperCase();
(二)、符合的示例代码
该方案显式地将 locale 设置为英文,从而避免产生意想不到的问题
"title".toUpperCase(Locale.ENGLISH);
这条规则同样适用于 String.equalsIgnoreCase()方法。
(三)、符合的示例代码
符合规则的方案在对字符串数据进行处理之前,把默认的 locale 设置为 English。
Locale.setDefault(Locale.ENGLISH);
"title".toUpperCase();
四、不要忽略方法的返回值
如果通过返回值来判断方法调用成功与否,或者通过返回值来更新本地的对象或数据成员,当忽略方法的返回值时,可能会产生安全风险,特别是在调用该方法的代码中没有进行适当处理时。所以程序必须重视方法调用的返回值。
(一)、不符合的示例代码
这个不符合规则的代码示例想要删除一个文件,但却没有确认这个删除动作是否成功。
public void deleteFile() [
File someFile = new File("someFileName.txt");
// do something with someFile
someFile.delete();
}
(二)、符合的示例代码
这个符合规则的方案对 delete() 方法返回的 boolean 变量进行检查,并且处理了可能产生的错误。
public void deleteFile() (
File someFile = new File("someFileName.txt"y;
// do something with someFile
if (!someFile.delete())(
// handle failure to delete the file
}
}
五、使用两个参数的Arrays.equals()方法来比较两个数组的内容
数组不会重写 Object.equals()方法,而 equals0 方法比较的是数组引用而不是数组的内容值程序必须使用两个参数的 Arrays.equals0 方法来比较两个数组的内容。当想要测试引用是否相等时,程序必须使用引用相等操作:== 和!=。程序不能使用数组的 quals() 方法,因为它会导致不可预期的后果。
(一)、不符合的示例代码
这个不符合规则的代码示例不正确地使用了 Object.equals( 方法来比较两个数组
public void arrayEqualsExample() [
int[] arrl =new int[20]; // initialized to 0
int[] arr2=newint[20];// initialized to 0
arrl.equals(arr2); // false
}
(二)、符合的示例代码
这个符合规则的方案使用了两个参数的Arrays.equals0 方法来比较两个数组
public void arrayEqualsExample() [
int[] arrl =new int[20]; // initialized to 0
int[] arr2=newint[20];// initialized to 0
Arrays.equals(arr1,arr2); // true
}