常见web开发安全漏洞修复方案

web系统测试工具:APPScan

1.不充分账户封锁

(一) 安全问题描述

发送了两次合法的登录尝试,并且在其间发送了几次错误的登录尝试。最后一个响应与第一个响应相同。这表明存在未充分实施帐户封锁的情况,从而使登录页面可能受到蛮力攻击

解决方案

效果,当用户登录错误3次,则提醒30分钟后才可再次登录

        if(!checkLock(session, username)) {
            System.out.println("该账号已经被锁定");
            return "该账号已经被锁定";
        }
        if (username=="小一"&&password=="1234"){
            //登录成功
            System.out.println("登录成功");
            User user=new User();
            user.setUsername(username);
            user.setPassword(password);
            System.out.println("登录成功");
            cleanFailNum(request.getSession(),username);//清空该用户之前登录的错误信息
            return "登录成功";
        }else {
            addFailNum(session,username);//错误信息加一
            return "用户名或者密码错误";
        }

  /**
     * 校验用户登录失败次数
     * @param session
     * @param username
     * @return
     */
    public boolean checkLock(HttpSession session,String username) {
        Object o = session.getServletContext().getAttribute(username);
        if(o==null) {
            return true;
        }
        HashMap<String,Object> map  = (HashMap<String, Object>) o;
        int num  = (int) map.get("num");
        Date date = (Date) map.get("lastDate");
        long timeDifference = ((new Date().getTime()-date.getTime())/60/1000);
        if(num>=3&&timeDifference<30) {
            return false;
        }
        return true;
    }
    /**
     * 新增用户登录失败次数
     * @param session
     * @param username
     */
    public void addFailNum(HttpSession session, String username) {
        Object o = session.getServletContext().getAttribute(username);
        HashMap<String,Object> map = null;
        int num= 0;
        if(o==null) {
            map = new HashMap<String,Object>();
        }else {
            map  = (HashMap<String, Object>) o;
            num  = (int) map.get("num");
            Date date = (Date) map.get("lastDate");
            long timeDifference = ((new Date().getTime()-date.getTime())/60/1000);
            if(timeDifference>=30) {
                num=0;
            }
        }
        map.put("num", num+1);
        map.put("lastDate", new Date());
        session.getServletContext().setAttribute(username, map);
    }
    /**
     * 清理用户登录失败的记录
     * @param session
     * @param username
     */
    public void cleanFailNum(HttpSession session, String username) {
        session.getServletContext().removeAttribute(username);
    }

2.会话标识未更新

安全规范要求

COOKIE中的登陆前JSESSIONID与登陆后JESSIONID不能相同。(只有J2EE应用服务器为JESSIONID,其他应用服务器可能不同)

简单理解就是登录前和登录后的sessionId要更新

方式一:在登录页面操作

<%
    //登录之后更改会话标识符
    request.getSession().invalidate();//清空session
    Cookie cookie = request.getCookies()[0];//获取cookie
    cookie.setMaxAge(0);//s让cookie过期
%>

方式二:登录方法中头加入操作

session.invalidate();

3.跨站点请求伪造

描述:可能会窃取或操纵客户会话和 cookie ,它们可能用于模仿合法用户,从而使黑客能够以该用户身份查
看或变更用户记录以及执行事务,窃取用户权限进行非法操作。
解决方案:过滤器拦截所有请求。非本站点和内网请求全部过滤。
import org.apache.logging.log4j.core.config.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author lhl
 * @version 1.0
 * @date 2020/5/6 16:47
 * @description TODO 拦截跨站点请求伪造
 */
