首页 > 数据库 > 数据库开发技术 > 互联网金融产品实战——安全开发篇

说到安全开发,总绕不开两个词:OWASP(Open Web Application Security Project)和CWE(Common Weakness Enumeration),针对其中的某些关键点再结合自身业务的特点,逐个作出应对。


(看不清时,点击查看大图)
下文针对某些点,并结合之前的项目经历,简单列出几个解决方法供大家参考。
一、CSRF跨站请求伪造过滤器,杜绝不信任的站点非法请求服务。一些图片防盗链的网站采用类似Refer机制完成的。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String sourceRefer = req.getHeader("Referer");
//允许配置多个可信赖Referer,存储在资源文件中
String allowRefers = bundle.getString("CSRF.NORMAL.REFERER");
List<String> urlList = new ArrayList<String>();
if (StringUtil.isNotEmpty(allowRefers)) {
String[] refers = allowRefers.split("#");
if (ArrayUtils.isNotEmpty(refers)) {
for (int i = 0; i < refers.length; i++) {
String string = refers[i];
urlList.add(string);
}
}
}
if (StringUtil.isNotBlank(sourceRefer)) {
//将http or https等协议头 过滤掉,形如http://www.baidu.com
String[] srcRef = sourceRefer.trim().split("//");
if (ArrayUtils.isNotEmpty(srcRef)) {
//非正式环境下,有端口配置,再重新分隔,形如http://test.backkom.com:8080/ofs
String[] srcRefer = srcRef[1].split(":");
if (srcRefer.length == 1) {
//正式环境下,均是域名,形如http://www.web2.0bk.com/news/12123.html
String[] srcReferSplit = srcRefer[0].split("/");
if (!urlList.contains(srcReferSplit[0])) {
logger.info("UnReliable referer :" + srcReferSplit[0]);
//不信任时不作任何展示,直接跳转至500页面,前端js拿到此响应码,跳转到500页面
resp.setStatus(500);
String redirectUrl = bundle.getString("CSRF.REDIRECT.URL");
resp.setHeader("Location", redirectUrl);
} else {
chain.doFilter(req, resp);
}
} else {
if (!urlList.contains(srcRefer[0])) {
logger.info("UnReliable referer :" + srcRefer[0]);
//不信任时不作任何展示,直接跳转至500页面,前端js拿到此响应码,跳转到500页面
resp.setStatus(500);
String redirectUrl = bundle.getString("CSRF.REDIRECT.URL");
resp.setHeader("Location", redirectUrl);
} else {
chain.doFilter(req, resp);
}
}
} else {
chain.doFilter(req, resp);
}
} else {
chain.doFilter(req, resp);
}
}
二、Session超时过滤器,过滤请求,判断请求是否失效,失效后直接退出要求再次登陆
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String countStr = bundle.getString("filter.url.count");
int urlCnts = Integer.valueOf(countStr);
String tempStr = "filter.url";
StringBuffer urlPre = new StringBuffer();
for (int i = 0; i < urlCnts; i++) {
String filterUrl = bundle.getString(urlPre.append(tempStr).append(i).toString());
if (StringUtils.isNotEmpty(filterUrl)) {
urlList.add(filterUrl);
}
urlPre.setLength(0);
}
// 初始化需要拦截的文件夹
String include = filterConfig.getInitParameter("include");
if (include != null) {
StringTokenizer st = new StringTokenizer(include, ",");
list.clear();
while (st.hasMoreTokens()) {
list.add(st.nextToken());
}
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//不含参数的路径
String servletPath = req.getServletPath();
StringBuilder jsStr = new StringBuilder("");
StringBuilder sb = new StringBuilder();
Date d = new Date();
String ts = String.valueOf(d.getTime());
sb.append(bundle.getString("tomcat.admin.login.url")).append(EztpfpConstants.LOGIN_ADMIN_URL).append(bundle.getString("tomcat.admin.url")).append("?ts=").append(ts);
//当用户没有登录时,需要跳转到的登陆链接
String adminLoginReturnUrl = sb.toString();
String adminJumpUrl = null;
if (StringUtils.isNotEmpty(adminLoginReturnUrl)) {
adminJumpUrl = jsStr.append(adminLoginReturnUrl).toString();
}
//获取用户信息,判断用户是否登录
UserInfoBean userInfoBean = (UserInfoBean) getSession().getAttribute("online.user")
//是否是ajax请求
String xRequested = req.getHeader("X-Requested-With");
if (userInfoBean == null) {
//至过滤*.action,*.html的链接
if ((servletPath.contains(".action") || servletPath.contains(".html")) && !urlList.contains(servletPath)) {
logger.info(FunIMsgFormat.MsgStyle.DEFAULT_LOG
.getFormat(EztpfpConstants.LOGGER_TXT_MONITOR),
new Object[] { "", "doFilter", "进入session过滤器拦截路径!", new Date() });
//如果是ajax请求,返回给前台
if ("XMLHttpRequest".equals(xRequested)) {
setJsonResponse(resp, adminLoginReturnUrl);
} else {
//不是ajax请求,直接跳转登陆页面,由JS处理跳转功能
req.setAttribute("msg", "您还没有登录或登录已超时,请重新登录!");
resp.sendRedirect(adminJumpUrl);
}
} else {
chain.doFilter(req, resp);
}
} else {
chain.doFilter(req, resp);
}
}
private void setJsonResponse(HttpServletResponse res, String redirectUrl) throws IOException {
res.setStatus(800);
res.setHeader("Location", redirectUrl);
}
}
三、关键交易防重技术

(看不清时,点击查看大图)
四、XSS过滤器
可以利用OWASP的一个开源项目:AntiSamy,来解决XSS攻击问题。AntiSamy是可以确保前端输入的HTML、CSS、JavaScript符合规范的API。确保用户无法在HTML中提交恶意代码,而这些恶意代码通常被输入到个人资料、评论等会被服务端存储的数据中,以造成服务的不友好或者破坏正常服务。项目地址:https://code.google.com/archive/p/owaspantisamy/downloads,扩展阅读可网络中查找相关资料。
另MyBatis中已经实现了对SQL的预编译,但针对${xxx}参数的情况需要着重关注,因为存在SQL注入的可能性。
五、校验再校验
特别针对后台权限开发时,以往的做法是这样的:根据登陆用户的不同,找到其对应的菜单展现出来,这样权限就控制住了。这种做法存在一种隐患,如果此用户通过其它渠道得到某个功能的访问链接地址,直接在URL中输入此链接来操作对应的功能,那么权限控制就无从谈起。
针对此种情况,可适当增加权限再校验的步骤,根据提交过来的请求,再次校验权限是否足够,可通过拦截器实现。
其它安全注意项,还很多,这里不一一展开了,可在项目中实际摸索,找出合适的解决方案。
乾坤大挪移--->:


原文作者:MavenTalk;如有侵权,请联系管理员删除。