欢迎使用普元产品知识库,本知识库包含普元应用开发平台EOSPlatform,流程平台BPS,企业服务总线ESB,微服务平台Microservice,运维管理平台Devops,数据集成平台DI
欢迎使用普元文档库
软件环境
EOS7.5企业版+tomcat7.0.54,权限框架使用EOS7.5自带的coframe,AppScan版本: V9.0.0.1
备注:tomcat7.0.54存在一些安全漏洞,本例后期用tomcat-7.0.72作为应用服务器。
说明
AppScan分为静态扫描和动态扫描,本例中仅提供业务代码给客户做静态扫描,未提供coframe源码供客户扫描,静态扫描问题很少也很好改,故不对静态扫描问题做说明,以下仅对动态扫描问题做详细说明。
本例首次提供给用户动态扫描地址:http://ip:8080/default,以下仅介绍中、高级别问题的解决方案。
参考
http://p.primeton.com/articles/54d0923bbe20aa4012000089
+http://www.cnblogs.com/zhuangjolon/p/5474436.html+
原因简析:tomcat服务器的http访问,安全级别不够
解决思路:开启EOS安全开关,由于本例是tomcat服务器,还需要将服务器修改成https访问
解决方案:
1) 打开安全开关
将外置目录下应用中的user-config.xml颜色标记的内容false改为true,路径如: apps_config\default(以实际应用名称为准)\config\user-config.xml
< group>
< configValue key="isOpenSecurity">true</configValue>
< configValue key="isAllInHttps">false</configValue>
< !-- --tomcat default config--->
< configValue key="host">ip</configValue>
< configValue key="http-port">8080</configValue>
< configValue key="https-port">8443</configValue>
< configValue key="Exclude">*/common.download,/saveForm.jsp,*/saveDataset.jsp</configValue> < /group>
提示:如是tomcat应用服务器将false改为true后,还要将注释部分打开,并根据注释部分的配置参数配置tomcat应用服务器的HTTPS协议,见下一节。
2) Tomcat配置https
keytool -genkey -alias tomcat -keyalg RSA -keystore C:\primeton\platform\apache-tomcat-7.0.54\tomcat.keystore -validity 36500
(参数简要说明:"C:\primeton\platform\apache-tomcat-7.0.54\tomcat.keystore"含义是将证书文件保存在路径C:\primeton\platform\apache-tomcat-7.0.54下,证书文件名称是tomcat.keystore ;"-validity 36500"含义是证书有效期,36500表示100年,默认值是90天)
在命令行填写必要参数:
A、Enter keystore password:此处需要输入大于等于6个字符的字符串可输入000000
B、"What is your first and last name?"这是必填项,并且必须是TOMCAT部署主机的域名或者IP[如:gbcom.com 或者 192.168.30.28],就是你将来要在浏览器中输入的访问地址
C、"What is the name of your organizational unit?"、"What is the name of your organization?"、"What is the name of your City or Locality?"、"What is the name of your State or Province?"、"What is the two-letter country code for this unit?"可以按照需要填写也可以不填写直接回车,在系统询问"correct?"时,对照输入信息,如果符合要求则使用键盘输入字母"y",否则输入"n"重新填写上面的信息
D、Enter key password for <tomcat>,这项较为重要,会在tomcat配置文件中使用,建议输入与keystore的密码一致,设置其它密码也可以
完成上述输入后,直接回车则在你在第二步中定义的位置可以找到生成的文件。
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="C:\primeton\platform\apache-tomcat-7.0.54\tomcat.keystore" keystorePass="000000"/>
配置所在位置,供参考:
属性说明:
clientAuth:设置是否双向验证,默认为false,设置为true代表双向验证
keystoreFile:服务器证书文件路径
keystorePass:服务器证书密码
上述配置完成后,即支持https访问系统,如需屏蔽http访问方式,可参考下一节
3) 屏蔽http访问(非必要)
可修改apache-tomcat-7.0.54\conf下面的web.xml,在100行之后添加如下内容:
<security-constraint>
<web-resource-collection >
<web-resource-name >SSL</web-resource-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.action</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>Client Cert Users-only Area</realm-name>
</login-config>
原因简析:AppScan试图访问系统中不存在的一些页面时,响应状态为"200 OK"。
解决思路:当AppScan访问不存在的页面时,修改响应状态为400或者404
解决方案:
修改UserLoginWebInterceptor.Java的doIntercept方法,在如下位置增加响应状态为404
(高)可预测的登录凭证
原因简析:账号密码过于简单,易被破解
解决思路:将密码修改得复杂一些,本例中将sysadmin的密码修改成1234qwerASDF即解决此问题。
完整示例代码请参考:不充分帐户封锁解决方案.rar
原因简析:连续输入密码错误多次,未锁定账号,存在被暴利破解风险
解决思路:密码输入错误3次后,锁定用户一段时间。
解决方案:
直接使用cap_user表中的错误标记字段errcount做标记,在org.gocom.components.coframe.rights\src\org\gocom\components\coframe\rights\user\CapUserService.java中增加2个方法:markErrorCount、autoUnlockCapUser供业务逻辑authentication.bizx(为coframe开源代码org.gocom.components.coframe.core\org.gocom.components.coframe.auth\src\org\gocom\components\coframe\auth\LoginManager下)调用,如下图示例:
ICapUserService.java新增接口:
void markErrorCount(CapUser capUser);
void autoUnlockCapUser(CapUser capUser);
CapUserService.java新增方法:
/**
* 标记密码输入次数,当验证用户密码错误后调用,处理逻辑如下:<br>
* 获取上次密码输入错误时间validtime字段,如果不是当天,则初始化错误次数为1,错误时间为当天<br>
* 如果是当天,则次数+1.如果次数达到3次,则锁定用户,并将解锁时间设定为24小时后。安全扫描通过后,可以将该次数增大一些, sysadmin的错误次数可以适当增加一些,避免系统管理员被锁定
* @param capUser
*/
public void markErrorCount(CapUser capUser) { Date date = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd"); String nowDate = sf.format(date); BigDecimal lastErrorCount = capUser.getErrcount(); int errorCount = 0; if (lastErrorCount != null) { errorCount = lastErrorCount.intValue(); } String validtime = capUser.getValidtime(); if (validtime != null && validtime.equals(nowDate)) {// 时间一致,表示当天有输入错误 errorCount++; capUser.setErrcount(BigDecimal.valueOf(errorCount)); int flag = 3; if (errorCount >= flag) {// 如果错误次数达到3次,则锁定用户,解锁时间为24小时后 capUser.setStatus("2"); // 如果错误次数达到3次,则锁定用户,解锁时间为24小时后 Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DAY_OF_MONTH, +1); // +1今天的时间加一天 date = calendar.getTime(); capUser.setUnlocktime(date); } } else {// 不是当天输入密码错误,则重置错误次数为1 errorCount = 1; capUser.setErrcount(BigDecimal.valueOf(errorCount)); capUser.setValidtime(nowDate); } this.updateCapUser(capUser); }
/**
* 自动解锁用户,当用户输入用户名和密码后,如果用户为锁定状态,并且解锁日期早于当前时间,则自动解锁用户,否则视为锁定期未结束
* @param capUser
*/
public void autoUnlockCapUser(CapUser capUser) { if (capUser.getStatus() != null && capUser.getStatus().equals("2")) {// 如果是锁定状态 if (capUser.getUnlocktime().before(new Date())) {// 解锁日期早于当期日期 capUser.setStatus("1"); capUser.setErrcount(BigDecimal.valueOf(0)); this.updateCapUser(capUser); } } }
原因简析:登录前和登陆后的会话标识未更新
解决思路:每次登陆时,更新会话标识
解决方案:
Ø 在项目中增加一个java类SessionUpdateInterceptor,拷贝以下代码:
package org.gocom.components.coframe.auth;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class SessionUpdateInterceptor implements Filter {
public void destroy() {
// TODO 自动生成的方法存根
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
if(req.getRequestURI().contains("org.gocom.components.coframe.auth.login.login.flow")) {
String action = req.getParameter("_eosFlowAction");
if(action == null || "login".equalsIgnoreCase(action)) {
HttpSession session = req.getSession(true);
session.invalidate();
HttpSession sessionToUpdate = req.getSession(true);
for(Cookie c : req.getCookies()) {
if(c.getName().equals("JSESSIONID"))
c.setValue(sessionToUpdate.getId());
}
}
}
}
chain.doFilter(request, response);
}
public void init(FilterConfig arg0) throws ServletException {
// TODO 自动生成的方法存根
}
}
Ø 修改web.xml
打开项目的web.xml文件,增加拦截器,在如下图位置增加以下代码:
<filter>
<filter-name>SessionUpdate</filter-name>
<filter-class>org.gocom.components.coframe.auth.SessionUpdateInterceptor</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionUpdate</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
原因简析:cookie中没有Secure 属性
解决思路:在cookie中添加此属性即可
解决方案:
此处一开始参考其他人的方案,在jsp页面添加如下代码,但问题依旧,而且引出了其他的一些已解决的问题:
<% response.setHeader("Set-Cookie", "name=value1; Secure ");%>
故本例未采用上面的方案,而是在redirect.jsp页面,增加一行如下代码即可:
原因简析:用户名无效和密码错误的提示不一样,AppScan认为这样不安全
解决思路:统一返回值,登录错误始终提示"用户名或密码错误"
解决方案:
修改authentication.bizx中的returnValue,除了认证成功外,其余一律返回0,修改login.jsp的提示,当返回值为0时,提示"用户名或密码错误!"