WEB开发安全漏洞修复方案_第1页
WEB开发安全漏洞修复方案_第2页
WEB开发安全漏洞修复方案_第3页
WEB开发安全漏洞修复方案_第4页
WEB开发安全漏洞修复方案_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

安全规范密级:保密WEB开发安全漏洞修复方案(V1.0)文档编号:文档名称:WEB开发安全漏洞修复方案编写:审核:批准:批准日期:技术研究部

文档修订记录编号版本号修订内容简述修订日期作者审核1V1.0初稿2012-7678910111213141516

TOC\o"1-6"\h\z\u(V1.0) 11.1 背景 11.2 FSDP安全漏洞清单 11.3 安全漏洞修复方案 11.3.1 会话标识未更新 11.3.2 登录错误消息凭证枚举 21.3.3 不充分帐户封锁 21.3.4 跨站点脚本编制 31.3.5 已解密的登录请求 61.3.6 跨站点脚本编制 91.3.7 通过框架钓鱼 131.3.8 链接注入(便于跨站请求伪造) 181.3.9 应用程序错误 251.3.10 SQL注入 291.3.11 发现数据库错误模式 381.3.12 启用了不安全的HTTP方法 481.3.13 发现电子邮件地址模式 501.3.14 HTML注释敏感信息泄露 511.3.15 发现内部IP泄露模式 521.3.16 主机允许从任何域进行flash访问 531.3.17 主机应用软件漏洞修复 531.3.18 目录列表 541.3.19 跨站点请求伪造 551.1 需要注意的问题 56背景随着移动公司对信息安全的进一步加强,要求我们部署的系统必须满足安全扫描要求。本文档描述了安徽移动对FSDP安全扫描的漏洞的解决方案,并作为WEB开发的安全编程规范。FSDP安全漏洞清单见《WEB开发安全漏洞清单.xlsx》安全漏洞修复方案会话标识未更新URL00/loginAction.do安全问题描述根据WASC:“会话固定”是一种攻击技术,会强制用户的会话标识变成显式值。固定会话标识值的技术有许多种,会随着目标Web站点的功能而不同。从利用“跨站点脚本编制”到向Web站点密集发出先前生成的HTTP请求,都在这些技术范围内。用户的会话标识固定之后,攻击者会等待用户登录,然后利用预定义的会话标识值来假定用户的联机身份。攻击方法登录过程前后会话标识的比较,显示它们并未更新,这表示有可能伪装用户。初步得知会话标识值后,远程攻击者有可能得以充当已登录的合法用户。 任何时候,只要一名用户与应用程序的交互状态由匿名转变为确认,应用程序就应该发布一个新的会话令牌。这不仅适用于用户成功登录的情况,而且适用于匿名用户首次提交个人或其他敏感信息时。安全规范要求COOKIE中的登陆前JSESSIONID与登陆后JESSIONID不能相同。(只有J2EE应用服务器为JESSIONID,其他应用服务器可能不同)解决方案将如下代码加入到登陆页面(login.jsp)的最后行:<%

request.getSession().invalidate();//清空session

Cookiecookie=request.getCookies()[0];//获取cookie

cookie.setMaxAge(0);//让cookie过期

%>登录错误消息凭证枚举URL00/loginAction.do安全问题描述当试图利用不正确的凭证来登录时,当用户输入无效的用户名和无效的密码时,应用程序会分别生成不同的错误消息。通过利用该行为,攻击者可以通过反复试验(蛮力攻击技术)来发现应用程序的有效用户名,再继续尝试发现相关联的密码。这样会得到有效用户名和密码的枚举,攻击者可以用来访问帐户。攻击方法修改00/loginAction.do的HTTP报文头:将参数“optrid”的值设置为“test123WithSomeChars”,除去cookie“JSESSIONID”,除去HTTP头“Cookie=JSESSIONID”。安全规范要求对每个错误的登录尝试发出相同的错误消息,不管是哪个字段发生错误,特别是用户名或密码字段错误。解决方案LoginImpl.java类中getLoginInfo方法,涉及到登录错误提示的都改成:“您输入的用户名或密码不正确!”。

登录超过3次数的改成:“您尝试登陆失败超过"+Constans.LOGIN_ERROR_TIMES+"次,请30分钟后再登陆!”。

不充分帐户封锁URL00/loginAction.do安全问题描述发送了两次合法的登录尝试,并且在其间发送了几次错误的登录尝试。最后一个响应与第一个响应相同。这表明存在未充分实施帐户封锁的情况,从而使登录页面可能受到蛮力攻击。(即使第一个响应不是成功的登录页面,也是如此。)攻击方法修改00/loginAction.do的HTTP报文头:除去cookie“JSESSIONID”,除去HTTP头“Cookie=JSESSIONID”。安全规范要求多次登录尝试失败后实施帐户封锁解决方案LoginImp.java中的getLoginInfo方法,修订如下代码片段://判断登陆失败次数 if(!checkLoginError(logininfo)){ ret.setRetCode("0003"); ret.setRetDesc("您尝试登陆失败超过"+Constans.LOGIN_ERROR_TIMES+"次,请"+Constans.LOGIN_ERROR_LOCK_SECOND+"分钟后再登录!"); returnret; }//增加验证登陆错误次数代码 addLoginErrorRec(logininfo);跨站点脚本编制URL00/callAction.do00/loginAction.do安全问题描述可能会窃取或操纵客户会话和cookie,它们可能用于模仿合法用户,从而使黑客能够以该用户身份查看或变更用户记录以及执行事务。攻击方法Web站点中所包含的脚本直接将用户在HTML页面中的输入(通常是参数值)返回,而不预先加以清理。如果脚本在响应页面中返回由JavaScript代码组成的输入,浏览器便可以执行此输入。因此,有可能形成指向站点的若干链接,且其中一个参数包含恶意的JavaScript代码。该代码将在站点上下文中(由用户浏览器)执行,这使得该代码有权访问用户在该站点中具有访问权的cookie,以及站点中其他可通过用户浏览器访问的窗口。攻击依照下列方式继续进行:攻击者诱惑合法用户单击攻击者生成的链接。用户单击该链接时,便会生成对于Web站点的请求,其中的参数值含有恶意的JavaScript代码。如果Web站点将这个参数值嵌入在响应的HTML页面中(这正是站点问题的本质所在),恶意代码便会在用户浏览器中运行。安全规范要求FSDP框架中在传递参数时有两个主要参数classes与common,一个指定要调用的service,一个是调用service中的方法,如果service或方法不存在,就会跳转到错误信息显示,并将详细的错误信息显示出来,如:callAction.do?method=call&nextPage=/oa/task/task_querylayout.jsp&classes=taskClientImpl&common=getInfoQueryDate这个URL,如果我们将URL修改一下,变成如下:

