代码审查
代码审查
输入验证
路径遍历
应用程序对用户可控制的输入未经合理校验,就传送给一个文件API。攻击者可能会使用一些特殊的字符(如..
和/
)摆脱受保护的限制,访问一些受保护的文件或目录。
缺陷代码:
@GET
@Path("/images/{image}")
@Produces("images/*")
public Response getImage(@javax.ws.rs.PathParam("image") String image, MultipartFile file) {
File fileTest1 = new File("resources/images/", image);
String fileName = file.getOriginalFilename();
if (!fileTest1.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(fileTest1)).build();
}
缺陷原因: 第五行中文件的名字由用户输入,未经过合法性验证,用户可以通过输入特殊字符(…/file.text)获取系统资源,获取resources下的file.test文件
正确示范:
# 引入文件名过滤/处理方法
import org.apache.commons.io.FilenameUtils;
@GET
@Path("/images/{image}")
@Produces("images/*")
public Response getImage(@javax.ws.rs.PathParam("image") String image, MultipartFile file) {
# 读取文件之前,对文件名进行过滤处理
File fileTest = new File("resources/images/", FilenameUtils.getName(image));
String fileName = FilenameUtils.getName(file.getOriginalFilename());
if (!fileTest.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(fileTest)).build();
}
代码注入
SQL注入:Mybatis
SQL注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原SQL语句的含义,进而执行任意SQL命令,达到入侵数据库乃至操作系统的目的。在Mybatis Mapper Xml中,#
变量名称创建参数化查询SQL语句,不会导致SQL注入。而$
变量名称直接使用SQL指令,会导致SQL注入攻击。
缺陷代码:
<!--select user information by name-->
<select id="queryByUserName" resultMap="userResultMap" parameterType="String">
select * from db_user where user_name=${username}
</select>
缺陷原因: 在第三行中使用了${},mybatis注入中¥{}是先取值,再编译,传入参数是什么直接填入{}内,不做任何改变,如果传入'username' or 1=1,则可以跳过验证,直接将数据库中信息返回。应替换为#{},mybatis中#{}会做预编译处理,用占位符?预留位置,传入参数会当作字符串进行处理如之前传入'username' or 1=1,会被转译为“'username' or 1=1”,判断是否有username=“'username' or 1=1”,更加安全。
正确示范:
<!--select user information by name-->
<select id="queryByUserName" resultMap="userResultMap" parameterType="String">
select * from db_user where user_name=#{username}
</select>
跨站脚本攻击
转存型XSS
存储型XSS是指应用程序通过Web请求获取不可信赖的数据,并且在未检验数据是否存在XSS代码的情况下,将其存入数据库。当程序下一次从数据库中获取该数据时,致使页面再次执行XSS代码。存储型XSS可以持续攻击用户,在用户提交了包含XSS代码的数据存储到数据库后,每当用户在浏览网页查询对应数据库中的数据时,那些包含XSS代码的数据就会在服务器解析并加载,当浏览器读到XSS代码后,会当做正常的HTML和JS解析并执行,于是发生存储型XSS攻击。
转存型XSS攻击图示:
反射型XSS
反射型XSS是指应用程序通过Web请求获取不可信赖的数据,并在未检验数据是否存在恶意代码的情况下,将其发送给用户。反射型XSS一般可以由攻击者构造带有恶意代码参数的URL来实现,在构造的URL地址被打开后,其中包含的恶意代码参数被浏览器解析和执行。这种攻击的特点是非持久化,必须用户点击包含恶意代码参数的链接时才会触发。
反射型XSS攻击图示:
解决方法
-
对用户的输入进行合理验证(如年龄只能是数字),对特殊字符(如
<、>、'、"
以及<script>、javascript
等进行过滤。 -
根据数据将要置于HTML上下文中的不同位置(HTML标签、HTML属性、JavaScript脚本、CSS、URL),对所有不可信数据进行恰当的输出编码。
-
设置HttpOnly属性,避免攻击者利用跨站脚本漏洞进行Cookie劫持攻击。在Java EE中,给Cookie添加HttpOnly的代码如下:
response.setHeader("Set-Cookie","cookiename=cookievalue; path=/; Domain=domainvaule; Max-age=seconds; HttpOnly");
继承HttpServletRequestWrapper方法,将请求中的参数替换掉
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
/**
* 请求参数替换,防止XSS攻击
*/
public class XSSHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] requestBody;//将流保存下来
public XSSHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
//修改并存储流信息
String str = scriptXSS(IOUtils.toString(request.getInputStream()));
requestBody = str.getBytes();
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = scriptXSS(values[i]);
}
return encodedValues;
}
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
return scriptXSS(value);
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
return scriptXSS(value);
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map1 = super.getParameterMap();
Map<String, String[]> escapeMap = new HashMap<>();
Set<String> keys = map1.keySet();
for (String key : keys) {
String[] valArr = map1.get(key);
if (valArr != null && valArr.length > 0) {
String[] escapeValArr = new String[valArr.length];
for (int i = 0; i < valArr.length; i++) {
String escapeVal = scriptXSS(valArr[i]);
escapeValArr[i] = escapeVal;
}
escapeMap.put(key, escapeValArr);
}
}
return escapeMap;
}
@Override
public ServletInputStream getInputStream(){
// 返回处理之后的数据
return new ServletInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
@Override
public int read(){
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
public static String scriptXSS(String value) {
if (value != null) {
value = value.replaceAll("", "");
Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Pattern.compile(".*<.*", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
}
return value;
}
}
为了防止xss攻击过滤器
import com.abc.iotplatform.config.XSSHttpServletRequestWrapper;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 防止xss攻击过滤器
*/
public class XSSFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(new XSSHttpServletRequestWrapper(httpServletRequest), httpServletResponse);
}
}
最后在文件配置中将过滤器加入就可以了
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import javax.servlet.DispatcherType;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<XSSFilter> XSSFilter() {
FilterRegistrationBean<XSSFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new XSSFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1); // 设置排序
registrationBean.setDispatcherTypes(DispatcherType.REQUEST);
return registrationBean;
}
}
注:目前项目代码审查就这么多问题,后续有待跟进!
本文来自博客园,作者:芏筄,转载请注明原文链接:https://www.cnblogs.com/MiaoStudy/p/16627323.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)