zoukankan      html  css  js  c++  java
  • sql注入、js注入、csrf漏洞修复

    以前没接触过网页安全方面的内容,正好这次碰巧客户有要求,学习了下,现将方案记录于此。

         Sql注入

         解决方案:

         服务器访问层的控制:

      1、在过滤器,针对后缀为jsp、html、htm的访问进行过滤拦截,判断请求参数中是否包含敏感字符

      2、在拦截其中,针对后缀为(.do )的Controller访问进行拦截,判断请求参数中是否包含敏感字符

      数据访问层的控制:    

      1、由于我们采用MyBaties,所以在写Sql时,尽量按#号传参,能有效防止SQL注入

         

          js注入

      解决方案:

      前端页面控制

      1、在输入框中添加js验证,具体可参考我随便里easyUI的一些正则表达式的写法。

      服务器访问控制

      1、在过滤器,针对后缀为jsp、html、htm的访问进行过滤拦截,判断请求参数中是否包含敏感字符  

      2、在拦截其中,针对后缀为(.do )的Controller访问进行拦截,判断请求参数中是否包含敏感字符

      csrf漏洞

      解决方案:

      服务器端控制

      1、对所有服务器请求进行拦截(通过过滤器、拦截器),判断请求中是否有crsftoken标记    

        a、如果没有则系统自动往seesion中添加csrftoken(就是个自动生成的guid)变量,允许继续访问

        b、如果请求中有csrftoken标记,则判断是否和服务器session中的csrftoken值相同  

          b-1、不同则将请求重置到错误页面(如果是ajax请求,则访问错误信息)

          b-2、相同则说明csrf验证通过,允许继续访问

      前台页面控制

      1、通过上面描述可知,只要是向服务器请求过一次页面,那么session中必定是包含csrftoken这个值,那么在服务端生成页面时要做的就是读取session中的csrftoken这个值,针对于所有服务器请求都添加上这个csrftoken参数。这些请求类型包括:表单提交、href超链接、ajax请求等等。

      注意:切忌在向服务器请求后,在浏览器的地址栏中能够看见你刚才提交的csrftoken值。

    代码实现 

         我们用的是SpringMVC,实现把三种漏洞的处理杂糅在一起了,下面直接上代码。但为了保密,所以代码可能掐头掐尾,希望能不影响大家阅读

      1、配置文件web.xml中配置 过滤器,用于对于jsp、htm、html等请求进行拦截

      

     <filter>
            <filter-name> validateFilter</filter-name>
            <filter-class>
                com.XXX.XX.XX.filter.ValidateFilter
            </filter-class>
        </filter>
        <filter-mapping>
            <filter-name>validateFilter</filter-name>
            <url-pattern>*.jsp</url-pattern>
            <url-pattern>*.htm</url-pattern>
            <url-pattern>*.html</url-pattern>
        </filter-mapping>
     </filter>
     

      2、spring-mvc.xml中配置 拦截器,用于对于.do的mvc请求进行拦截

      

     <mvc:interceptors>
            <bean class="com.XXX.XX.XX.interceptor.ValidateInterceptor" />
        </mvc:interceptors>

         3、拦截器、过滤器的实现代码

    @Controller
    public class ValidateFilter implements Filter {
        @Override
        public void destroy() {
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest,
                             ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            //验证请求参数是否包含敏感字符
            boolean isValidate = ValidateUtil.sensitiveKeywordJudge(servletRequest, servletResponse);
            if (isValidate)
                //验证是否存在CSRF漏洞
                isValidate = ValidateUtil.csrfTokenJudge(servletRequest, servletResponse);
            if(isValidate)
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }
    
    
    
    @Controller
    @Scope("prototype")
    public class ValidateInterceptor implements HandlerInterceptor {
        /**
         * 对传入请求进行拦截
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //验证请求参数是否包含敏感字符
            boolean allowPass=ValidateUtil.sensitiveKeywordJudge(request, response);
            if(allowPass)
                //验证是否存在CSRF漏洞
                allowPass=ValidateUtil.csrfTokenJudge(request,response);
            return allowPass;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            //资源释放
        }
    }
    
    
    
    
    public class ValidateUtil {
        /**
         * SQL注入敏感字符、关键字验证
         * 请求参数中不包含敏感字符,通过
         *
         * @param request  请求
         * @param response 响应
         */
        public final static boolean sensitiveKeywordJudge(ServletRequest request, ServletResponse response) throws ServletException, IOException {
            boolean notSensitiveKeyWord = true;
            //判定请求参数中是否包含敏感字符
            Pattern pattern = Pattern.compile(Contstants.SQL_SENSITIVE_KEY_WORDS);
            for (Object value : request.getParameterMap().values()) {
                String reqData = ((String[]) value)[0];
                Matcher match = pattern.matcher(reqData);
                if (match.find()) {
                    notSensitiveKeyWord = false;
                    break;
                }
            }
            //如果验证不通过,跳转到异常界面异常
            if (!notSensitiveKeyWord) {
                WriteResponseUtil.JumpToErrorPage((HttpServletRequest) request, (HttpServletResponse) response, Contstants.ContainSensitiveWord);
            }
            return notSensitiveKeyWord;
        }
    
        /**
         * CSRF TOKEN校验
         * @param request  请求
         * @param response 响应
         */
        public final static boolean csrfTokenJudge(ServletRequest request, ServletResponse response) throws ServletException {
            String requestUri = ((HttpServletRequest) request).getRequestURI();
            HttpServletRequest req = (HttpServletRequest) request;
            HttpSession s = req.getSession();
            // 从 session 中得到 csrftoken 属性
            String sToken = (String) s.getAttribute("csrftoken");
            if (sToken == null) {
                // 产生新的 token 放入 session 中
                sToken = UUID.randomUUID().toString();
                s.setAttribute("csrftoken", sToken);
                return true;
            }
            //跳转登陆页,错误页面时不进行校验
            if ( requestUri.equals("/") || requestUri.contains("loginController/mainPage.do") || requestUri.contains("loginController/login.do")||requestUri.contains("/login.jsp")||requestUri.contains("/error.jsp") ||requestUri.contains("/nopermission.jsp")) {
                return true;
            }
            // 从 HTTP 头中取得 csrftoken
            String xhrToken = req.getHeader("csrftoken");
            // 从请求参数中取得 csrftoken
            String pToken = req.getParameter("csrftoken");
            if (sToken != null && xhrToken != null && sToken.equals(xhrToken)) {
                return true;
            } else if (sToken != null && pToken != null && sToken.equals(pToken)) {
                return true;
            }
            WriteResponseUtil.JumpToErrorPage((HttpServletRequest) request, (HttpServletResponse) response, Contstants.ErrCSRFToken);
            return false;
        }
    }

      4、敏感字符,采用正则表达式:

    public static final  String SQL_SENSITIVE_KEY_WORDS="['"<>=%;|&]|-{2}|\\{2}";
    

      5、前端页面引入session变量

    <script type="text/javascript">
        var tokenSession="<%=request.getSession().getAttribute("csrftoken")%>"
        var token=tokenSession!=null?tokenSession.toString():"";
    </script>

      6、针对form元素进行后缀添加csrftoken

    function updateForms( ) {
        var forms = document.getElementsByTagName('form');
        for(i=0; i<forms.length; i++) {
            var tokenInput=$("form[name='"+forms[i].name+"']").children("[name='csrftoken']");
            if(tokenInput.length==0)
            {
                tokenInput =document.createElement("input");
                tokenInput.name = "csrftoken";
                tokenInput.value = token;
                tokenInput.type="hidden";
                forms[i].appendChild(tokenInput);
            }else{
                tokenInput.val(token);
            }
        }
        // 得到页面中所有的 form 元素
    //    var forms = document.getElementsByTagName('form');
    //    for(i=0; i<forms.length; i++) {
    //        var form=forms[i];
    //        var input=form.getElementsByName("csrftoken");
    //        if(input==null){
    //        // 动态生成 input 元素,加入到 form 之后
    //            input =document.createElement("input");
    //            input.name = "csrftoken";
    //            input.value = token;
    //            input.type="hidden";
    //        forms[i].appendChild(input);
    //        }
    //        else
    //        {
    //            input.setValue(token);
    //        }
    //    }
    }
    //为Html<a>标签的 href添加Token后缀
    //function updateTags() {
    //    var all = document.getElementsByTagName('a');
    //    var len = all.length;
    //
    //    // 遍历所有 a 元素
    //    for(var i=0; i<len; i++) {
    //        var e = all[i];
    //        updateTag(e, 'href', token);
    //    }
    //}
    //
    //function updateTag(element, attr, token) {
    //    var location = element.getAttribute(attr);
    //    if(location != null && location != "" ) {
    //        var fragmentIndex = location.indexOf('#');
    //        var fragment = null;
    //        if(fragmentIndex != -1){
    //
    //            //url 中含有只相当页的锚标记
    //            fragment = location.substring(fragmentIndex);
    //            location = location.substring(0,fragmentIndex);
    //        }
    //        var index = location.indexOf('?');
    //        if(index != -1) {
    //            //url 中已含有其他参数
    //            location = location + '&csrftoken=' + token;
    //        } else {
    //            //url 中没有其他参数
    //            location = location + '?csrftoken=' + token;
    //        }
    //        if(fragment != null){
    //            location += fragment;
    //        }
    //        element.setAttribute(attr, location);
    //    }
    //}

      配合的每个界面的初始化方法中要调用一下上面的js

    $(function () {
        updateForms();
    });

      注:其中注释的代码你也可以看看,根据自己需要调整。

      7、在前端ajax中请求参数后缀添加csrftoken,由于一些写法和差异,这边直接黏贴一个js以供参考了,具体根据自己的项目可以区别处理(只需要关注提交请求的相关代码段即可)

    $(function () {
        updateForms();
        loadData(null);
    })
    
    function loadData(url) {
        $('#TDataDictTable').datagrid({
            url: url,
            fit: true,
            pagination: true,
            fitColumns: true,
            rownumbers: true,
            sortName: 'itemName',
            sortOrder: 'desc',
            idField: 'id',
            loadMsg: "数据加载中,请稍候……",
            columns: [
                [
                    {field : 'id',title : '编号',checkbox:true
                    },
                    { field: 'systemId', title: '编号', hidden: true, sortable: true, align: 'left',  100
                    },
                    { field: 'itemName', title: '字典项名', sortable: true, align: 'left',  100
                    },
                    { field: 'colNameCn', title: '列中文名', sortable: true, align: 'left',  100
                    },
                    { field: 'colName', title: '列英文名', sortable: true, align: 'left',  100
                    },
                    { field: 'itemVal', title: '列值项', sortable: true, align: 'left',  100
                    },
                    { field: 'itemDesc', title: '描述', sortable: true, align: 'left',  200
                    },
                    { field: 'ext1', title: '扩展字段1', hidden: true, sortable: true, align: 'left',  200
                    },
                    { field: 'ext2', title: '扩展字段2', hidden: true, sortable: true, align: 'left',  200
                    },
                    { field: 'createDatetime', title: '记录生成日期', sortable: true, align: 'left',  100
                    },
                    { field: 'updateDatetime', title: '记录更新日期', sortable: true, align: 'left',  100
                    },
                    { field: 'operid', title: '操作员', sortable: true, align: 'left',  100
                    }
                ]
            ],
            onLoadError: function (r) {
                if (r.statusText == 'Forbidden') {
                    if (r.responseText != null && r.responseText != "") {
                        Showbo.Msg.alert(r.responseText);
                    }
                    else {
                        Showbo.Msg.alert('抱歉,您的身份验证已过期!');
                        window.top.location.href = projectPath + "loginController/login.do";
                    }
                }
            }
        });
    }
    
    
    function showDialog(rowDate, title) {
        var permissUrl = "?permissionCode=YWDATADICTADDCODE"
        if (rowDate != null) {
            permissUrl = "?permissionCode=YWDATADICTUPDATECODE"
        }
        var d = $('<div/>').dialog({
            href: projectPath + "view/vayw/systemmanager/datadict/addDataDict.jsp?csrftoken=" + token,
            modal: true,
            closable: false,
            title: title,
             370,
            height: 450,
            buttons: [
                {
                    text: '确定',
                    handler: function () {
                        if ($('#DataDictAddForm').form('validate')) {
                            $.ajax({
                                type: 'post',
                                dataType: 'json',
                                url: projectPath + 'TYwDataDictController/save.do' + permissUrl,
                                data: $('#DataDictAddForm').serialize(),
                                success: function (r) {
                                    if (r.success) {
                                        Showbo.Msg.alert(r.msg);
                                        d.dialog('close');
                                        if (rowDate == null)
                                            searchDataDict();
                                        else
                                            holdSearchDataDict();
                                    } else {
                                        Showbo.Msg.alert(r.msg);
                                    }
                                },
                                error: function (r) {
                                    if (r.statusText == 'Forbidden') {
                                        if (r.responseText != null && r.responseText != "") {
                                            Showbo.Msg.alert(r.responseText);
                                        }
                                        else {
                                            Showbo.Msg.alert('抱歉,您的身份验证已过期!');
                                            window.top.location.href = projectPath + "loginController/login.do";
                                        }
                                    }
                                }
                            });
                        }
                    }
                },
                {
                    text: '取消',
                    handler: function () {
                        d.dialog('close');
                    }
                }
            ],
            onLoad: function () {
                if (rowDate != null) {
                    $('#pid').val(rowDate.id);
                    $('#psystemId').val(rowDate.systemId);
                    $('#pitemName').val(rowDate.itemName);
                    $('#pcolNameCn').val(rowDate.colNameCn);
                    $('#pcolName').val(rowDate.colName);
                    $('#pitemVal').val(rowDate.itemVal);
                    $('#pitemDesc').val(rowDate.itemDesc);
                    $('#pext1').val(rowDate.ext1);
                    $('#pext2').val(rowDate.ext2);
                }
            },
            onLoadError: function (r) {
                if (r.statusText == 'Forbidden') {
                    if (r.responseText != null && r.responseText != "") {
                        d.dialog('close');
                        Showbo.Msg.alert(r.responseText);
    
                    }
                    else {
                        Showbo.Msg.alert('抱歉,您的身份验证已过期!');
                        window.top.location.href = projectPath + "loginController/login.do";
                    }
                }
            },
            onClose: function () {
                $(this).dialog('destroy');
            }
        });
    }
    //添加
    function addDataDict() {
        showDialog(null, "添加数据字典");
    }
    
    //修改
    function updateDataDict() {
        var rows = $('#TDataDictTable').datagrid('getChecked');
        if (rows.length == 0) {
            Showbo.Msg.alert('请先选中要修改的记录!');
            return;
        } else if (rows.length > 1) {
            Showbo.Msg.alert('一次只能对一条数据字典信息进行修改!');
            return;
        }
        $.ajax({
            type: 'post',
            dataType: 'json',
            url: projectPath + 'TYwDataDictController/findById.do?permissionCode=YWDATADICTUPDATECODE',
            data: {'id': rows[0].id, 'csrftoken': token},
            success: function (r) {
                if (r != null) {
                    showDialog(rows[0], "修改数据字典");
                } else {
                    Showbo.Msg.alert('数据字典信息不存在,无法完成修改操作!');
                }
            },
            error: function (r) {
                if (r.statusText == 'Forbidden') {
                    if (r.responseText != null && r.responseText != "") {
                        Showbo.Msg.alert(r.responseText);
                    }
                    else {
                        Showbo.Msg.alert('抱歉,您的身份验证已过期!');
                        window.top.location.href = projectPath + "loginController/login.do";
                    }
                }
            }
        });
    }
    
    //删除
    function deleteDataDict() {
        var delrow = $('#TDataDictTable').datagrid('getChecked');
        if (delrow.length == 0) {
            Showbo.Msg.alert('请先选中要删除的记录!');
            return;
        }
        var ids = '';
        for (var i = 0; i < delrow.length; i++) {
            if (i != delrow.length)
                ids += delrow[i].id + ",";
            else
                ids += delrow[i].id;
        }
        Showbo.Msg.confirm('请确认是否要删除您选择的记录?', function (b) {
            if (b == 'yes') {
                $.ajax({
                    type: 'post',
                    dataType: 'json',
                    url: projectPath + 'TYwDataDictController/delete.do?permissionCode=YWDATADICTDELCODE',
                    data: {'ids': ids, 'csrftoken': token},
                    success: function (r) {
                        if (r.success) {
                            Showbo.Msg.alert(r.msg);
                            $('#TDataDictTable').datagrid('clearSelections');
                            holdSearchDataDict();
                        } else
                            Showbo.Msg.alert(r.msg);
                    },
                    error: function (r) {
                        if (r.statusText == 'Forbidden') {
                            if (r.responseText != null && r.responseText != "") {
                                Showbo.Msg.alert(r.responseText);
                            }
                            else {
                                Showbo.Msg.alert('抱歉,您的身份验证已过期!');
                                window.top.location.href = projectPath + "loginController/login.do";
                            }
                        }
                    }
                });
            }
        });
    }
    
    //保持当前页刷新
    function holdSearchDataDict() {
        var dataDictTable = $('#TDataDictTable');
        if ($('#TDataDictForm').form('validate')) {
            dataDictTable.datagrid({
                url: projectPath + 'TYwDataDictController/findAll.do?permissionCode=YWDATADICTSEARCHCODE',
                queryParams: $('#TDataDictForm').serializeObject(),
                onLoadError: function (r) {
                    if (r.statusText == 'Forbidden') {
                        if (r.responseText != null && r.responseText != "") {
                            Showbo.Msg.alert(r.responseText);
                        }
                        else {
                            Showbo.Msg.alert('抱歉,您的身份验证已过期!');
                            window.top.location.href = projectPath + "loginController/login.do";
                        }
                    }
                }});
            dataDictTable.datagrid('clearChecked');
        } else {
            Showbo.Msg.alert('查询条件不能包含敏感字符!');
        }
    }
    
    //查询按钮
    function searchDataDict() {
        var dataDictTable = $('#TDataDictTable');
        if ($('#TDataDictForm').form('validate')) {
            dataDictTable.datagrid({pageNumber: 1,
                url: projectPath + 'TYwDataDictController/findAll.do?permissionCode=YWDATADICTSEARCHCODE',
                queryParams: $('#TDataDictForm').serializeObject(),
                onLoadError: function (r) {
                    if (r.statusText == 'Forbidden') {
                        if (r.responseText != null && r.responseText != "") {
                            Showbo.Msg.alert(r.responseText);
                        }
                        else {
                            Showbo.Msg.alert('抱歉,您的身份验证已过期!');
                            window.top.location.href = projectPath + "loginController/login.do";
                        }
                    }
                }});
            dataDictTable.datagrid('clearChecked');
        } else {
            Showbo.Msg.alert('查询条件不能包含敏感字符!');
        }
    }

      

      

  • 相关阅读:
    Qt应用如何发布
    关于在windows下部署发布QT程序的总结
    干净地发布QT程序
    解析 Qt 程序在Windows 下发布
    Qt 5.2.0 和 VS 2012集成
    Unable to find a qt build, to solve this problem specify a qt build
    运行python程序不显示cmd的方法
    py2exe使用方法
    python 类
    在Pygtk和Glade使用Gtkbuilder
  • 原文地址:https://www.cnblogs.com/SunDigital/p/4786263.html
Copyright © 2011-2022 走看看