相关背景
在实际的业务开发中,SQL交互往往是业务系统中不可或缺的一项。在Java中提供了类似Mybatis、Hibernate、SpringData JPA等来满足相关的数据库交互需要。但是由于种种原因,开发人员在处理应用程序和数据库交互时,使用字符串拼接的方式构造SQL语句,导致了SQL注入问题。那么有时候面对大量的接口存在SQL注入,迭代困难的时候,过滤器/拦截器便是很多开发人员的首选,通过过滤相关的SQL关键字,避免SQL注入得到进一步利用。
针对上述场景,很多时候需要加检查过滤器设计是否严谨,检查是否有漏网之鱼,导致SQL注入漏洞被攻击者进行利用。前段时间审计某项目时发现一处SQL注入导致的"越权",以下是相关的过程。
挖掘过程
系统基于SpringMVC进行开发,业务主要是与简历编辑相关。相关的问题接口主要在修改个人简历处。一般来说,这种修改个人信息的业务,除了修改内容以外,主要传递两个关键信息:
- 当前用户的身份凭证userId
- 当前用户的业务编号(这里是简历),resumeId
在进行接口业务请求时,将业务相关的关键参数userid聪当前用户的身份凭证(一般是session)获取,绑定个人用户身份,然后从前端获取需要修改的resumeId,最后在保存信息进行SQL交互时,从会话在获取的userId再与resumeId进行二次绑定,保证userId对应的用户仅能修改自己的简历。类似的SQL语句如下:
UPDATE user_resume SET content='test',user_name='test'{省略相关内容} where userId = $userId and resumeId=$resumeId;
如下是相关的代码:
首先是Controller,在Controller层对用户的输入进行相关的封装(这里是简历的相关信息),通过自动绑定的处理方式,直接将用户的输入绑定到resume对象里,然后通过当前登录会话获取当前用户的userId,通过调用service的update方法进行简历内容的更新:
@ResponseBody
@RequestMapping(value = "/updateResume", method = RequestMethod.POST)
public PagedResult<ResponseRes> updateResume(Resume resume) {
String userId = (String)session.getAttribute("userid");
PagedResult<ResponseRes> pageResult = this.resumeService
.update(resume,userid);
return pageResult;
}
查看service层实现,调用的是resumeService的update方法: