SQL注入绕开登录?过滤器+数据验证双保险!——Web应用安全实战(PART3下)

admin 2025-12-26 01:42:53 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文解析Web登录SQL注入风险与危害,提出过滤危险字符与验证输入类型的双重防护。重点展示Java过滤器代码实现,适配已上线系统快速部署,并建议新系统采用请求级验证防范URL编码绕过,构建全流程后端逻辑安全防线。 综合评分: 84 文章分类: WEB安全,漏洞分析,安全开发,解决方案


cover_image

SQL注入绕开登录?过滤器+数据验证双保险!——Web应用安全实战(PART 3 下)

原创

耶度

野猪与安全

2025年12月25日 10:01 广东

在上一篇「Web 应用安全实战(PART 3 上)」中,我们拆解了登录环节的“已解密的登录请求”漏洞,重点讲解了 HTTPS 加密和临时过渡方案,帮大家筑牢了登录数据传输的安全防线。除了数据传输,登录环节的后端验证逻辑同样暗藏风险,其中最致命的就是——SQL 注入。

今天第三篇(下),我们就聚焦登录环节的后端逻辑安全,深入拆解 SQL 注入这一黑客常用的攻击手段,从漏洞描述、核心风险,到解决方案和技术实现,给出全流程的防护指南。

已解密的登录请求——登录信息“裸奔”传输

中风险漏洞

  1. 漏洞描述:用户输入未过滤,构造 SQL 语句直接入侵

SQL 注入是 Web 应用中最常见且危害极大的漏洞之一,核心问题在于:后端程序没有对用户输入的登录信息进行合法性判断和过滤,直接将用户输入的内容拼接成SQL语句执行。

黑客利用这一漏洞,在登录界面的用户名或密码输入框中,输入特殊构造的SQL语句片段(比如“’ or 1=1 –”),就能篡改原本的登录验证SQL逻辑,绕过账号密码验证,直接以合法用户(甚至管理员)身份登录系统。

比如原本的登录验证SQL是“select * from user where username=’xxx’ and password=’xxx’”,黑客输入特殊语句后,可能被篡改为“select * from user where username=” or 1=1 –‘ and password=’xxx’”,由于“1=1”恒成立,直接查询出所有用户信息,实现登录。

安全级别:

高风险!无需知道正确账号密码,就能直接入侵系统,是黑客最常用的攻击手段之一。

2. 核心风险:数据库被操控,系统完全失控

SQL 注入的危害远不止绕开登录验证,黑客后续还能:

  • 查看数据库中的所有数据,包括用户信息、交易记录、核心业务数据等;
  • 修改数据库中的数据,比如篡改用户密码、交易金额等;
  • 删除数据库表和数据,导致系统功能瘫痪;
  • 通过数据库权限提升,获取服务器控制权,植入恶意代码。

3. 解决方案:多重防护,从输入到开发全流程管控

核心思路是“堵住用户输入的漏洞+规范开发流程”,具体方案如下:

  • 过滤危险字符:对用户输入的内容进行严格过滤,剔除 SQL 语句中的特殊字符(如单引号、分号、or、and、–、()等);
  • 验证输入类型:检查用户输入的字段类型是否符合预期(比如用户名应为字符串、用户 ID 应为整数),避免输入非法类型数据;
  • 屏蔽详细错误信息:避免向用户返回包含 SQL 语句、数据库结构的错误提示,防止黑客利用这些信息构造攻击语句;
  • 使用专业漏洞扫描工具:定期对 Web 应用进行扫描,及时发现潜在的 SQL 注入漏洞;
  • 规范开发流程:在开发全阶段实施代码安全检查,部署前进行安全测试,部署后定期用扫描工具和站点监视工具检测。

4. 技术实现:两种核心方案,适配不同项目阶段

(1)采用过滤器技术(适配已上线系统)

核心逻辑:通过自定义过滤器,对所有请求的参数进行扫描,若检测到危险字符,直接弹出提示并阻断请求。该方案侵入性小、代码量少、部署方便,适合已完成且正在运行的系统。

具体实现包括三个部分:过滤器类、辅助工具类和 web.xml 配置:

  1. 过滤器类 ParameterFilter.java:

