Web安全那些事儿

安全原则

  • Secure By Default
    • 白名单/黑名单
    • 最小权限
  • 纵深防御
    • 不同层面、不同角度
  • 数据与代码分离
  • 不可预测性
    • 使用加密算法、随机数、哈希算法对敏感数据进行处理,以使其不可预测

客户端脚本安全

浏览器

  • 同源策略
    • host
    • 子域名
    • 端口
    • 协议

使用HTTP头Access-Control-Allow-Origin是把双刃剑,在使得绕过同源策略的同时,也引发了安全的问题,使用时要注意

XSS

XSS又叫”HTML注入”,主要是通过网站上的用户输入输出来执行恶意的JS代码来完成攻击

  • 类型
    • 反射型
    • 存储型
    • DOM Based

现在浏览器对URL中的script会检查,并有如下提示

The XSS Auditor refused to execute a script in ‘http://localhost/websecurity/index.php?param=%3Cscript%3Ealert(/xss/)%3C/script%3E‘ because its source code was found within the request. The auditor was enabled as the server sent neither an ‘X-XSS-Protection’ nor ‘Content-Security-Policy’ header.

使用header(“X-XSS-Protection: 0”)可以关闭浏览器的xss检查并测试

危害

  • 获取客户端信息
    • 通过navigator可以获取用户的浏览器、安装的插件等信息
    • 通过JavaApplet可以获取用户的真实IP
    • 通过document.cookie可以进行比较经典的”cookie劫持”
    • 通过css的visited属性获取用户访问过的链接(现在已不复存在)

收集到这些信息,便可以通过生成一个0像素的图片的src发送到攻击者的服务器上

  • 构造GET/POST请求

这个可以导致用户在不知情的情况下完成了一些攻击者所期望的HTTP请求

  • XSS钓鱼

通过JS绘制表单,引导用户输入密码等信息发送到攻击者的服务器

  • XSS Worm

构造GET/POST请求的基础上,利用发站内消息等途径将XSS攻击代码进行传播

构造技巧

  • 利用字符编码

通过有些字符编码可以巧妙地把转义符号给“吃”掉

  • 绕过长度限制
    • 事件
    • 注释符
    • location.hash(内容不会在HTTP包中发送)

location.hash保存的是URL井号(#)及之后的内容,如果将页面中注入以下语句

1
onclick="eval(location.hash.substr(1))" //通过substr(1)把井号去掉

然后在URL里便可通过井号+相应JS代码完成攻击

  • 使用base标签

由于base标签可以放在body内,并且它定义了页面上的所有使用“相对路径”标签的hosting地址
所以当页面上有相对路径的标签,并且攻击者对当前页面注入了base标签指向自己的服务器,便可以执行自己服务器上相应的文件

  • window.name

因为window对象是浏览器的窗体,所以不受同源策略的限制,攻击者利用它可以实现跨域、跨页面传数据(比如将cookie赋值给window.name,然后跳转到攻击者的域名上输出)

防御

  • Http Only
1
bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string$domain [, bool $secure = false [, bool $httponly = false ]]]]]] )

PHP的setcookie函数最后一个参数就是Http Only
设置该参数为TRUE后,该COOKIE即无法被JS获取到,便可防止cookie劫持

  • 输入检查

