033-安全开发-JavaEE应用&SQL预编译&Filter过滤器&Listener监听器&访问控制
#知识点:
1、JavaEE-JDBC-SQL预编译
2、JavaEE-HTTP-Filter过滤器
3、JavaEE-对象域-Listen监听器
演示案例:
➢JavaEE-预编译-SQL
➢JavaEE-过滤器-Filter
➢JavaEE-监听器-Listen
#JavaEE-预编译-SQL原理:
提前编译好执行逻辑,你注入的语句不会改变原有逻辑!
- 预编译写法:
safesql
是一个预编译的 SQL 查询语句,其中?
是一个占位符,表示将在执行时动态替换。- 使用
PreparedStatement
:PreparedStatement
是Statement
的子接口,用于执行预编译的 SQL 语句。通过调用connection.prepareStatement(safesql)
创建一个PreparedStatement
对象。- 设置参数: 使用
setXXX
方法设置占位符的值。在这里,使用setString(1, s)
将字符串 **s
的值设置到第一个占位符上及sql语句中的==?==。**这种方式防止了 SQL 注入攻击,因为参数值是通过预编译的方式传递的,而不是通过直接拼接字符串。- 执行查询: 调用
executeQuery()
执行查询,得到ResultSet
对象。- 处理结果集: 根据业务需要,处理查询结果集的数据。
- 打印最终的预编译 SQL 语句(用于调试):
System.out.println(safesql);
这行代码用于在控制台打印最终生成的预编译 SQL 语句。这对于调试时检查生成的 SQL 语句是否正确是有帮助的。
// 预编译写法
String safesql = "SELECT * FROM news WHERE id=?";
// 使用PreparedStatement
try (PreparedStatement preparedStatement = connection.prepareStatement(safesql)) {
// 设置参数,防止SQL注入攻击
preparedStatement.setString(1, s);
// 执行查询
ResultSet resultSet = preparedStatement.executeQuery();
// 处理结果集...
// 打印最终的预编译 SQL 语句(用于调试)
System.out.println(safesql);
} catch (SQLException e) {
e.printStackTrace();
}
-
使用不安全写法,可以进行sql注入
select * from news where id=1
: 这是一个正常的SQL查询,目的是从名为"news"的表中选择ID为1的记录。
union
: 这是SQL的关键字,用于合并两个查询的结果集。select 1,2,3,version(),user(),database()
: 这是一个注入的查询,它返回了一些固定的值(1、2、3)以及数据库的版本信息(version()
)、当前用户(user()
)和当前数据库(database()
)的信息。
通过将这两个查询合并,攻击者试图将恶意的查询注入到正常的查询中,从而获取数据库的敏感信息。这种类型的攻击被称为联合查询注入。
- 使用预编译写法,固定sql语句的逻辑,防止进行sql注入
#JavaEE-过滤器-Filter
Filter被称为过滤器,过滤器实际上就是对Web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,通常都是用来拦截request进行处理的,也可以对返回的 response进行拦截处理。开发人员利用filter技术,可以实现对所有Web资源的管理,例如实现权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
1、创建过滤器之前的准备
- 创建新的项目FilterDemo1
- 在对应的包名上,创建分类包filter与servlet
- 在servlet下创建
TestServlet
,并进行检测- 启动服务器,尝试进行Xss攻击,发现可以
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从请求中获取名为 "code" 的参数值
String code = req.getParameter("code");
// 获取用于将输出发送回客户端的 PrintWriter 对象
PrintWriter out = resp.getWriter();
// 将 "code" 参数的值打印到客户端
out.println(code);
// 刷新 PrintWriter,确保立即发送任何缓冲的内容
out.flush();
// 关闭 PrintWriter 以释放资源
out.close();
}
localhost:8080/FilterDemo1_war_exploded/test?code=
2、创建过滤器
3、过滤器内置方法
-
在对应的filter下创建
XssFilter
-
并实现
Filter
接口中的所有方法- init doFilter destroy
- init(FilterConfig filterConfig):
- 该方法在过滤器被初始化时调用,只会执行一次。
- 用于执行一些初始化操作,例如获取配置信息等。
- doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain):
- 这是过滤器的主要方法,在每次请求被过滤时都会调用。
doFilter
方法中的filterChain.doFilter(request, response)
表示继续执行过滤器链,如果没有更多的过滤器,最终将调用目标资源(例如 Servlet 或 JSP)。- 如果在
doFilter
中不调用filterChain.doFilter
,则请求将被拦截,不会继续传递。
- destroy():
- 该方法在过滤器被销毁时调用,只会执行一次。
- 用于执行一些清理工作,释放资源等。
@WebFilter("/test") public class XssFilter implements Filter { @Override **// 中间件启动后就自动运行** public void init(FilterConfig filterConfig) throws ServletException { System.out.println("xss开启过滤"); } @Override **// 中间件关闭后就自动运行** public void destroy() { System.out.println("xss销毁过滤"); } @Override **// doFilter 访问路由触发的方法** public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("xss正在过滤"); // 过滤代码就应该在放行前 // 如果符合就放行,不符合就过滤(拦截) // XSS过滤 接受参数值 如果有攻击payload 就进行拦截 // 接受参数值 如果没有攻击payload 就进行放行 **HttpServletRequest request = (HttpServletRequest) servletRequest; String code = request.getParameter("code"); if (!code.contains("<script>")) { // 没有攻击payload // 放行 filterChain.doFilter(servletRequest, servletResponse); } else { System.out.println("存在XSS攻击"); // 继续拦截 // 这里可以根据需要添加拦截后的处理逻辑,例如记录日志、返回错误信息等** } } }
4、过滤器触发流程
@WebFilter("/test")
<filter>
<filter-name>xssFilter</filter-name>
<filter-class>com.example.filter.xssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>xssFilter</filter-name>
<url-pattern>/test</url-pattern>
</filter-mapping>
5、利用过滤器简单实现:cookie身份验证
-
在servlet下创建AdminServlet,
@WebServlet("/admin") public class AdminServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎进入管理员页面"); } }
-
在filter下创建AdminFileter
-
先不加入判断获取到浏览器本身的cookie值
@WebFilter("/admin") public class AdminFileter implements Filter{ @Override // 过滤器初始化方法,在应用启动时执行 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("admin身份检测开启"); } @Override // 过滤器销毁方法,在应用关闭时执行 public void destroy() { System.out.println("admin身份检测销毁"); } @Override // 过滤器核心逻辑,处理请求和响应 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("admin身份检测进行"); // 检测Cookie过滤 HttpServletRequest request = (HttpServletRequest) servletRequest; Cookie[] cookies = request.getCookies(); // 对Cookie进行遍历获取 for (Cookie c : cookies) { String cName = c.getName(); // 获取cookie名 String cValue = c.getValue(); // 获取cookie值 System.out.println(cName); System.out.println(cValue); filterChain.doFilter(servletRequest, servletResponse); } } }
-
检查请求中是否包含名为 “user” 且值为 “admin” 的Cookie。如果符合条件,则放行请求;否则,输出 “非管理员访问”。
-
相应进入管理员页面,必须先在浏览器中添加对应判断的cookie值
-
如果对应不上则是非管理员访问,不予通过
@Override // 过滤器核心逻辑,处理请求和响应 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("admin身份检测进行"); // 检测Cookie过滤 HttpServletRequest request = (HttpServletRequest) servletRequest; Cookie[] cookies = request.getCookies(); **// 对Cookie进行遍历获取 for (Cookie c : cookies) { String cName = c.getName(); // 获取cookie名 String cValue = c.getValue(); // 获取cookie值 System.out.println(cName); System.out.println(cValue); // 检查是否包含名为 "user" 且值为 "admin" 的Cookie if (cName.contains("user") && cValue.contains("admin")) { // 是管理员,放行请求** filterChain.doFilter(servletRequest, servletResponse); **} else { System.out.println("非管理员访问"); // 非管理员,可以根据需求添加相应的处理逻辑,例如重定向到登录页等** } } }
-
6、过滤器安全场景
开启过滤后,发现成功拦截Xss攻击
Payload检测,权限访问控制,红队内存马植入,蓝队清理内存马等
内存马参考:https://mp.weixin.qq.com/s/hev4G1FivLtqKjt0VhHKmw
#JavaEE-监听器-Listen
参考:https://blog.csdn.net/qq_52797170/article/details/124023760
监听ServletContext、HttpSession、ServletRequest等域对象创建和销毁事件
监听域对象的属性发生修改的事件
监听在事件发生前、发生后做一些必要的处理
1、创建监听器
-
创建新的项目ListenDemo1
-
在对应的包名上,创建分类包listenerr与servlet
-
在servlet下创建
CSession
DSession
,并进行检测 -
DSession
一个简单的Servlet,对应一个/ds
的URL映射。在收到GET请求时,它会销毁当前请求的HttpSession
。下面是对代码的注释:
@WebServlet("/ds") public class DSession extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet里面销毁Session"); // 销毁Session req.getSession().invalidate(); } }
@WebServlet("/ds")
: 通过此注解,指定了Servlet的URL映射为 “/ds”。System.out.println("Servlet里面销毁Session");
: 打印一条日志,说明Servlet正在销毁Session。req.getSession().invalidate();
: 获取当前请求的HttpSession
,并调用invalidate()
方法使其失效,从而销毁Session。这通常会导致用户在当前会话中的状态丢失,因为Session被销毁了。
-
这段代码是一个简单的Servlet,对应一个
/cs
的URL映射。在收到GET请求时,它会创建一个新的HttpSession
。下面是对代码的注释:
@WebServlet("/cs") public class CSession extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet里面创建Session"); // 创建Session req.getSession(); } }
@WebServlet("/cs")
: 通过此注解,指定了Servlet的URL映射为 “/cs”System.out.println("Servlet里面创建Session");
: 打印一条日志,说明Servlet正在创建Session。req.getSession();
: 获取当前请求的HttpSession
,如果不存在**则会创建一个新的Session。**这通常会在应用程序需要使用会话状态时调用。
2、监听器内置方法
这段代码定义了一个实现 HttpSessionListener
接口的监听器类 ListenSession
,用于监听HttpSession
的创建和销毁事件。
下面是对代码的注释:
@WebListener
public class ListenSession implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
// 监听检测有Session创建就会执行这里
System.out.println("监听器监听到了session创建");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// 监听检测有Session销毁就会执行这里
System.out.println("监听器监听到了session销毁");
}
}
@WebListener
: 通过此注解,标记这是一个监听器类。@Override
注解用于表示下面的方法是对接口中方法的重写。public void sessionCreated(HttpSessionEvent se)
: 当有新的HttpSession
被创建时,这个方法会被调用。在这里,它简单地输出一条日志表示监听器检测到了session
的创建。public void sessionDestroyed(HttpSessionEvent se)
: 当一个HttpSession
被销毁时,这个方法会被调用。在这里,它简单地输出一条日志表示监听器检测到了session
的销毁。
3、监听器触发流程
在Java Web应用中,监听器用于监控和响应特定的事件。对于监听器的触发流程,以下是一般的步骤:
@WebListener
<listener>
.......
</listener>
- 注册监听器:
- 在Web应用中,你需要将监听器注册到相应的组件上。例如,在
web.xml
文件中配置监听器,或者使用注解(如@WebListener
)标记监听器类。
- 在Web应用中,你需要将监听器注册到相应的组件上。例如,在
- 事件发生:
- 当与监听器关联的特定事件在Web应用中发生时,监听器会被触发。
- 调用监听器方法:
- 监听器类中实现的相应方法(如
sessionCreated
、sessionDestroyed
等)将被调用。这些方法包含与事件相关的信息,允许监听器执行特定的逻辑。
- 监听器类中实现的相应方法(如
- 执行自定义逻辑:
- 在监听器方法中,你可以编写自定义的逻辑以响应事件。这可能包括记录日志、修改数据、发送通知等。
举例来说,对于HttpSessionListener
:
- 当一个新的
HttpSession
被创建时,sessionCreated
方法将被调用。 - 当一个
HttpSession
被销毁时,sessionDestroyed
方法将被调用。
总的来说,监听器提供了一种在Web应用中对特定事件进行响应的机制,使开发者能够以声明性的方式处理应用的生命周期事件。
4、监听器安全场景
代码审计中分析执行逻辑触发操作,红队内存马植入,蓝队清理内存马等