首页
登录 | 注册

详解Javaweb中常见漏洞的防御二

0x01 Token的使用

可以有效防止csrf漏洞和http请求批量提交或http重放,像爆破,刷评论,刷短信,请求重放,请求并发都可以利用token以及反射型xss和url调用之类的都可以用token做防御。

esapi中token的使用过程

a.在用户刚登录的时候,产生一个新的不可预知的CSRF Token,并且把此Token存放在用户的session中。

b.在任何一个需要保护的表单中,增加一个隐藏的字段来存放这个Token;对于需要保护的URL,增加一个参数来存放此Token。

c.提交此请求的时候,在服务器端检查提交的Token与用户session中的Token是否一致,如果一致,继续处理请求,否则返回一个错误信息给用户。

d.在用户退出或者session过期的时候,用户信息(包括CSRF Token)从session中移除并且销毁session。

看一下addCSRFToken函数,其实这个函数的作用就相当于加了个ctoken的参数,即&ctoken=xxxxx

	public String addCSRFToken(String href) {
		User user = ESAPI.authenticator().getCurrentUser();
		if (user.isAnonymous()) {
			return href;
		}

		// if there are already parameters append with &, otherwise append with ?
		String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken();
		return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token;
	}
故Get型请求增加token的写法是

String Href = "/test.php?action=update&id=100";

<a href='<%=ESAPI.httpUtilities().addCSRFToken(Href)%>'>update</a>

如果是form表单使用相同,不需要在写成form表单自动这么麻烦,同样可以达到防止刷接口和csrf的效果。

    String url = "/account/login/";
    <form action="<%=ESAPI.httpUtilities().addCSRFToken(url)%>" method="POST">
        <input type="text"  name="user"/>
        <input type="text"  name="pass"/>
        <input type="hidden" value="<%=token %>" name="ctoken"/>
        <input type="submit" value="submit"/>
    </form>

看一下它的验证方法,检测从客户端得到的ctoken和用户的csrftoken是相同。

	public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException {
		User user = ESAPI.authenticator().getCurrentUser();

		// check if user authenticated with this request - no CSRF protection required
		if( request.getAttribute(user.getCSRFToken()) != null ) {
			return;
		}
		String token = request.getParameter(CSRF_TOKEN_NAME);
		if ( !user.getCSRFToken().equals( token ) ) {
			throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected");
		}
	}

下面是表单中加入token的常用方法,实现起来也算简单方便。

   <%
           long token=System.currentTimeMillis();
           session.setAttribute("token",token);
    %>
    <form action="/account/login/" method="POST">
        <input type="text"  name="user"/>
        <input type="text"  name="pass"/>
        <input type="hidden" value="<%=token %>" name="ctoken"/>
        <input type="submit" value="submit"/>
    </form>


处理接收的token并进行验证

public String login(HttpServletRequest request, HttpServletResponse response){
    String username= request.getParameter("user");
    String password = request.getParameter("pass");
    
    String token = request.getParameter("ctoken");
    
    HttpSession session=request.getSession();
    String tokenInSession  =  ""+session.getAttribute("token");

    if (tokenInSession!=null && token!=null && token.equals(tokenInSession)) {
        session.removeAttribute("token");
        return "login";
    }
    return "error";  
    }


0x02安全随机数的生成

随机数的作用

1.可以防止平行越权漏洞,我们可以执行越权的原因是我们可以猜测这个操作的唯一关键字,像订单号变成唯一且随机的,我们就无法查看他人的订单了。

2.静态敏感文件的保存,当我们把省份证照片存储到网站目录上时,如果是时间戳生成的,可以预测的,我们就能爆破他人的身份证照片了。

3.生成安全的cookie,防止cookie可以被破解。

下面我们就看看esapi中随机数的使用和getRandomString函数:

获取特定字符串中长度为length的随机字符串

    public String getRandomString(int length, char[] characterSet) {
    	StringBuilder sb = new StringBuilder();
        for (int loop = 0; loop < length; loop++) {
            int index = secureRandom.nextInt(characterSet.length);
            sb.append(characterSet[index]);
        }
        String nonce = sb.toString();
        return nonce;
    }

获取两个整数中的整数


    public int getRandomInteger(int min, int max) {
        return secureRandom.nextInt(max - min) + min;
    }

获取长整型随机值

    public long getRandomLong() {
        return secureRandom.nextLong();    
    }

使用的时候可以用时间戳加随机数(最好大于8位)的形式来生成唯一的随机数。



2020 jeepxie.net webmaster#jeepxie.net
10 q. 0.009 s.
京ICP备10005923号