《Java安全编码标准》学习笔记 - 1
一、概述
1、相对来说,Java是一种较为安全的语言:
1)没有显式的指针操作
2)对数组和字符串边界有自动检查机制
3)如果尝试引用一个空指针会抛出系统异常
4)算术运算是明确定义的且与平台无关,类型转换也是如此。
5)内置的字节码验证器可以确保这些检查会在正确的地方执行
二、输入验证和数据净化(IDS)
1、sql注入,使用PreparedStatement
2、xml注入,正则验证(白名单),xml模板
3、字符串验证前(如正则验证),先标准化字符串:Normalizer.normalize()
4、文件路径使用之前,先标准化路径名:file.getCanonicalPath()。然后检查路径名的安全性,比如是否在所允许访问的目录里
5、传递给ZipInputStream的文件应该限制大小
6、使用ASCII字符集的子集作为文件名和路径名,正则表达式:
Pattern pattern = Pattern.compile("[^A-Za-z0-9%&+,.=_]");
Matcher matcher = Pattern.matcher(filename);
if(matcher.find()){
//filename contains bad chars, handle error
}
7、不要向Runtime.exe()方法传递非受信、未净化的数据:正则过虑、通过switch选择(可以通过属性文件读入到java.util.Properties对象中)、避免使用Runtime.exec()
8、如果正则表达式的匹配模式中,有用户输入的字符,则需要对用户输入的字符进行净化。Character.isLetterOrDigit(char ch)
9、如果没有指定适当的locale,不要使用locale相关方法处理与locale相关的数据。
正例:
1)"title".toUpperCase(Locale.ENGLISH);
2)Locale.setDefault(Locale.ENGLISH);
"title".toUpperCase();
10、避免拆分多字节字符
1)
2)使用Reader
3)了解一下这两个类:java.text.BreakIterator、java.text.Collator
11、在验证前去掉非字符码点(自己实际编码,测试未通过)
12、在不同的字符编码中无损转换字符串数据时,通过CharsetEncoder和CharsetDecoder两个类来处理编码转换问题。写文件时可以给OutputStreamWriter传入CharsetEncoder参数
13、byte数组转化成String时,需指定字符编码,如:String result = new String(byteData,"UTF-8")
三、声明和初始化
1、防止类的循环初始化,正例:
2、避免类间的静态变量循环引用
3、不要重用Java标准库的已经公开的标识
4、将所有增强for语句的循环变量声明为final类型;给增强型的for循环变量赋值,不影响整体的迭代次序。
正例:
for(final Obj obj : objList){
}
四、表达式
1、不要忽略方法的返回值。如:
1)不可变对象需要重新赋值
2)判断方法返回结果是否为true
2、不要解引用空指针,注意对null的判断
3、数组不会重写Object.equals()方法,而equals()方法比较的是数组引用而不是数组的内容值。程序必须使用两个参数的Arrays.equals()方法来比较两个数组的内容。当想要测试引用是否相等时,程序必须使用引用相等操作:==或!=
4、不要用相等操作来比较两个基础数据类型的值。会被内存化的基础结构数据:如果要封装的p的数值是true、false、一个字节、一个在\u0000 ~ \u007f范围的char,或者是一个位于-128 ~ 127的int或short数据。
5、确保使用正确的类型来自动封装数值
6、不要在一个表达式中对同一变量进行多次写入
7、不要在断言中使用有副作用的表达式
五、数值类型与运算
1、检测和避免整数溢出
1)先决条件检测,通过Integer.MIN_VALUE和Integer.MAX_VALUE
2)
3)向上类型转换
4)使用BigInteger的方法来检测溢出
5)使用AtomicInteger时,应该通过get()方法判断当前值,符合计算要求后再通过compareAndSet()方法设置新值
2、不要对同一数据进行位运算和数学运算
3、确保除法运算和模运算中的除数不为0。注意:当被除数等于有符号整数的最小值并且除数是-1时,也会发生溢出
4、使用可容纳无符号数据合法取值范围的整数类型
5、不要使用浮点数进行精细计算
1)金额可以用分为单位进行计算
2)也可以使用BigDecimal,但是会有性能损失
6、不要使用非标准化数,用double类型进行浮点数计算
7、使用strictfp修饰符确保跨平台浮点运算的一致性
8、不要尝试与NaN进行比较。可以通过Double.isNaN(result); 来检测result是否是NaN
9、检查浮点输入特殊的数值。三种特殊的数值:无穷大、无穷小和NaN。
10、不要使用浮点变量作为循环计数器
11、不要从浮点字元构造BigDecimal对象。
正例:new BigDecimal("0.1");
反例:new BigDecimal(0.1);
12、不要比较或者审查以字符串表达的浮点数值
13、确保将数值转换成较小类型时不会产生数据丢失或曲解。转换之前做数值范围检查。
14、转换基本整数类型至浮点类型时应避免精度损失