WEB安全之XSS和CRSF攻击

XSS

定义

XSS攻击类似于SQL注入攻击,攻击之前,我们先找到一个存在XSS漏洞的网站,XSS漏洞分为两种,一种是DOM Based XSS漏洞,另一种是Stored XSS漏洞。理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script。

类似的攻击还有XSRF,XSRF是在本地生成cookie,模仿或者伪造跨域请求者信息,使用工具或者伪代码向后端发起请求,达到攻击的目的

攻击方式

  • 盗用Cookie,获取敏感信息
  • 破坏正常的页面的内容,插入恶意信息
  • 实现DDOS攻击效果:利用服务器请求占用请求,消耗服务器资源,使正常用户(合法用户)访问请求无法得到响应
  • ServerLimitDos,利用http的requestHeader请求header过长,http头超长,会造成部分用户无法访问站点

XSS攻击手方式主要有反射型和存储型

1.反射型:发出请求时候,XSS代码出现在URL中,作为请求提交到服务器中,服务器解析后响应,这样的一个过程叫做反射型XSS

例子:
假设有一个请求是:
http://ip:port/index
XSS攻击是请求地址为:
http://ip:port/index?xss=<script>alert('Hello');</script>

不单单是javascript,普通的DOM也可以
http://ip:port/index?xss=<iframe src='植入广告的网址'/>
http://ip:port/index?xss=<img src='广告的图片地址' onclick='window.location.href=广告网址'

2.存储型:存储型将提交的代码存储在服务器端(数据库、内存、文件系统等),下次请求目标页面时不用再提交XSS代码

XSS防范

编码

通过编码的统一,HTML Entity编码,就是将代码进行转义,比如>转义为&gt;

过滤

过滤掉<script>等敏感,移除用户上传的Dom属性,如onerror等,移除用户上传的style节点、script节点、iframeframe节点等

建议用户所有的事件全部要过滤掉,onclick、onerror等
如果攻击用户设置了style,假如被用户设置body为display:none,那么正常用户看到整个body都会变成空白,达到攻击的效果

校正

避免直接对Html Entity解码,使用Dom parse转换,校正不配对的Dom标签

Java防止XSS攻击

自定义

自定义HttpServletRequestWrapper

import java.util.Enumeration;



import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;



public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {  

    public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {

        super(servletRequest);

    }

    public String[] getParameterValues(String parameter) {

      String[] values = super.getParameterValues(parameter);

      if (values==null)  {

                  return null;

          }

      int count = values.length;

      String[] encodedValues = new String[count];

      for (int i = 0; i < count; i++) {

                 encodedValues[i] = cleanXSS(values[i]);

       }

      return encodedValues;

    }

    public String getParameter(String parameter) {

          String value = super.getParameter(parameter);

          if (value == null) {

                 return null;

                  }

          return cleanXSS(value);

    }

    public String getHeader(String name) {

        String value = super.getHeader(name);

        if (value == null)

            return null;

        return cleanXSS(value);

    }

    private String cleanXSS(String value) {

                //You'll need to remove the spaces from the html entities below

        value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");

        value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");

        value = value.replaceAll("'", "& #39;");

        value = value.replaceAll("eval\\((.*)\\)", "");

        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");

        value = value.replaceAll("script", "");

        return value;

    }



}

新建拦截器Filter

import java.io.IOException;  



import javax.servlet.Filter;  

import javax.servlet.FilterChain;  

import javax.servlet.FilterConfig;  

import javax.servlet.ServletException;  

import javax.servlet.ServletRequest;  

import javax.servlet.ServletResponse;  

import javax.servlet.http.HttpServletRequest;  

import javax.servlet.http.HttpServletResponse;



public class XssFilter implements Filter {

    FilterConfig filterConfig = null;



    public void init(FilterConfig filterConfig) throws ServletException {

        this.filterConfig = filterConfig;

    }



    public void destroy() {

        this.filterConfig = null;

    }



    public void doFilter(ServletRequest request, ServletResponse response,

            FilterChain chain) throws IOException, ServletException {

        chain.doFilter(new XssHttpServletRequestWrapper(

                (HttpServletRequest) request), response);

    }

}

配置拦截器