又叫XSS Filter。故名思义,是对用户输入的数据进行检查——是否存在引起XSS攻击的特殊字符
但是这样做有一定的缺陷——因为无法判断用户转入数据的语境,容易引起改变用户的本意(比如对双引号做了转义,而用户输入的我是”天才”,最终会被显示为我是\”天才\”
所以这种Filter建议用在已知输入限制的情况下(比如ID全部是数字)

  • 输出检查
    在变量输出到HTML页面时,使用编码函数或转义来防御XSS攻击
    由于XSS比较复杂,所以需要在正确的地方使用正确的编码方式

    • 在正确的地方防御
      • HTML标签:HtmlEncode
      • HTML属性:HtmlEncode、HTMLEntities
      • SCRIPT标签:确保输出的变量在引号中->JavascriptEncode
      • 事件:JavascriptEncode
      • CSS:encodeForCss
      • 地址:确保变量以http开头(没有则强制加上)->URLEncode
  • 处理富文本

    • 通过htmlparser解析出富文本中的HTML标签->白名单
    • 最好禁止自定义样式,如果一定要允许,也需要对CSS进行parser并应用白名单过滤
    • 成熟的富文本XSS检查项目
      • PHP开源项目HTMLPurify
      • Anti-Samy
  • 防御DOM Based XSS (DOM Based XSS比较特别(前面的方法不顶用),需要特别对待)

    • 形成:将代码写入DOM节点
    • 防御:首先,转出到script时应执行javascriptEncode,其次,再write到HTML页面的话:如果是事件或脚本,再做一次javascriptEncode;如果是HTML内容或属性,则用HtmlEncode

CSRF

  • CSRF的产生

用户在A网站上登录后,访问了B网站,B网站上包含A网站请求的代码,该请求执行成功

  • 原因

COOKIE分为Session Cookie和Third-party Cookie
Third-party Cookie保存在本地,有些浏览器会默认禁止Third-party Cookie随其他网站的标签(img、iframe、script、link等)中的链接发送,而有些浏览会允许。在允许的浏览器中就会由于Third-party Cookie的发送而导致请求执行,从而CSRF攻击成功

  • 防御
    • 验证码
    • Referer Check
    • Token(WEB框架一般都会提供该功能,只需开启选项即可)
  • 其他
    • P3P头会导致浏览器对Third-party Cookie的限制失效,从而扩大CSRF攻击范围。使用时应多注意
    • CSRF不仅可以发起GET请求,也可以模拟POST请求,甚至扩散成为CSRF Worm

点击劫持

  • 产生

攻击者使用透明的iframe,诱使用户在不知情的情况下点击透明iframe页面

  • 类型
    • Flash点击劫持
    • 图片覆盖攻击
    • 拖拽劫持
    • 触屏劫持
  • 防御
    • frame busting 用JS代码禁止iframe嵌套
    • X-Frame-Options 在HTTP头中设置,为解决劫持而生
      • DENY 拒绝当前页面加载任何frame页面
      • SAMEORIGIN 仅允许同源下页面加载frame页面
      • ALLOW-FROM origin 自定义源

HTML5安全

  • 新标签可能会产生新的XSS攻击
  • iframe的sandbox增加了其安全性
  • a标签和area标签新增的noreferer属性,定义后不再发送Referer,可保护敏感信息和隐私
  • canvas的出现在丰富了客户端的同时,也可被攻击者巧妙使用(比如破解验证码)
  • postMessage可以跨窗口传递消息,会使XSS更灵活
  • Web Storage可以成为攻击者保存恶意代码的地方,从而实施跨页面攻击

服务器端安全

SQL注入

注入步骤

服务端有这么一条sql:

1
sql = "select * from orders where city = '". $ciy . "'";

那么当用户输入Beijing’;drop table orders–,这条sql就变成了

1
select * from orders where city = 'Beijing';drop table orders--'

这样就完成了SQL的注入

盲注

在不知道后端程序是如何执行,并且服务器没有错误回显时,就需要一些方法测试注入的SQL能否执行,这就是盲注

比如常见的and 1=1and 1=2
以及不常见的Timing Attack——利用BENCHMARK()函数,让同一个函数执行若干次,通过执行时间的长短来判断注入语句是否执行成功

其他攻击技巧

  • 通过LOAD_FILE()读取系统文件,并通过INTO DUMPFILE/INTO OUTFILE写入本地文件(需要有相应的权限)
  • 通过lib_mysqludf_sys提供的函数执行系统命令
  • 基于字符集的注入攻击-通过字符编码可以把转义符给“吃”掉
  • SQL Column Truncation(列截断攻击)
    如果sql-mode设置为default(没有开启STRICT_ALL_TABLES选项)时,MySQL会对用户插入的超长值只提示Warning并截断插入成功,通过这种方式可以修改管理员密码等

防御

找到所有的SQL注入漏洞并修补这些漏洞

  • 使用预编译语句
  • 统一数据库、操作系统、WEB应用的字符集
  • 使用安全的存储过程(存储过程要避免导致SQL注入)
  • 检查数据类型
  • 使用安全函数

文件上传漏洞

用户上传了一个可执行的脚本文件,并通过些脚本文件获得了执行服务端命令的能力

  • 常见安全问题
    • 上传WEB脚本,服务器执行了该脚本,导致代码执行
    • 上传的是crossdomain.xml导致可以控制Flash的域限制
    • 上传病毒、木马,诱骗用户或管理员下载执行
    • 上传钓鱼图片或包含脚本的图片被执行
  • 防御
    • 文件上传的目录设置为不可执行
    • 判断文件类型
    • 使用随机数改写文件名和文件路径
    • 单独设置文件服务器域名

PHP安全

文件包含漏洞

  • 函数
    • include
    • require
    • include_once
    • require_once

由于PHP内核不会在意这些函数包含的文件是什么类型,所以会把包含的文件作为PHP代码执行

导致文件包含漏洞主要有两个条件

  • 包含函数通过动态变量方式包含文件
  • 用户能控制该动态变量
  • allow_url_include为ON(可加载远程文件)

如下所示:

1
2
$file = $_GET['file'];
if (file_exsits('/www/'.$file.'.php')) include '/www/'.$file.'.php';

这里有一个问题就是代码中的地址拼接中有后缀,攻击者所要做的就是把这个后缀给PASS掉

  • 字符串结束符(\0)

由于PHP是由C语言实现的,因此在连接字符串时,0字节(\x00)作为字符串的结束符,因些攻击者可以通过在地址栏中使用如下参数即可完成攻击

1
?file=../etc/passwd%00 // ../etc/passwd\0
  • 操作系统对目录最大长度限制

windows下256字节,linux下4096字节,最大值长度之后的字符将被丢掉

变量覆盖漏洞

  • 全局变量覆盖(register_globals)

开启该选项可导致URL中的参数覆盖代码中同名的变量(参见全局变量注册),
PHP5.4.0之后已经移除

  • extract函数
1
int extract ( array &$array [, int $flags = EXTR_OVERWRITE [, string $prefix = NULL ]] )

extract能将变量从数组导入当前的符号表中,第二个参数如果是EXTR_OVERWRITE(默认),就会覆盖当前重名的变量

  • import_request_variable函数

该函数的作用是把GET、POST、Cookie中的变量导入到全局,第二个参数为导入的变量添加前缘,没指定的情况下会覆盖当前重名的变量
PHP5.4.0之后已经移除

  • parse_str函数

解析URL中的query string

代码执行漏洞

  • 直接执行代码的函数

    • eval
    • assert
    • system
    • exec
    • shell_exec
    • passthru
    • escapshellcmd
    • pcntl_exec
    • 等等
  • preg_replace

preg_replace第一个参数如果存在/e模式,则允许代码执行(ThinkPHP 2012年曾暴过该漏洞,围观)

  • 动态函数执行(如代码所示)
1
2
3
4
//http://a.com/?foobar=system(%27ls%27)
$foobar = $_GET['foobar'];
$d_func = create_function('$foobar', "echo $foobar;");
$d_func('');
  • 回调函数执行
    • array_map
    • array_filter
    • array_reduce
    • 等等

防御

  • 升级到较高的PHP版本(>=5.4.0)
  • 禁用0字节(代码实现对$_GET中的0字节进行过滤)
  • open_basedir
  • disable_functions

Web Server配置安全

Web Server的安全主要有以下几点

  • Web Server本身的安全
  • 加载的模块的安全
  • 执行Web Server的用户及权限
  • HPP(HTTP Parameter Pollution):通过GET或POST向服务器发起请求时,提交两个相同的参数,根据Web Server的处理方式绕过一些服务器端的逻辑判断

对应的防御

  • 模块的安装遵循“最小权限原则”,尽可能地减少不必要的Module
  • Web Server以单独的用户执行
  • 关注漏洞并及时升级到安全的版本
  • 因为HPP是服务器软件的一种功能,所以只需在具体环境中注意Web Server环境的参数取值顺序即可

结论

WEB涉及到两个方面

  • 横向的层(浏览器、第三方内容、WEB前端框架、WEB应用、WEB开发框架、WEB服务端语言、WEB容器、存储、操作系统等)
  • 纵向的数据流(输入输出)

一切的WEB安全问题都体现在这些层的“输入输出”上。针对于这些“输入输出”的问题,笔者也只能从阅读中择其主要的记之一文,更多的需要对安全问题的持久关注、实践及研究

参考

坚持原创技术分享,您的支持将鼓励我继续创作!