所以应该做的是确定“什么样的数据是合法的?”。在数据输入时,检查数据是否符合定义,拒绝所有不符合定义的数据;而不是检查数据是否不符合定义,接受符合定义的数据。
例如,有一个程序,根据用户的输入,创建一个文件。很显然,有些字符,如/,是不允许的。但是仅仅去检查这一个字符也不够,其他字符,比如,控制字符、空格、横线等,都有可能不合法。即使创建了一个“非法”字符的列表,也可能没有办法定义完全,因为总可能有没有考虑到的情况。
因此,正确的方法应该是:确定文件名输入的一个安全的特定格式,而拒绝不符合这个特定格式的所有输入。
3.2 几种典型的输入安全问题 3.2.1 数字输入安全问题数字的输入安全,是比较常见的。比如在表单上输入一个人的年龄,一般就会有范围限制。对数字的安全检查主要有:
格式,如整数、小数等;
精度,如小数保留的位数等;
范围,如某个输入数字的大小取值范围等;
类型和范围的匹配,如为了预防整数溢出,对短整数的输入进行范围检查,等等。
针对数字输入的安全要注意以下几点:
(1)将数字格式进行确定。比如,有的系统中数字是阿拉伯数字,也有的系统支持中文数字(如一、二、三,甚至壹、贰、叁等)输入,有的系统中数字每三位就有一个“,”,等等。一般情况下,可以用正则表达式来进行验证字符串是否是数字,然后进行数字的安全检查。
(2)对于负数的验证。一般***不要根据有没有符号位来确定该数是不是负数。因为有些程序中,如果输入一个很大的正数,也可能导致数值“溢出”而变成一个负数,而要进行一些底层的判断。
(3)特别要注意判断数值溢出(如整数溢出)的问题。
3.2.2 字符串输入安全问题字符串输入的安全性,也是很重要的。根据前面的原则,一般情况下,要确定合法的字符串,拒绝所有其他字符串;而不是确定非法的字符串,接受所有其他字符串。
同样,指定合法字符串最简单的方法是使用正则表达式,这种情况下,只需要正确使用正则表达式,描述合法字符串的模式,判断输入的字符串是否符合这个模式,拒绝不符合这个模式的数据。
关于对字符串的验证,有以下问题值得注意:
(1)如果使用正则表达式,***明确地指出要匹配数据的开始(通常用^来标识)和
结束(通常用$来标识),否则,攻击者可能在输入中嵌入攻击文本,并且能够绕过安全检查。
(2)尽可能在输入中拒绝特殊字符。因为有很多特殊字符在某些系统下拥有特殊的含义,如\,在Windows系统中可能作为文件路径分隔符。在开发阶段这个问题可能不容易引起注意,但是可能会被攻击者利用。
这些字符可能包括以下几类:
常规特殊字符,一般在ASCII码表内,如$、%、@、*、\0、\n等,但是由于有时候会用来表达特定含义,攻击者可能用数字代替这些字符来进行输入,达到攻击的目的。
不在ASCII码表内,字符值大于127的国际化的字符,也可能会有许多可能的含义。例如,UTF-8编码的字符,用两个字节进行编码,有些特殊字符也可以在该字符集里进行表达,尽量不要使用。
和某些特定应用有关的字符或者字符串,如shell中的命令名称(rm、ls、mount)、SQL中的关键词或者关键字符(如select、注释符号-一、单引号、exec)等。
在程序中有特定含义的字符,如某些系统中,将系统的配置信息用“#“隔开之后保存在配置文件内,这不是一个规定,但是可由软件的开发者在程序中自行确定;又如,在XML和HTML中用<和>表示结点,这些字符都不应该在合法范围之内。
3.2.3 环境变量输入安全问题在操作系统中,环境变量是交互环境(shell)中的变量,在该交互环境下运行的进程,可以访问环境变量并修改其值。
环境变量在同一个交互环境下只有一个实例。不同的交互环境有不同的实例,互不干扰。其功能是用于影响该环境下进程的行为。
例如,在Linux中,输入env命令,就可以看到系统中的环境变量。它们以“变量名=值”的形式出现。在Windows中,输入set命令,也可以看到系统中的环境变量。
环境变量的输入可能给攻击者带来机会。主要来源于:
(1)环境变量的内容给攻击者以机会。