<filter>

     <filter-name>XssSqlFilter</filter-name>

     <filter-class>com.ibm.web.beans.XssFilter</filter-class>

  </filter>

  <filter-mapping>

     <filter-name>XssSqlFilter</filter-name>

     <url-pattern>/*</url-pattern>

     <dispatcher>REQUEST</dispatcher>

  </filter-mapping>

CRSF

定义

CSRF攻击形式其实很简单,正因为它的简单反而容易被人忽视,因此它的危害非常巨大。其攻击形式为:用户(USER)首先登录一正常网站(Normal Website),正常网站向用户浏览器发送cookie信息,此时用户还未注销登录信息。然后用户又打开浏览器另一标签页(tab)访问了一个恶意网站(Malicious Website),Malicious Website会自动构造指向Normal Website的恶意HTTP请求(更新、删除、添加您的重要信息)

攻击

1)假如系统没有权限控制,通过跨域伪造来达到攻击的效果

<img src="http://xxx/del_user_posts.do?id=1234"/>

加入非正常用户通过分析网页得到网站的删除链接是del_user_posts,那么在别的系统通过修改id来删除系统中的数据,这个是非常可怕的

2)攻击实例
比如说,受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2可以使 Bob 把 1000000 的存款转到 bob2 的账号下。

通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src="http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ",并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。

防御策略

验证 HTTP Referer 字段

Referer带有网站的域名信息,后台可以校验这个域名是否是本站点,如果不是,直接拒绝

// 从 HTTP 头中取得 Referer 值
 String referer=request.getHeader("Referer"); 
 // 判断 Referer 是否以 bank.example 开头
 if((referer!=null) &&(referer.trim().startsWith(“bank.example”))){ 
    chain.doFilter(request, response); 
 }else{ 
    request.getRequestDispatcher(“error.jsp”).forward(request,response); 
 }

在请求地址中添加 token 并验证

用户请求存在与Cookie中,假设服务器每次都会产生一个随机Token,返回到浏览器中,浏览器中下次请求必须带上此Token,服务器有一个Filter来校验此Token,如果Token不正确,则拒绝此请求

HttpServletRequest req = (HttpServletRequest)request; 
 HttpSession s = req.getSession(); 

 // 从 session 中得到 csrftoken 属性
 String sToken = (String)s.getAttribute(“csrftoken”); 
 if(sToken == null){ 

    // 产生新的 token 放入 session 中
    sToken = generateToken(); 
    s.setAttribute(“csrftoken”,sToken); 
    chain.doFilter(request, response); 
 } else{ 

    // 从 HTTP 头中取得 csrftoken 
    String xhrToken = req.getHeader(“csrftoken”); 

    // 从请求参数中取得 csrftoken 
    String pToken = req.getParameter(“csrftoken”); 
    if(sToken != null && xhrToken != null && sToken.equals(xhrToken)){ 
        chain.doFilter(request, response); 
    }else if(sToken != null && pToken != null && sToken.equals(pToken)){ 
        chain.doFilter(request, response); 
    }else{ 
        request.getRequestDispatcher(“error.jsp”).forward(request,response); 
    } 
 }

在 HTTP 头中自定义属性并验证

通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。局限性较大,只适合Ajax

Spring防止攻击

使用HandlerInterceptorAdapter

public class CSRFTokenInterceptor extends HandlerInterceptorAdapter {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
            Object handler) throws IOException {
        String token = CookieUtils.getCookie("csrf_token"); //从cookie中读取token
        if (request.getMethod().equalsIgnoreCase("POST")) {
            String requestType = request.getHeader("X-Requested-With");
            //AJAX POST 请求
            if (requestType != null && requestType.equalsIgnoreCase("XMLHttpRequest")) {
                if (token != null && token.equals(request.getHeader("csrf_token")))
                    return true;
            } else if (token != null && token.equals(request.getParameter("csrf_token"))) {//普通表单POST方法
                return true;
            }

            if (token == null) {
                token = UUID.randomUUID().toString();
                CookieUtils.addCookie(request, response, "csrf_token", token);
            }
            //SC_FORBIDDEN,状态码是403,表示服务器明白客户的请求,但拒绝响应
            response.sendError(403, "Bad or missing token!");
            return false;
        }


        if (token == null) {
            token = UUID.randomUUID().toString();
            CookieUtils.addCookie(request, response, "csrf_token", token);
        }

        //request只有两个页面之间的作用域,不能再传给第3个页面了
        //request只能在一次页面传递之间保存数据,超过就会丢失
        request.setAttribute("token", token);
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值