WEB2.0的普及,丰富了各类WEB产品。WEB交互能力的增强,也滋生出种类繁多的安全威胁,用户输入便成了万恶之源,不仅威胁用户信息安全,也给服务器、操作系统,甚至整个局域网带来灾难,因此,验证用户输入是WEB应用必不可少的安全防范举措。
1 输入为何需要验证
输入验证一般基于两个方面的原因:一是为了保证业务功能的合理性,二是为了保证用户数据、应用程序及内部系统和网络的安全。
1.1 业务层面
从业务的有效性和合理性来说,用户提交的参数都需要进行验证。在业务层面可能要求用户名只能包含大小写字母、数字,长度必须小于12位等;密码必须同时包含字母、数字、特殊字符,且长度必须大于8位等;金额必须在(0~1000]之间……诸如此类,我们的应用程序都需进行检测。可以想象,在金融类系统中,如果不对金额进行有效性检查,在转账类业务中,如果提交转账金额-10000¥,那是不是等同于对方给我转了10000¥呢。
1.2 安全层面
从另一个安全层面来说,输入验证则显得尤为重要,而这一点恰恰容易被开发者所忽略,众多的WEB漏洞中,无不因输入引起。如果你的应用中涉及如下功能,那么就得考虑是否有相应的验证和防护措施。
类型
功能
安全威胁
说明
输入
↓
服务器端
响应
输入作为响应body的一部分
XSS
XXE
XML作为参数传递
输入作为响应header的一部分
CRLF
输入作为邮件的一部分
SMTP注入
响应中包含输入指定的文件
目录遍历
重定向至输入指定的网页
任意重定向
输入
↓
服务器端
执行代码
输入嵌入SQL语句中
SQL注入
输入嵌入XPath表达式
XPath注入
输入嵌入LDAP语句
LDAP注入
输入作为应用代码执行
OS命令注入
文件上传
后门
输入
↓
服务端
API参数
服务器端包含输入指定的文件
文件包含
服务器端请求输入的网址
服务器端HTTP重定向
不同应用之间通过输入参数互相调用
SOAP注入
使用SOAP
JSON注入
使用JSON
XML注入
使用XML
HTTP参数注入
……
表1-1功能和安全威胁对照表
2 哪些输入要素需要验证
上面已经提到如果不验证输入带来的威胁,那到底哪些输入需要验证呢?这就得先了解信任边界。
2.1 信任边界
信任边界是以组件或者功能单元进行区分,在信任边界外的所有输入均需验证。下图展示了一个典型的信任边界验证的例子(各个组件在执行操作前,均需输入验证):
WEB应用安全之输入验证 - tuchengju - tuchengju的博客
图2-1 信任边界确认
(1) 应用程序收到用户提交的输入。表单处理程序确认每个输入仅包含的合法字符、特殊长度限制,应转义或者过滤任何已知的攻击特征。
(2) 应用程序执行SQL查询。为防止SQL注入, DAO执行查询前,应用程序应对用户输入中包含的可用于攻击数据库的所有字符转义。
(3) 将用户提交的某些输入数据提交给SOAP服务,进一步获取相关数据。为防止SOAP注入,SAOP查询组件需要对用户提交数据中的任何XML元字符进行适当编码。
(4) 应用程序在用户的浏览器中显示响应数据。为防止跨站脚本攻击,输出组件需对植入返回页面中的任何用户提交数据执行HTML编码。
2.2 输入来源
在WEB应用中,输入来源基本可分为两类:一类由用户提交,另一类则来自于共享数据。用户提交的数据主要包括:
(1) 查询参数
(2) POST参数
(3) Cookie
(4) Referer
(5) REST参数
共享数据主要包括:
(1) 共享数据库
(2) 共享文件数据
(3) 网络数据
3 如何验证输入
输入验证的方式按照输入的类型有所不同,输入的类型可归纳为两类:常规参数和文件。当然,这里不涉及业务层面的合理性验证。
3.1 常规参数的输入验证
常规参数的输入验证方法需要根据特定的功能而定,主要有如下方法:
方法
说明
备注
字符转义
对影响程序结构和逻辑,以及改变输出效果的特殊字符均需转义。
效果比较好,且不影响业务功能。
字符过滤
对影响程序结构和逻辑,以及改变输出效果的特殊字符均需过滤。
效果比较好,但特殊字符可能与业务要求冲突。
白名单
只接受特定的输入,其他均忽略。
效果非常好,但适用性低,适合需要严格检查的业务。
黑名单
不接受特定的输入,其他均接受。
效果差,特别针对XSS等此类变种很多的安全威胁。
映射
建立映射关系,外部使用映射对象,而非直接使用源数据
效果非常好,但适用性低,适合需严格检查且不希望泄露源数据的业务。
表3-1 常规参数输入验证方法
如下针对各类安全威胁,列举了行之有效的参数输入验证方法:
类型
安全威胁
输入验证方法
输入
↓
服务器端
响应
XSS
纯文本的参数:输出时转义<、>、&、{、}、#、”、’、;、/、[、]为HTML实体,对于DOM型XSS,则需确保JS在使用参数前,转义这些特殊字符。
富文本的参数:
1、 格式化输入,保证所有数据均可被识别和标准化;
2、 采用白名单的机制,明确允许出现哪些标签、哪些属性,对不允许出现的标签和属性值进行干扰或移除;
3、 对特定的属性值进行检查,比如:url必须以http://或https://开头,或者以/开头等。
4、 对标签内的特殊字符(<、>、”、’等)采用HTML实体转义。
XXE
优选方案:在解析XML时,不解析外部实体。
CRLF
移除%0D%0A或者其他形式的回车换行符。
SMTP注入
移除%0D%0A或者其他形式的回车换行符。
正文中不允许仅包含.的消息行。
目录遍历
对输入解码和规范化,拒绝包含、/以及空字符的请求。
检查是否请求相应目录、相应后缀的文件。
或者使用白名单指定允许访问的文件列表,拒绝其他文件的访问。
任意重定向
对输入解码和规范化,检查重定向地址是否在合法域内。
输入
↓
服务器端
执行代码
SQL注入
参数化查询。
XPath注入
仅允许字母数字。
拒绝包含(、)、=、’、[、]、:、,、*、/,以及所有空白符的请求。
LDAP注入
仅允许字母数字。
拒绝包含(、)、;、,、*、|、&、=,以及空字符的请求。
OS命令注入
避免直接调用操作系统命令。
白名单限制允许调用的系统命令,拒绝白名单之外的命令执行。
输入
↓
服务端
API参数
文件包含
白名单限制允许包含的文件,拒绝白名单之外的文件包含。
服务器端HTTP重定向
建立重定向地址的强随机映射表,外部提交随机字符,应用程序则根据随机字符匹配重定向地址,拒绝无法映射的重定向。
SOAP注入
解码后转义<、>、/ 为<、>、/。
XML注入
解码后转义<、>、/ 为<、>、/。
JSON注入
解码后转义’、”、、{、}、[、]为’、”、\、{、}、[、]。
HTTP参数注入
解码后转义&为%26
表3-2 常见安全威胁输入验证方法
3.2 文件上传的输入验证
文件上传时,如果验证不当,则很可能被用于上传恶意文件,也就是说,服务器以及内部网络可能完全沦陷。一般地,需对上传文件执行如下检查:
(1) 文件类型:最好使用endWith检查上传文件名中的文件类型。
(2) 文件头:检查二进制文件的文件头是否为白名单文件类型的文件头。
(3) 文件格式:检查文件的格式是否为白名单文件类型的格式。
以上只是简单总结WEB应用常见安全威胁的一般输入验证方法,在具体的项目开发过程中,还需要有针对性的调整验证策略。希望此文能给各位开发、测试人员以及白帽子们有所帮助。