callAction.do?method=call&nextPage=/oa/task/task_querylayout.jsp&classes=taskClientImpl<script>alert(123)</script>&common=getInfoQueryDate,通过这个URL执行时会提示service不存在,并跳转到错误页面,同时会弹出123信息的提示窗口,同时如果我们修改common参数也能达到这种效果

解决方案web.xml增加如下配置:

<!--可能存在的跨域代码字符串,用逗号分开-->

<context-param>

<param-name>CROSS_DOMAIN_STR</param-name>

<param-value><,>,%3C,%3E</param-value>

</context-param>

Constans.java类增加如下变量:

/**

*跨域特殊字符判断

*/

publicstaticList<String>CROSS_DOMAIN_STR=newArrayList<String>();

FriendOneServlet.java类增加initSafetyConf安全初始化配置方法

privatevoidinitSafetyConf(){

Constans.CROSS_DOMAIN_STR.clear();

StringcrossDomainStr=getServletContext().getInitParameter("CROSS_DOMAIN_STR");

String[]crossDomainAry=crossDomainStr.split(",");

for(Strings:crossDomainAry){

Constans.CROSS_DOMAIN_STR.add(s.trim());

}

Constans.LOGIN_ERROR_TIMES=getServletContext().getInitParameter("LOGIN_ERROR_TIMES");

Constans.LOGIN_ERROR_LOCK_SECOND=getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND");

(Constans.CROSS_DOMAIN_STR);

("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES);

("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR_LOCK_SECOND);

}

在init方法中直接调用

在ActionFilter.java类中增加checkCrossDomain跨域特殊字符串检查,并在doFilter中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面

修改error.jsp,此处是用于处理返回的错误信息

目前是通过<html-el:errors/>标签方式加载错误信息,此处可根据输入的条件来进行错误注入,执行js代码,修改该当如下:

一、将此错误标签通过textarea进行包装,错误信息是以文本方式显示,无法执行,如下:

<textareastyle="height:100%;width:95%;color:red"readonly=true><html-el:errors/></textarea>

同时修改BaseWebAction.java类的processError方法,将sb.append(ste[i]).append("<br>");这段代码改为sb.append(ste[i]).append("\n");

二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系管理员检查!”启用了不安全的HTTP方法<security-constraint>

<web-resource-collection>

<url-pattern>/*</url-pattern>

<http-method>PUT</http-method>

<http-method>DELETE</http-method>

<http-method>HEAD</http-method>

<http-method>OPTIONS</http-method>

<http-method>TRACE</http-method>

<http-method>SEARCH</http-method>

<http-method>COPY</http-method>

<http-method>MOVE</http-method>

<http-method>PROPFIND</http-method>

<http-method>PROPPATCH</http-method>

<http-method>MKCOL</http-method>

<http-method>LOCK</http-method>

<http-method>UNLOCK</http-method>

</web-resource-collection>

<auth-constraint>

</auth-constraint>

</security-constraint>

<login-config>

<auth-method>BASIC</auth-method>

</login-config>

已解密的登录请求URL00/loginAction.do安全问题描述用户登录密码为明文攻击方法可通过http报文截取登录用户密码安全规范要求发送敏感信息时,始终使用SSL和HTTPPOST方法解决方案修改server.xml

<Connectorprotocol="org.apache.coyote.http11.Http11NioProtocol"

port="8443"minSpareThreads="5"maxSpareThreads="75"

enableLookups="true"disableUploadTimeout="true"

acceptCount="100"

maxThreads="200"

scheme="https"secure="true"SSLEnabled="true"

clientAuth="false"sslProtocol="TLS"

keystoreFile="D:/apache-tomcat-6.0.18/server.keystore"

keystorePass="friendone"/>

标红的地方注意,要与附件中server.keystore存放的位置一致标蓝的8443要注意,外网的一律全用443端口,BOSS网系统还是全用8443端口。修改web.xml,在welcome-file-list后面增加如下配置

<login-config>

<!--AuthorizationsettingforSSL-->

<auth-method>CLIENT-CERT</auth-method>

<realm-name>ClientCertUsers-onlyArea</realm-name>

<auth-method>BASIC</auth-method>

</login-config>

<security-constraint>

<!--AuthorizationsettingforSSL-->

<web-resource-collection>

<web-resource-name>SSL</web-resource-name>/*/oa/login.jsp为应用登录URL,此为公司OA则为此串*/

<url-pattern>/oa/login.jsp</url-pattern>

</web-resource-collection>

<user-data-constraint>

<transport-guarantee>CONFIDENTIAL</transport-guarantee>

</user-data-constraint>

</security-constraint><!--禁止不安全的http方法-->

<security-constraint>

<web-resource-collection>

<web-resource-name>fortune</web-resource-name>

<url-pattern>/*</url-pattern>

<http-method>PUT</http-method>

<http-method>DELETE</http-method>

<http-method>HEAD</http-method>

<http-method>OPTIONS</http-method>

<http-method>TRACE</http-method>

</web-resource-collection>

<auth-constraint></auth-constraint>

</security-constraint>增加初始化变量: <context-param> <param-name>HTTP_URI</param-name> <param-value>8080</param-value> </context-param> 此为从https转到http时的跳转值,为应用部署服务器IP地址为端口LoginAction.java修改如下:Login方法修改如下:Stringrequesturl=request.getRequestURL().toString();requesturl=requesturl.substring(requesturl.indexOf("//")+2);requesturl=requesturl.substring(0,requesturl.indexOf(":"));response.sendRedirect("http://"+requesturl+":"+Constans.HTTP_URI+request.getContextPath()+"/loginAction.do?method=flogin&sessionid="+session.getId()); returnnull;// clearTempFile(); //returnnewActionForward("/"+Constans.PROJECT_NAME+"/frames/indexFrame.jsp");增加以下方法:publicActionForwardflogin(ActionMappingmapping,ActionFormform,HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ try{ Stringvalue=request.getParameter("sessionid"); HashMapsessions=(HashMap)request.getSession().getServletContext().getAttribute("sessions"); HttpSessionsession=(HttpSession)sessions.get(value); if(session!=null){ HttpSessionnsession=request.getSession(); nsession.setAttribute(Constans.LOGIN_USER,session.getAttribute(Constans.LOGIN_USER)); sessions.put(value,nsession); session=null; } returnnewActionForward("/"+Constans.PROJECT_NAME+"/frames/indexFrame.jsp"); }catch(Exceptione){ logger.error("LoginActionExceptionError:"+e.toString()); throwe; } }修改LoginAction.java类的systemLogout方法:Stringrequesturl=request.getRequestURL().toString();requesturl=requesturl.substring(requesturl.indexOf("//")+2); requesturl=requesturl.substring(0,requesturl.indexOf(":")); response.sendRedirect("http://"+requesturl+":"+Constans.HTTP_URI+request.getContextPath()+LOGINPAGE); returnnull;// returnnewActionForward(LOGINPAGE);跨站点脚本编制URL00/callAction.do00/loginAction.do安全问题描述“跨站点脚本编制”攻击是一种隐私违例,可让攻击者获取合法用户的凭证,并在与特定Web站点交互时假冒这位用户。这个攻击立足于下列事实:Web站点中所包含的脚本直接将用户在HTML页面中的输入(通常是参数值)返回,而不预先加以清理。如果脚本在响应页面中返回由JavaScript代码组成的输入,浏览器便可以执行此输入。因此,有可能形成指向站点的若干链接,且其中一个参数包含恶意的JavaScript代码。该代码将在站点上下文中(由用户浏览器)执行,这使得该代码有权访问用户在该站点中具有访问权的cookie,以及站点中其他可通过用户浏览器访问的窗口。攻击依照下列方式继续进行:攻击者诱惑合法用户单击攻击者生成的链接。用户单击该链接时,便会生成对于Web站点的请求,其中的参数值含有恶意的JavaScript代码。如果Web站点将这个参数值嵌入在响应的HTML页面中(这正是站点问题的本质所在),恶意代码便会在用户浏览器中运行。攻击方法A.在响应页面中,返回发送给CGI脚本的参数值,嵌入在HTML中。例如:[请求]GET/cgi-bin/script.pl?name=JSmithHTTP/1.0[响应]HTTP/1.1200OKServer:SomeServerDate:Sun,01Jan200200:31:19GMTContent-Type:text/htmlAccept-Ranges:bytesContent-Length:27<HTML>HelloJSmith</HTML>B.在HTML参数值上下文中,返回发送给CGI脚本的参数值。例如:[请求]GET/cgi-bin/script.pl?name=JSmithHTTP/1.0[响应]HTTP/1.1200OKServer:SomeServerDate:Sun,01Jan200200:31:19GMTContent-Type:text/htmlAccept-Ranges:bytesContent-Length:254<HTML>Pleasefillinyourzipcode:<FORMMETHOD=GETACTION="/cgi-bin/script.pl"><INPUTTYPE=textNAME="name"value="JSmith"><br><INPUTTYPE=textNAME="zip"value="Enterzipcodehere"><br><INPUTTYPE=submitvalue="Submit"></FORM></HTML>安全规范要求通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划外的任务,例如:启动任意SQL查询、嵌入将在客户端执行的Javascript代码、运行各种操作系统命令,等等。建议过滤出所有以下字符:[1]|(竖线符号)[2]&(&符号)[3];(分号)[4]$(美元符号)[5]%(百分比符号)[6]@(at符号)[7]'(单引号)[8]"(引号)[9]\'(反斜杠转义单引号)[10]\"(反斜杠转义引号)[11]<>(尖括号)[12]()(括号)[13]+(加号)[14]CR(回车符,ASCII0x0d)[15]LF(换行,ASCII0x0a)[16],(逗号)[17]\(反斜杠)解决方案LoginImpl.java类中的getLoginInfo方法,将之前的操作员工号与密码拼接方式改成SQL变量绑定方式StringBuffersqlbuf=newStringBuffer();sqlbuf.append("SELECT.orgcode,A.userid,A.username,A.password,A.validate,A.usertype,C.orgname,C.norgcode,C.orgtype,");sqlbuf.append("now()ASlogindate,sp_genseqfunc('S','D')ASsessionid,");sqlbuf.append("(SELECTGROUP_CONCAT(B.datatype)FROMtb_userdatarelBWHEREB.userid=?)ASdatatypes,PASSWORD(?)=A.passwordASpwdiscorrect");sqlbuf.append("FROMtb_userA,tb_organizationC");sqlbuf.append("WHEREA.userid=?ANDA.effdate<=CURDATE()ANDA.expdate>=CURDATE()ANDC.orgcode=A.orgcode");web.xml增加如下配置:<!--可能存在的跨域代码字符串,用逗号分开--><context-param><param-name>CROSS_DOMAIN_STR</param-name><param-value><,>,%3C,%3E</param-value></context-param><context-param> <param-name>GET_CROSS_DOMAIN_STR</param-name><param-value><,>,",',%,;,(,),&,+,HTTP,http,%0a</param-value></context-param>Constans.java类增加如下变量:/***跨域特殊字符判断*/publicstaticList<String>CROSS_DOMAIN_STR=newArrayList<String>();publicstaticList<String>GET_CROSS_DOMAIN_STR=newArrayList<String>();FriendOneServlet.java类增加initSafetyConf安全初始化配置方法privatevoidinitSafetyConf(){Constans.CROSS_DOMAIN_STR.clear();StringcrossDomainStr=getServletContext().getInitParameter("CROSS_DOMAIN_STR");String[]crossDomainAry=crossDomainStr.split(",");for(Strings:crossDomainAry){Constans.CROSS_DOMAIN_STR.add(s.trim());}crossDomainStr=getServletContext().getInitParameter("GET_CROSS_DOMAIN_STR");crossDomainAry=crossDomainStr.split(",");for(Strings:crossDomainAry){Constans.GET_CROSS_DOMAIN_STR.add(s.trim());}Constans.LOGIN_ERROR_TIMES=getServletContext().getInitParameter("LOGIN_ERROR_TIMES");Constans.LOGIN_ERROR_LOCK_SECOND=getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND");Constans.HTTP_URI=getServletContext().getInitParameter("HTTP_URI");(Constans.CROSS_DOMAIN_STR);("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES);("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR_LOCK_SECOND);("HTTP_URI="+Constans.HTTP_URI);}在init方法中直接调用在ActionFilter.java类中增加checkCrossDomain跨域特殊字符串检查,并在doFilter中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面修改error.jsp,此处是用于处理返回的错误信息目前是通过<html-el:errors/>标签方式加载错误信息,此处可根据输入的条件来进行错误注入,执行js代码,修改该当如下:一、将此错误标签通过textarea进行包装,错误信息是以文本方式显示,无法执行,如下:<textareastyle="height:100%;width:95%;color:red"readonly=true><html-el:errors/></textarea>同时修改BaseWebAction.java类的processError方法,将sb.append(ste[i]).append("<br>");这段代码改为sb.append(ste[i]).append("\n");二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系管理员检查!”通过框架钓鱼URL00/callAction.do安全问题描述网络钓鱼是一个通称,代表试图欺骗用户交出私人信息,以便电子欺骗身份。攻击者有可能注入frame或iframe标记,其中含有类似受攻击之网站的恶意属性。不小心的用户有可能浏览它,但并不知道他正在离开原始网站,冲浪到恶意的网站。之后,攻击者便可以诱惑用户重新登录,然后获取他的登录凭证。攻击方法伪造的网站嵌入在原始网站中,这个情况对攻击者有帮助,因为他的网络钓鱼企图会披上更可信赖的外表。利用的样本:如果参数值未经适当清理便反映在响应中,那么下列请求:http://[SERVER]/script.aspx?parameter=<framename="evil"src="">会使响应含有通往这个邪恶站点的框架。安全规范要求若干问题的补救方法在于对用户输入进行清理。通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划外的任务,例如:启动任意SQL查询、嵌入将在客户端执行的Javascript代码、运行各种操作系统命令,等等。建议过滤出所有以下字符:[1]|(竖线符号)[2]&(&符号)[3];(分号)[4]$(美元符号)[5]%(百分比符号)[6]@(at符号)[7]'(单引号)[8]"(引号)[9]\'(反斜杠转义单引号)[10]\"(反斜杠转义引号)2012-7-416:57:34154/187[11]<>(尖括号)[12]()(括号)[13]+(加号)[14]CR(回车符,ASCII0x0d)[15]LF(换行,ASCII0x0a)[16],(逗号)[17]\(反斜杠)以下部分描述各种问题、问题的修订建议以及可能触发这些问题的危险字符:SQL注入和SQL盲注:A.确保用户输入的值和类型(如Integer、Date等)有效,且符合应用程序预期。B.利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。当使用存储过程时,请利用ADO命令对象来实施它们,以强化变量类型。C.清理输入以排除上下文更改符号,例如:[1]'(单引号)[2]"(引号)[3]\'(反斜线转义单引号)[4]\"(反斜杠转义引号)[5])(结束括号)[6];(分号)跨站点脚本编制:A.清理用户输入,并过滤出JavaScript代码。我们建议您过滤下列字符:[1]<>(尖括号)[2]"(引号)[3]'(单引号)[4]%(百分比符号)[5];(分号)[6]()(括号)[7]&(&符号)[8]+(加号)B.如果要修订<%00script>变体,请参阅MS文章821349C.对于UTF-7攻击:[-]可能的话,建议您施行特定字符集编码(使用'Content-Type'头或<meta>标记)。HTTP响应分割:清理用户输入(至少是稍后嵌入在HTTP响应中的输入)。请确保输入未包含恶意的字符,例如:[1]CR(回车符,ASCII0x0d)[2]LF(换行,ASCII0x0a)远程命令执行:清理输入以排除对执行操作系统命令有意义的符号,例如:[1]|(竖线符号)[2]&(&符号)[3];(分号)执行shell命令:A.绝不将未检查的用户输入传递给eval()、open()、sysopen()、system()之类的Perl命令。B.确保输入未包含恶意的字符,例如:[1]$(美元符号)[2]%(百分比符号)[3]@(at符号)XPath注入:清理输入以排除上下文更改符号,例如:[1]'(单引号)[2]"(引号)等LDAP注入:A.使用正面验证。字母数字过滤(A..Z,a..z,0..9)适合大部分LDAP查询。B.应该过滤出或进行转义的特殊LDAP字符:2012-7-416:57:34155/187[1]在字符串开头的空格或“#”字符[2]在字符串结尾的空格字符[3],(逗号)[4]+(加号)[5]"(引号)[6]\(反斜杠)[7]<>(尖括号)[8];(分号)[9]()(括号)MX注入:应该过滤出特殊MX字符:[1]CR(回车符,ASCII0x0d)[2]LF(换行,ASCII0x0a)记录伪造:应该过滤出特殊记录字符:[1]CR(回车符,ASCII0x0d)[2]LF(换行,ASCII0x0a)[3]BS(退格,ASCII0x08)ORM注入:A.确保用户输入的值和类型(如Integer、Date等)有效,且符合应用程序预期。B.利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。C.使用参数化查询APID.清理输入以排除上下文更改符号,例如:(*):[1]'(单引号)[2]"(引号)[3]\'(反斜线转义单引号)[4]\"(反斜杠转义引号)[5])(结束括号)[6];(分号)(*)这适用于SQL。高级查询语言可能需要不同的清理机制。解决方案LoginImpl.java类中的getLoginInfo方法,将之前的操作员工号与密码拼接方式改成SQL变量绑定方式StringBuffersqlbuf=newStringBuffer();sqlbuf.append("SELECT.orgcode,A.userid,A.username,A.password,A.validate,A.usertype,C.orgname,C.norgcode,C.orgtype,");sqlbuf.append("now()ASlogindate,sp_genseqfunc('S','D')ASsessionid,");sqlbuf.append("(SELECTGROUP_CONCAT(B.datatype)FROMtb_userdatarelBWHEREB.userid=?)ASdatatypes,PASSWORD(?)=A.passwordASpwdiscorrect");sqlbuf.append("FROMtb_userA,tb_organizationC");sqlbuf.append("WHEREA.userid=?ANDA.effdate<=CURDATE()ANDA.expdate>=CURDATE()ANDC.orgcode=A.orgcode");web.xml增加如下配置:<!--可能存在的跨域代码字符串,用逗号分开--><context-param><param-name>CROSS_DOMAIN_STR</param-name><param-value><,>,%3C,%3E</param-value></context-param>Constans.java类增加如下变量:/***跨域特殊字符判断*/publicstaticList<String>CROSS_DOMAIN_STR=newArrayList<String>();FriendOneServlet.java类增加initSafetyConf安全初始化配置方法privatevoidinitSafetyConf(){Constans.CROSS_DOMAIN_STR.clear();StringcrossDomainStr=getServletContext().getInitParameter("CROSS_DOMAIN_STR");String[]crossDomainAry=crossDomainStr.split(",");for(Strings:crossDomainAry){Constans.CROSS_DOMAIN_STR.add(s.trim());}Constans.LOGIN_ERROR_TIMES=getServletContext().getInitParameter("LOGIN_ERROR_TIMES");Constans.LOGIN_ERROR_LOCK_SECOND=getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND");(Constans.CROSS_DOMAIN_STR);("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES);("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR_LOCK_SECOND);}在init方法中直接调用在ActionFilter.java类中增加checkCrossDomain跨域特殊字符串检查,并在doFilter中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面修改error.jsp,此处是用于处理返回的错误信息目前是通过<html-el:errors/>标签方式加载错误信息,此处可根据输入的条件来进行错误注入,执行js代码,修改该当如下:一、将此错误标签通过textarea进行包装,错误信息是以文本方式显示,无法执行,如下:<textareastyle="height:100%;width:95%;color:red"readonly=true><html-el:errors/></textarea>同时修改BaseWebAction.java类的processError方法,将sb.append(ste[i]).append("<br>");这段代码改为sb.append(ste[i]).append("\n");二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系管理员检查!”链接注入(便于跨站请求伪造)URL00/callAction.do安全问题描述可能会劝说初级用户提供诸如用户名、密码、信用卡号、社会保险号等敏感信息可能会窃取或操纵客户会话和cookie,它们可能用于模仿合法用户,从而使黑客能够以该用户身份查看或变更用户记录以及执行事务可能会在Web服务器上上载、修改或删除Web页面、脚本和文件攻击方法“链接注入”是修改站点内容的行为,其方式为将外部站点的URL嵌入其中,或将有易受攻击的站点中的脚本的URL嵌入其中。将URL嵌入易受攻击的站点中,攻击者便能够以它为平台来启动对其他站点的攻击,以及攻击这个易受攻击的站点本身。在这些可能的攻击中,有些需要用户在攻击期间登录站点。攻击者从这一易受攻击的站点本身启动这些攻击,成功的机会比较大,因为用户登录的可能性更大。“链接注入”漏洞是用户输入清理不充分的结果,清理结果会在稍后的站点响应中返回给用户。攻击者能够将危险字符注入响应中,便能够嵌入URL及其他可能的内容修改。以下是“链接注入”的示例(我们假设“”站点有一个用来问候用户的参数,称为“name”)。下列请求:HTTP:///greet.asp?name=JohnSmith会生成下列响应:<HTML><BODY>Hello,JohnSmith.</BODY></HTML>然而,恶意的用户可以发送下列请求:HTTP:///greet.asp?name=<IMGSRC="http://www.ANY-SITE.com/ANYSCRIPT.asp">这会返回下列响应:<HTML><BODY>Hello,<IMGSRC="http://www.ANY-SITE.com/ANY-SCRIPT.asp">.</BODY></HTML>2012-7-416:57:34149/187如该示例所示,这有可能导致用户浏览器向几乎是攻击者所期待的任何站点发出自动请求。因此,他可能利用这个“链接注入”漏洞来启动若干类型的攻击:跨站点伪造请求:攻击者可以让用户的浏览器向用户目前登录的站点发送请求,以及执行用户并不想执行的操作。这些操作可能包括从站点中注销,或修改用户的概要文件、电子邮件地址,甚至是修改密码,结果造成彻底的帐户接管。跨站点脚本编制:任何“跨站点脚本编制”攻击都开始自诱惑用户单击精心制作的URL,以便利用受害者站点中的漏洞。发送含有恶意链接的电子邮件,或创建一个Web站点来包含指向易受攻击的站点的链接,通常可以做到这一点。当采用“链接注入”漏洞时,有可能在A站点中嵌入一个恶意的URL,当单击这个链接时,便启动对B站点的“跨站点脚本编制”攻击。网络钓鱼:攻击者有可能注入指向类似受攻击站点的恶意站点的链接。不小心的用户可能单击这个链接,但并不知道自己即将离开原始站点而浏览到恶意站点。之后,攻击者便可以诱惑用户重新登录,然后获取他的登录凭证。安全规范要求通过验证用户输入未包含危险字符,便可能防止恶意的用户导致应用程序执行计划外的任务,例如:启动任意SQL查询、嵌入将在客户端执行的Javascript代码、运行各种操作系统命令,等等。建议过滤出所有以下字符:[1]|(竖线符号)[2]&(&符号)[3];(分号)[4]$(美元符号)[5]%(百分比符号)[6]@(at符号)[7]'(单引号)[8]"(引号)[9]\'(反斜杠转义单引号)[10]\"(反斜杠转义引号)[11]<>(尖括号)[12]()(括号)[13]+(加号)[14]CR(回车符,ASCII0x0d)[15]LF(换行,ASCII0x0a)[16],(逗号)[17]\(反斜杠)以下部分描述各种问题、问题的修订建议以及可能触发这些问题的危险字符:SQL注入和SQL盲注:A.确保用户输入的值和类型(如Integer、Date等)有效,且符合应用程序预期。B.利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。当使用存储过程时,请利用ADO命令对象来实施它们,以强化变量类型。C.清理输入以排除上下文更改符号,例如:[1]'(单引号)[2]"(引号)[3]\'(反斜线转义单引号)[4]\"(反斜杠转义引号)[5])(结束括号)[6];(分号)2012-7-416:57:34150/187跨站点脚本编制:A.清理用户输入,并过滤出JavaScript代码。我们建议您过滤下列字符:[1]<>(尖括号)[2]"(引号)[3]'(单引号)[4]%(百分比符号)[5];(分号)[6]()(括号)[7]&(&符号)[8]+(加号)B.如果要修订<%00script>变体,请参阅MS文章821349C.对于UTF-7攻击:[-]可能的话,建议您施行特定字符集编码(使用'Content-Type'头或<meta>标记)。HTTP响应分割:清理用户输入(至少是稍后嵌入在HTTP响应中的输入)。请确保输入未包含恶意的字符,例如:[1]CR(回车符,ASCII0x0d)[2]LF(换行,ASCII0x0a)远程命令执行:清理输入以排除对执行操作系统命令有意义的符号,例如:[1]|(竖线符号)[2]&(&符号)[3];(分号)执行shell命令:A.绝不将未检查的用户输入传递给eval()、open()、sysopen()、system()之类的Perl命令。B.确保输入未包含恶意的字符,例如:[1]$(美元符号)[2]%(百分比符号)[3]@(at符号)XPath注入:清理输入以排除上下文更改符号,例如:[1]'(单引号)[2]"(引号)等LDAP注入:A.使用正面验证。字母数字过滤(A..Z,a..z,0..9)适合大部分LDAP查询。B.应该过滤出或进行转义的特殊LDAP字符:[1]在字符串开头的空格或“#”字符[2]在字符串结尾的空格字符[3],(逗号)[4]+(加号)[5]"(引号)[6]\(反斜杠)[7]<>(尖括号)[8];(分号)[9]()(括号)MX注入:应该过滤出特殊MX字符:[1]CR(回车符,ASCII0x0d)[2]LF(换行,ASCII0x0a)记录伪造:应该过滤出特殊记录字符:[1]CR(回车符,ASCII0x0d)[2]LF(换行,ASCII0x0a)[3]BS(退格,ASCII0x08)ORM注入:A.确保用户输入的值和类型(如Integer、Date等)有效,且符合应用程序预期。2012-7-416:57:34151/187B.利用存储过程,将数据访问抽象化,让用户不直接访问表或视图。C.使用参数化查询APID.清理输入以排除上下文更改符号,例如:(*):[1]'(单引号)[2]"(引号)[3]\'(反斜线转义单引号)[4]\"(反斜杠转义引号)[5])(结束括号)[6];(分号)(*)这适用于SQL。高级查询语言可能需要不同的清理机制。解决方案LoginImpl.java类中的getLoginInfo方法,将之前的操作员工号与密码拼接方式改成SQL变量绑定方式StringBuffersqlbuf=newStringBuffer();sqlbuf.append("SELECT.orgcode,A.userid,A.username,A.password,A.validate,A.usertype,C.orgname,C.norgcode,C.orgtype,");sqlbuf.append("now()ASlogindate,sp_genseqfunc('S','D')ASsessionid,");sqlbuf.append("(SELECTGROUP_CONCAT(B.datatype)FROMtb_userdatarelBWHEREB.userid=?)ASdatatypes,PASSWORD(?)=A.passwordASpwdiscorrect");sqlbuf.append("FROMtb_userA,tb_organizationC");sqlbuf.append("WHEREA.userid=?ANDA.effdate<=CURDATE()ANDA.expdate>=CURDATE()ANDC.orgcode=A.orgcode");web.xml增加如下配置:<!--可能存在的跨域代码字符串,用逗号分开--><context-param><param-name>CROSS_DOMAIN_STR</param-name><param-value><,>,%3C,%3E</param-value></context-param>Constans.java类增加如下变量:/***跨域特殊字符判断*/publicstaticList<String>CROSS_DOMAIN_STR=newArrayList<String>();FriendOneServlet.java类增加initSafetyConf安全初始化配置方法privatevoidinitSafetyConf(){Constans.CROSS_DOMAIN_STR.clear();StringcrossDomainStr=getServletContext().getInitParameter("CROSS_DOMAIN_STR");String[]crossDomainAry=crossDomainStr.split(",");for(Strings:crossDomainAry){Constans.CROSS_DOMAIN_STR.add(s.trim());}Constans.LOGIN_ERROR_TIMES=getServletContext().getInitParameter("LOGIN_ERROR_TIMES");Constans.LOGIN_ERROR_LOCK_SECOND=getServletContext().getInitParameter("LOGIN_ERROR_LOCK_SECOND");(Constans.CROSS_DOMAIN_STR);("LOGIN_ERROR_TIMES="+Constans.LOGIN_ERROR_TIMES);("LOGIN_ERROR_LOCK_SECOND="+Constans.LOGIN_ERROR_LOCK_SECOND);}在init方法中直接调用在ActionFilter.java类中增加checkCrossDomain跨域特殊字符串检查,并在doFilter中进行判断验证,如果存在特殊字符,则直接跳转到登陆界面修改error.jsp,此处是用于处理返回的错误信息目前是通过<html-el:errors/>标签方式加载错误信息,此处可根据输入的条件来进行错误注入,执行js代码,修改该当如下:一、将此错误标签通过textarea进行包装,错误信息是以文本方式显示,无法执行,如下:<textareastyle="height:100%;width:95%;color:red"readonly=true><html-el:errors/></textarea>同时修改BaseWebAction.java类的processError方法,将sb.append(ste[i]).append("<br>");这段代码改为sb.append(ste[i]).append("\n");二、无论返回什么错误信息,此处只显示“操作故障,请确认操作是否合法或联系管理员检查!”应用程序错误URL00/callAction.do 00/clientAction.do 00/loginAction.do安全问题描述未对入局参数值执行适当的边界检查未执行验证以确保用户输入与预期的数据类型匹配攻击方法如果攻击者通过伪造包含非应用程序预期的参数或参数值的请求,来探测应用程序(如以下示例所示),那么应用程序可能会进入易受攻击的未定义状态。攻击者可以从应用程序对该请求的响应中获取有用的信息,且可利用该信息,以找出应用程序的弱点。例如,如果参数字段是单引号括起来的字符串(如在ASP脚本或SQL查询中),那么注入的单引号将会提前终止字符串流,从而更改脚本的正常流程/语法。错误消息中泄露重要信息的另一个原因,是脚本编制引擎、Web服务器或数据库配置错误。以下是一些不同的变体:[1]除去参数[2]除去参数值[3]将参数值设置为空值[4]将参数值设置为数字溢出(+/-99999999)[5]将参数值设置为危险字符,如'"\'\");[6]将某字符串附加到数字参数值安全规范要求所有涉及到拼接SQL的地方,用绑定变量方式解决方案非模糊匹配的很好改,将以前拼接的形式找成“?”号,如果是动态拼接,无法确定数量的,如通过如下形式:List<String>args=newArrayList<String>();if(!"".equals(order.getOrdertitle())){sql.append("anda.ordertitlelike?");args.add("%"+order.getOrdertitle()+"%");//这种方式是用来进行模糊匹配的}if(!"".equals(order.getDbuser())){sql.append("anda.dbuser=?");args.add(order.getDbuser());}if(!"".equals(order.getEffdate())){sql.append("anda.effdate>=to_date(?,'yyyy-mm-dd')");//日期格式args.add(order.getEffdate());}if(!"".equals(order.getExpdate())){sql.append("anda.expdate<=to_date(?,'yyyy-mm-dd')");args.add(order.getExpdate());}拼接后查询如下:Stringsqlexec=pages.wrapSqlTotal(sql.toString(),getSimpleJdbcTemplate(),args.toArray());还有一种命名参数变量绑定的形式:Stringsql="SELECT*FROMtb_oa_fileswhereid=:id";List<FileInfo>files=newjava.util.ArrayList<FileInfo>();Map<String,String>parameters=newHashMap<String,String>();parameters.put("id",id);这种在查询时传入的是Map(key、value的键值对),key的值必需与绑定变量的名称一致,查询如下:getSimpleJdbcTemplate().query(sql,tb_oa_files_map,parameters);SQL查询条件中带In条件的变量绑定方法:如这种:selectdsnamefromtb_da_datasourcewheredsidin('111','222')首先我们确定从前台传过来的ID必需是不带单引号括起来的,如上面这种,传过来用逗号分开应该是:111,222这种形式,在进行变量绑定拼接SQL时进行如下操作:StringBuffersql=newStringBuffer(“selectdsnamefromtb_da_datasourcewheredsidin(”);String[]idAry=ids.split(“,”);for(inti=0;i<idAry.length;i++){ if(i!=0) sql.append(“,”); sql.append(“?”);}sql.append(“)”);getSimpleJdbcTemplate().query(sql.toString(),map,idAry);如果查询的变量不止这些ID还有其它的值,可通过下面方式:List<String>args=newArrayList<String>();if(!"".equals(dsname)){sql.append("anddsnamelike?");args.add("%"+dsname+"%");//这种方式是用来进行模糊匹配的}String[]idAry=ids.split(“,”);for(inti=0;i<idAry.length;i++){ if(i!=0) sql.append(“,”); sql.append(“?”); args.add(idAry[i]);}sql.append(“)”);getSimpleJdbcTemplate().query(sql.toString(),map,args.toArray());重新初始化一个ArrayList(此种List是顺序存储结构,此止必需是顺序存储结构),将数组的字增加到List,再通过toArray转成数组。SQL查询条件中带In条件的命名参数的变量绑定。命名参数就是通过冒号+变量名的形式进行绑定,在传入参数时是一个key、value的键值对,key必需与变量名保持一致,value就是对应输入的值。Map<String,String>parameters=newHashMap<String,String>();StringBuffersql=newStringBuffer(“selectdsnamefromtb_da_datasourcewheredsidin(”);String[]idAry=ids.split(“,”);for(inti=0;i<idAry.length;i++){ if(i!=0) sql.append(“,”); sql.append(“:dsid”).append(i);parameters.put(“dsid”+i,idAry[i]);}sql.append(“)”);getSimpleJdbcTemplate().query(sql.toString(),map,parameters);SQL注入URL00/loginAction.do安全问题描述可能会查看、修改或删除数据库条目和表攻击方法Web应用程序通常在后端使用数据库,以与企业数据仓库交互。查询数据库事实上的标准语言是SQL(各大数据库供应商都有自己的不同版本)。Web应用程序通常会获取用户输入(取自HTTP请求),将它并入SQL查询中,然后发送到后端数据库。接着应用程序便处理查询结果,有时会向用户显示结果。如果应用程序对用户(攻击者)的输入处理不够小心,攻击者便可以利用这种操作方式。在此情况下,攻击者可以注入恶意的数据,当该数据并入SQL查询中时,就将查询的原始语法更改得面目全非。例如,如果应用程序使用用户的输入(如用户名和密码)来查询用户帐户的数据库表,以认证用户,而攻击者能够将恶意数据注入查询的用户名部分(和/或密码部分),查询便可能更改成完全不同的数据复制查询,可能是修改数据库的查询,或在数据库服务器上运行Shell命令的查询。一般而言,攻击者会分步实现这个目标。他会先学习SQL查询的结构,然后使用该知识来阻挠查询(通过注入更改查询语法的数据),使执行的查询不同于预期。假设相关查询是:SELECTCOUNT(*)FROMaccountsWHEREusername='$user'ANDpassword='$pass'其中$user和$pass是用户输入(从调用构造查询的脚本的HTTP请求收集而来-可能是来自GET请求查询参数,也可能是来自POST请求主体参数)。此查询的一般用法,其值为$user=john、$password=secret123。形成的查询如下:SELECTCOUNT(*)FROMaccountsWHEREusername='john'ANDpassword='secret123'如果数据库中没有这个用户密码配对,预期的查询结果便是0,如果此类配对存在(也就是数据库中有名称为“john”的用户,且其密码为“secret123”),结果便是>0。这是应用程序的基本认证机制。但攻击者可以用下列方式来更改此查询:1.攻击者可以提供单引号字符(')所组成的输入,使数据库发出错误消息,其中通常包含关于SQL查询的有价值的信息。攻击者只需在发送的请求中包含用户值',并在密码中包含任何值(如foobar)。结果便是下列(格式错误)的SQL查询:SELECTCOUNT(*)FROMaccountsWHEREusername='''ANDpassword='foobar'这可能会产生以下错误消息(取决于后端所使用的特定数据库):查询表达式'username='''ANDpassword='foobar''中发生语法错误(遗漏运算符)。2012-7-416:57:2971/187这时攻击者便得知查询是根据表达式username='$user'ANDpassword='$pass'来构建的。利用手边的SQL查询时需要这一关键信息。攻击者了解查询的格式后,下一步只需使用:user='or1=1or''='password=foobar生成的查询如下:SELECTCOUNT(*)FROMaccountsWHEREusername=''or1=1or''=''ANDpassword='foobar'这表示查询(在SQL数据库中)对于“accounts”表的每项记录都会返回TRUE,因为1=1表达式永远为真。因此,查询会返回“accounts”中的记录数量,于是用户(攻击者)也会被视为有效。这个探测方法有若干变体,例如,发送';or\'(您应该记住,几乎所有供应商都有他们自己唯一的SQL“版本”。具体地说,发送'having1=1,也会生成错误消息,此消息会泄露有关列名称的信息。在某些情况下,用户输入不会并入字符串上下文(用单引号括住),而是并入数字上下文,换言之,就是依现状嵌入。因此,在这种情况下,可以使用输入字符串

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论