@Order(1)
@WebFilter(filterName = "CSRFFilter", urlPatterns = "/*")
public class CSRFFilter  implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
 System.out.println("==============CSRFFilter=================");
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        if (checkReferer(req, resp)) {
            // 拦截
            response.setContentType("text/html;charset=utf-8");
//            resp.sendRedirect("/login.jsp");
            throw new ServletException("非法请求!");
            // return;
        }
        // 放行
        chain.doFilter(req, resp);
    }
    private boolean checkReferer(HttpServletRequest request, HttpServletResponse response) {
        String referer = request.getHeader("referer");
        String serviceName = request.getServerName();

        if (null == referer) {
            return false;
        }
        if (referer != null && referer.matches("^(http|https)+://(" + serviceName + ")(.*)")) {
            // 本系统的访问 直接放行
            return false;
        }
        if (referer != null && referer
                .matches("^[(http)|(https)]+://(localhost|10\\.|172\\.|127\\.0\\.0\\.1)+(.*)")) {
            // 内网的访问 直接放行
            return false;
        }
        return true;
    }
    @Override
    public void destroy() {

    }
}

4.“Content-Security-Policy”头缺失或不安全

解决方案1

中间件为IIS,网站根目录下找到“web.cofig”文件,没有则新建该文件。复制以下代码,粘贴到web.cofig文件中(新建全部复制,已有复制system.webserver)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<system.webServer>
		<httpProtocol>
			<customHeaders>
				<add name="Content-Security-Policy" value="default-src 'self';" />
			</customHeaders>
		</httpProtocol>
	</system.webServer>
</configuration>

解决方案2

HTML前端解决方法:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'"/>

5.“X-Content-Type-Options”头缺失或不安全

解决方案1.

中间件为IIS,网站根目录下找到“web.cofig”文件,没有则新建该文件。复制以下代码,粘贴到web.cofig文件中(新建全部复制,已有复制system.webserver)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<system.webServer>
		<httpProtocol>
			<customHeaders>
				<add name="X-Content-Type-Options" value="nosniff"/>
			</customHeaders>
		</httpProtocol>
	</system.webServer>
</configuration>

 解决方案2.

HTML前端解决方法:

<meta http-equiv="X-Content-Type-Options" content="nosniff" />

6.“X-XSS-Protection”头缺失或不安全

解决方案1.

中间件为IIS,网站根目录下找到“web.cofig”文件,没有则新建该文件。复制以下代码,粘贴到web.cofig文件中(新建全部复制,已有复制system.webserver)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<system.webServer>
		<httpProtocol>
			<customHeaders>
				<add name="X-XSS-Protection" value="1;mode=block"/>
			</customHeaders>
		</httpProtocol>
	</system.webServer>
</configuration>

HTML前端解决方法:

<meta http-equiv="X-XSS-Protection" content="1; mode=block" />

检测到目标URL存在电子邮件地址模式

Spambot 搜寻因特网站点,开始查找电子邮件地址来构建发送自发电子邮件(垃圾邮件)的邮件列表。 
如果检测到含有一或多个电子邮件地址的响应,可供利用以发送垃圾邮件。 
而且,找到的电子邮件地址也可能是专用电子邮件地址,对于一般大众应是不可访问的。

解决方案

从 Web 站点中除去任何电子邮件地址,使恶意的用户无从利用。

 关于内部IP暴露漏洞的解决

项目扫描遇到“内部IP暴露”漏洞,关于该漏洞的含义大家自行百度。

考虑的解决方法就是限制IP直接访问项目本身。具体做法如下:

项目是部署在Tomcat中,直接通过修改Tomcat配置文件中的server.xml实现。

初始配置为:

<pre name="code" class="html"><Engine name="Catalina" defaultHost="localhost">  
    <Host name="localhost"  appBase="webapps/test1"  
            unpackWARs="true" autoDeploy="true"  
            xmlValidation="false" xmlNamespaceAware="false">  
    </Host>   
</Engine>  

修改为

    <Host name="项目实际域名"  appBase="webapps/test1"  
            unpackWARs="true" autoDeploy="true"  
            xmlValidation="false" xmlNamespaceAware="false">  
    </Host>   
</Engine>

defaultHost是默认的,随便写点都行,应该是在域名无法发生作用的时候访问的。