/**&nbsp;* 参数过滤类,过滤普通表单&nbsp;*/public&nbsp;class&nbsp;ParameterFilter&nbsp;implements&nbsp;Filter&nbsp;{&nbsp;private&nbsp;Pattern scriptPattern;&nbsp;private&nbsp;Pattern sqlPattern;&nbsp;private&nbsp;Pattern letterPattern;&nbsp;private&nbsp;String&nbsp;notProtect&nbsp;=&nbsp;"";&nbsp;&nbsp;private&nbsp;String&nbsp;totalLetter&nbsp;=&nbsp;"";&nbsp;public&nbsp;void&nbsp;destroy()&nbsp;{&nbsp;}&nbsp;public&nbsp;void&nbsp;doFilter(ServletRequest request, ServletResponse response,&nbsp; &nbsp;FilterChain filtreChain)&nbsp;throws&nbsp;IOException, ServletException {&nbsp;&nbsp;HttpServletRequest&nbsp;req&nbsp;=&nbsp;(HttpServletRequest) request;&nbsp;&nbsp;String&nbsp;contentType&nbsp;=&nbsp;request.getContentType() ==&nbsp;null&nbsp;?&nbsp;""&nbsp;: request&nbsp; &nbsp; .getContentType();&nbsp;&nbsp;if&nbsp;(!contentType.startsWith("multipart/form-data")&nbsp; &nbsp; && !FilterUtils.isContainUrl(notProtect, FilterUtils&nbsp; &nbsp; &nbsp; .getFullUrlFromRequest(req))) {&nbsp; &nbsp;Enumeration&nbsp;params&nbsp;=&nbsp;req.getParameterNames();&nbsp; &nbsp;boolean&nbsp;isSecurity&nbsp;=&nbsp;true;&nbsp; &nbsp;while&nbsp;(null&nbsp;!= params && params.hasMoreElements()) {&nbsp; &nbsp;&nbsp;String&nbsp;para_name&nbsp;=&nbsp;(String) params.nextElement();&nbsp; &nbsp; String[] para_value =&nbsp;null;&nbsp; &nbsp; para_value = (String[]) req.getParameterValues(para_name);&nbsp; &nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0; i < para_value.length; i++) {&nbsp; &nbsp; &nbsp;String&nbsp;_para_value&nbsp;=&nbsp;para_value[i].toLowerCase();&nbsp; &nbsp; &nbsp;if&nbsp;(scriptPattern.matcher(_para_value).matches()&nbsp; &nbsp; &nbsp; &nbsp;|| sqlPattern.matcher(_para_value).matches()) {&nbsp; &nbsp; &nbsp; isSecurity =&nbsp;false;&nbsp; &nbsp; &nbsp;&nbsp;break;&nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;if&nbsp;(!isSecurity)&nbsp; &nbsp; &nbsp;break;&nbsp; &nbsp;}&nbsp; &nbsp;if&nbsp;(!isSecurity) {&nbsp; &nbsp; response.setContentType("text/html; charset=GBK");&nbsp; &nbsp; response.getWriter().write("<script language='javascript'>alert('输入有误,请不要包含"+totalLetter+"中的任何敏感字符!');history.go(-1);</script>");&nbsp; &nbsp;&nbsp;return;&nbsp; &nbsp;}&nbsp; }&nbsp; filtreChain.doFilter(request, response);&nbsp;}&nbsp;public&nbsp;void&nbsp;init(FilterConfig filterConfig)&nbsp;throws&nbsp;ServletException { &nbsp;&nbsp; letterPattern = Pattern.compile("[a-z]*");&nbsp;&nbsp;String&nbsp;scriptPara&nbsp;=&nbsp;filterConfig.getInitParameter("scriptRegx").toLowerCase(); &nbsp;&nbsp;&nbsp;String&nbsp;sqlPara&nbsp;=&nbsp;filterConfig.getInitParameter("sqlRegx").toLowerCase(); &nbsp;&nbsp; notProtect = filterConfig.getInitParameter("notProtect");&nbsp; scriptPattern = Pattern.compile(resultStr(scriptPara)); &nbsp;&nbsp; sqlPattern = Pattern.compile(resultStr(sqlPara)); &nbsp;&nbsp; totalLetter = scriptPara+"|"+sqlPara;&nbsp;&nbsp;int&nbsp;index&nbsp;=&nbsp;totalLetter.indexOf("'");&nbsp;&nbsp;if(index >&nbsp;0){&nbsp; &nbsp;totalLetter = totalLetter.substring(0, index)+"\\'"+totalLetter.substring(index+1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;public&nbsp;String&nbsp;resultStr(String oldStr)&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;String&nbsp;newStr&nbsp;=&nbsp;"";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(oldStr !=&nbsp;null&nbsp;&& !oldStr.equals("")) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String[] temp = oldStr.split("\\\\|");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(temp.length >&nbsp;0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0; i < temp.length; i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;String&nbsp;tempStr&nbsp;=&nbsp;"";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;boolean&nbsp;isLetter&nbsp;=&nbsp;false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(int&nbsp;j&nbsp;=&nbsp;0; j < temp[i].length(); j++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;String&nbsp;str&nbsp;=&nbsp;temp[i].substring(j, j +&nbsp;1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(letterPattern.matcher(str).matches()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tempStr = tempStr+&nbsp;"((\\\\%"+ parseAscii(str.toUpperCase()) +&nbsp;")|"&nbsp;+&nbsp;"(\\\\%"+ parseAscii(str)+&nbsp;")|("&nbsp;+ str +&nbsp;"))";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isLetter =&nbsp;true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(str.equals("("&nbsp;)|| str.equals(")"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; str =&nbsp;"\\\\"+str;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tempStr = tempStr +&nbsp;"((\\\\%"+ parseAscii(str) +&nbsp;")|("&nbsp;+ str+&nbsp;"))";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isLetter =&nbsp;false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(isLetter)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(newStr.equals("")) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newStr = newStr +&nbsp;".*(\\\\s+)("&nbsp;+ tempStr +&nbsp;")(\\\\s+).*";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newStr = newStr +&nbsp;"|.*(\\\\s+)("&nbsp;+ tempStr +&nbsp;")(\\\\s+).*";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(newStr.equals("")) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newStr = newStr +&nbsp;".*("&nbsp;+ tempStr +&nbsp;").*";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newStr = newStr +&nbsp;"|.*("&nbsp;+ tempStr +&nbsp;").*";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;newStr;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;private&nbsp;String&nbsp;toHexUtil(int&nbsp;n){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String rt="";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;switch(n){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;10:rt+="A";break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;11:rt+="B";break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;12:rt+="C";break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;13:rt+="D";break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;14:rt+="E";break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;15:rt+="F";break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rt+=n;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;rt;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;public&nbsp;String&nbsp;toHex(int&nbsp;n){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StringBuffer sb=new&nbsp;StringBuffer();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if(n/16==0){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;toHexUtil(n);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String t=toHex(n/16);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;int&nbsp;nn=n%16;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sb.append(t).append(toHexUtil(nn));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;sb.toString();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;public&nbsp;String&nbsp;parseAscii(String str){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StringBuffer sb=new&nbsp;StringBuffer();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;byte[] bs=str.getBytes();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for(int&nbsp;i=0;i<bs.length;i++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sb.append(toHex(bs[i]));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;sb.toString();&nbsp; &nbsp; &nbsp; &nbsp; }}
  1. 辅助工具类 FilterUtils.java:
public&nbsp;class&nbsp;FilterUtils&nbsp;{public&nbsp;static&nbsp;String&nbsp;getFullUrlFromRequest(HttpServletRequest&nbsp;httRequest) {String&nbsp;url = httRequest.getRequestURI();String&nbsp;queryString = httRequest.getQueryString();if&nbsp;(null&nbsp;!= queryString && !queryString.trim().equals("")) {            url = url +&nbsp;"?"&nbsp;+ queryString;        }return&nbsp;url;   }public&nbsp;static&nbsp;boolean&nbsp;isContainUrl(String&nbsp;urlList,&nbsp;String&nbsp;url) {boolean&nbsp;isExclude =&nbsp;false;if&nbsp;(null&nbsp;!= urlList && !urlList.trim().equals("")) {String[] resources = urlList.split(",");if&nbsp;(null&nbsp;!= resources) {for&nbsp;(int i =&nbsp;0; i < resources.length; i++) {if&nbsp;(null&nbsp;!= resources[i] && !resources[i].equals(""))if&nbsp;(url.indexOf(resources[i].trim()) >=&nbsp;0) {                          isExclude =&nbsp;true;break;                        }               }           }       }return&nbsp;isExclude; }}web.xml配置片段:
<filter>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<filter-name>SecurityFilter</filter-name>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<filter-class>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cn.com.victorysoft.devcenter.component.usrmgr.security.filter.ParameterFilter&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</filter-class>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<init-param>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<param-name>scriptRegx</param-name>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<param-value>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <![CDATA[<|>|=|"|and]]>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</param-value>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</init-param>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<init-param>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<param-name>sqlRegx</param-name>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<param-value><![CDATA['|;|or|--|(|)]]></param-value>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</init-param>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<init-param>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<param-name>notProtect</param-name>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<param-value>login.html,.upload</param-value>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</init-param>&nbsp; &nbsp; &nbsp; &nbsp; </filter>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<filter-mapping>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<filter-name>SecurityFilter</filter-name>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<url-pattern>*.jsp</url-pattern>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</filter-mapping>

(2)请求级数据验证(适配开发中系统)

核心逻辑:对每个登录请求(及其他用户输入请求),单独编写数据验证函数,验证输入数据的类型、长度,仅允许特定的特殊字符输入。

重要提示:

  • 黑客可能将敏感字符转化为 URL 编码(如<对应%3C)绕过过滤,因此验证时需同时对 URL 编码的敏感字符进行过滤;
  • 已上线系统优先采用过滤器方案(侵入性小、部署方便);开发中系统优先采用请求级验证方案(适配特殊业务需求,过滤更精准)。

安全攻击及防范手册

连载预告:登录环节收尾!下一篇聚焦前端交互安全

今天我们完成了“已解密的登录请求”和“SQL注入”两个漏洞的拆解,从数据传输到后端逻辑,为大家筑牢了登录环节的安全防线。这两个漏洞的高发,要么是忽视了传输加密,要么是开发时未规范处理用户输入,希望大家能对照项目及时自查整改。

下一篇(PART 4),我们将完成登录环节的安全漏洞拆解,聚焦前端交互层面的两个高频漏洞:跨站点脚本攻击(XSS)(注入恶意脚本窃取信息)和跨站点请求伪造(CSRF)(伪造用户请求执行恶意操作),并带来对应的防护指南。

你在项目中是否遇到过SQL注入相关的安全问题?或者对过滤器部署有疑问?欢迎在评论区留言讨论,我们将在后续文章中针对性解答!


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:野猪与安全 耶度《SQL注入绕开登录?过滤器+数据验证双保险!——Web应用安全实战(PART 3 下)》

评论:0   参与:  2