通过上述配置,就可以实现禁止IP直接访问项目。

若完善一些,可以再配置一个Host,将IP访问指向特定的页面进行说明。

 潜在文件上载

文件上传漏洞是指网络攻击者上传了一个可执行的文件到服务器上,当开发者没有对该文件进行合理的校验及处理的时候,很有可能让程序执行这个上传文件导致安全漏洞。大部分网站都会有文件上传的功能,例如头像、图片、视频等,这块的逻辑如果处理不当,很容易触发服务器漏洞

防御方法

防范文件上传漏洞常见的几种方法。

1、文件上传的目录设置为不可执行

2、判断文件类型

在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文件类型检查中,强烈推荐白名单方式,黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。

3、使用随机数改写文件名和文件路径

文件上传如果要执行代码,则需要用户能够访问到这个文件。在某些环境中,用户能上传,但不能访问。如果应用了随机数改写了文件名和路径,将极大地增加攻击的成本。再来就是像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击。

4、单独设置文件服务器的域名

由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、上传包含Javascript的XSS利用等问题将得到解决。

已解密的登录请求

【原因】
经过实验测试,认为是页面input 标签type="password" 导致的,
如果 改成type="text"是可以绕过漏洞扫描的,但是密码框的内容要自己隐藏,出现诸多业务bugs。

【解决】在原来的<input type="password" />上面加多一个

`<input id="fp" type="password" style="display:none;" autocomplete="off">
<input id="password" name="password" placeholder="请输入密码" type="password" autocomplete="off">

文件参数Shell命令注入

可能会在 Web 服务器上运行远程命令。这通常意味着完全破坏服务器及其内容

原因:未对用户输入正确执行危险字符清理

确保所访问的文件驻留在虚拟路径中并具有特定扩展名;除去用户输入中的特殊字符

跨站点脚本编制

XSS跨站脚本攻击:两种情况。一种通过外部输入然后直接在浏览器端触发,即反射型XSS;还有一种则是先把利用代码保存在数据库或文件中,当web程序读取利用代码并输出在页面上时触发漏洞,即存储型XSS。DOM型XSS是一种特殊的反射型XSS。

危害:前端页面能做的事它都能做。(不仅仅盗取cookie、修改页面等)

解决方案

(1) 特殊字符HTML实体转码。最好的过滤方式是在输出和二次调用的时候进行加HTML实体一类的转码,防止脚本注入。

(2) 标签事件属性黑名单。特殊字符容易被绕过,所以还得加标签事件得黑名单或者白名单,这里推荐使用白名单的方式,实现规则可以直接使用正则表达式来匹配,如果匹配到的事件不在白名单列表,就可以直接拦截,而不是过滤为空。

特殊字符XSS攻击

在过滤器中,Http所有请求参数,过滤,去除特殊字符对系统的影响;

(1)sql注入

(2)文件参数注入


    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("e-xpression\\\\((.*?)\\\\)\"", "");

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

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


        //防止sql语句字符注入
        String[] sqlStr = {"and", "exec", "execute", "insert", "select", "delete", "update", "count", "drop", "chr", "mid", "master", "truncate", "char", "declare", "sitename", "net user", "xp_cmdshell", "like", "and", "exec", "execute", "insert", "create", "drop", "table", "from", "grant", "use", "group_concat", "column_name", "information_schema.columns", "table_schema", "union", "where", "select", "delete", "update", "order", "by", "count", "chr", "mid", "master", "truncate", "char", "declare", "or"};
        for (int i = 0; i < sqlStr.length; i++) {
            value = value.replaceAll(sqlStr[i], "");
        }
        //文件参数注入
        String[]cmdParameters={
                "cmd.exe","/k","bin","sh",".sh","shell","sleep"
        };
        for (int i = 0; i < cmdParameters.length; i++) {
            value = value.replaceAll(cmdParameters[i], "");
        }
        return value;

    }

更多博客和源码请到微信公众号:源码plus   探索和领取。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值