安全开发JAVAJAVAEE
Att@ckxu创建javaee项目


创建新项目时可以删除的内容:

Servlet&路由&周期
https://blog.csdn.net/yxmoar/article/details/109889006
什么是Servlet
Servlet是运行在Web服务器或应用服务器上的程序,它是作为来自Web浏览器或其他HTTP客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。使用Servlet可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。本章内容详细讲解了web开发的相关内容以及servlet相关内容的配置使用,是JAVAEE开发的重中之重。

Servlet API

创建一个类继承HttpServlet

web.xml配置映射关系
具体参考:https://blog.csdn.net/weixin_52937170/article/details/142183673

当访问index时,经过路由配置访问到IndexServlet,由于是GET请求,触发了doGet方法(类似于反序列化的魔术方法)

类似的 触发doPost方法:


还可以使用@WebServlet注解来配置Servlet路由(此时只需要在Servlet类前加一个@WebServlet,)

web.xml不需要配置,但是需要保留web-app标签结构

此时也能够正常识别路由信息


Servlet生命周期


这些方法也类似于反序列化魔术方法
处理接收和回显
HttpServletRequest(HTTP请求的信息)
- ServletRequest的子接口:**
HttpServletRequest是ServletRequest**接口的子接口,提供了用于处理HTTP请求的额外功能。
- getParameter(name):通过参数名获取请求中的值。返回一个**
String**,表示与给定参数名相对应的单个值。
- getParameterValues(name):通过参数名获取请求中的多个值。返回一个**
String[]**,表示与给定参数名相对应的多个值。
HttpServletResponse(HTTP响应的信息)
- ServletResponse的子接口:**
HttpServletResponse是ServletResponse**接口的子接口,提供了用于处理HTTP响应的额外功能。
- setCharacterEncoding():设置响应的字符编码格式。通常用于确保正确的文本输出。
- setContentType():设置响应内容的类型和编码。常用于指定输出的数据类型,如HTML、JSON等。
- getWriter():获取一个**
PrintWriter**字符输出流,用于向客户端发送文本数据。
- PrintWriter:**
PrintWriter**是用于向客户端输出字符数据的类,可以接受各种数据类型,然后将其转换为文本并发送到客户端。
连接数据库-JDBC&Mybatis&库
https://blog.csdn.net/xiaozhezhe0470/article/details/105420763
三种连接数据库的方法:jdbc mybatis hibernate

现在用的最多的是mybatis
JDBC
https://www.jianshu.com/p/ed1a59750127
原生数据库开发,是由java提供的统一API接口
数据库驱动:由各个数据库厂商提供,用于访问数据库的jar包,遵循JDBC接口
下载jar
下载地址:https://mvnrepository.com/
搜索相应的数据库(比如这里是mysql),选择版本,下载jar包

引用封装jar
在目录下创建一个lib文件夹,将jar包放进去

添加为库

注册数据库驱动
新建一个java文件,类似于php中的连接数据库文件
Class.forName("com.mysql.jdbc.Driver");
|

出现错误时可以用IDEA自动更正

如果存在导包问题,可以直接导入 import java.sql.*;

建立数据库连接
String url = "jdbc:mysql://localhost:3306/dome01";
Connection connection = DriverManager.getConnection(url, "root", "root");
System.out.println(connection);
|
成功连接上

如果密码失败(连接不上的情况)会产生报错

创建Statement执行sql

connection.createStatement();: 在**Connection对象上调用createStatement方法,创建一个Statement对象。Statement对象用于执行SQL语句,它可以执行静态的SQL查询、更新、删除等操作。createStatement方法返回一个新的Statement**对象。
- 创建一个**
Statement对象,然后使用该对象执行给定的SQL查询语句,将查询结果存储在一个ResultSet对象中。这样,您可以通过遍历ResultSet**来检索和处理查询的结果集中的数据。


ResultSet对结果进行提取


和数据库里的内容对应

安全修复SQL注入:JDBC-SQL预编译
原理:提前编译好执行逻辑,你注入的语句不会改变原有逻辑
- 预编译写法:
safesql 是一个预编译的 SQL 查询语句,其中 ? 是一个占位符,表示将在执行时动态替换。
- 使用
PreparedStatement: PreparedStatement 是 Statement 的子接口,用于执行预编译的 SQL 语句。通过调用 connection.prepareStatement(safesql) 创建一个 PreparedStatement 对象。
- 设置参数: 使用
setXXX 方法设置占位符的值。在这里,使用 setInt(1, id) 将 id 的值设置到第一个占位符上。这种方式防止了 SQL 注入攻击,因为参数值是通过预编译的方式传递的,而不是通过直接拼接字符串。
- 执行查询: 调用
executeQuery() 执行查询,得到 ResultSet 对象。
- 处理结果集: 根据业务需要,处理查询结果集的数据。
String safesql = "SELECT * FROM news WHERE id=?";
try (PreparedStatement preparedStatement = connection.prepareStatement(safesql)) { preparedStatement.setInt(1, id);
ResultSet resultSet = preparedStatement.executeQuery();
} catch (SQLException e) { e.printStackTrace(); }
|
相比较于直接拼接 SQL 语句的方式,预编译语句提供了更好的安全性,可以防止SQL注入攻击。在使用预编译语句时,务必通过参数设置的方式传递值,而不要直接拼接值到 SQL 语句中。
过滤器Filter
介绍
Filter被称为过滤器,过滤器实际上就是对Web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,通常都是用来拦截request进行处理的,也可以对返回的 response进行拦截处理。开发人员利用filter技术,可以实现对所有Web资源的管理,例如实现权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
(考虑跟安全相关的-内存马)

简单来说,平常的马是处于Servlet代码层面中,会以代码文件呈现,而内存马处于Listener和Filter层面中


过滤器来进行对xss过滤
TestServlet文件(用于接受参数code,并返回code的值到客户端)
package com.example.filterdemo1.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/test") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("---------doGet"); String code=req.getParameter("code"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out=resp.getWriter(); out.println("这是GET请求的数据"); out.println("code: "+code+"<br>"); out.flush(); out.close(); } }
|
XssFilter文件(实现Filter接口中的方法)
package com.example.filterdemo1.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @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 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("xss正在过滤"); HttpServletRequest request= (HttpServletRequest) servletRequest; String code = request.getParameter("code"); if(!code.contains("<script>")){ filterChain.doFilter(servletRequest,servletResponse); }else{ System.out.println("存在XSS攻击"); } } }
|
要注意这里的TestServlet和XssFilter的路由不同,一个是@WebServlet(“/test”),一个是@WebFilter(“/test”)
中间件启动后会自动运行init,所以控制台输出xss开启过滤

TestServlet的访问路由为test,访问test文件,触发doFilter方法,控制台打印xss正在过滤

当我们GET方式传递code参数=1,先调用filter再调用Servlet,所以先调用XssFilter中的doFilter方法,打印xss正在过滤;再调用TestServlet中的doGet方法,控制台打印———–doGet

当我们GET方式传递code=<script>alert(1)</script>攻击代码,由于XssFilter中检测到了<script>关键字,触发过滤,打印存在XSS攻击

由于XssFilter中没有放行,因此TestServlet中的doGet方法不会被调用

当我们停止时,自动调用了XssFilter中的destroy方法

过滤器实现cookie身份验证
检测客户端的cookie的user值是否为admin
AdminServlet文件
package com.example.filterdemo1.servlet;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;
@WebServlet("/admin") public class AdminServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎进入管理员页面"); } }
|
AdminFilter文件
package com.example.filterdemo1.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @WebFilter("/admin") public class AdminFilter 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身份检测进行"); HttpServletRequest request= (HttpServletRequest) servletRequest; Cookie[] cookies=request.getCookies(); for(Cookie c:cookies){ String cName = c.getName(); String cValue = c.getValue(); System.out.println(cName); System.out.println(cValue); if(cName.contains("user") && cValue.contains("admin")){ filterChain.doFilter(servletRequest,servletResponse); }else { System.out.println("非管理员访问"); } } } }
|
开启中间件服务,调用init方法,admin身份检测开启;当我们GET访问admin时,经过AdminFilter过滤,打印我们的cookie的name和value,并且过滤name不为user,value不为admin,拦截,打印非管理员访问

当我们添加cookie为user:admin,成功执行,进入管理员页面

内存马技术
这里只做简单了解

内存马实验:
哥斯拉生成java的后门1.jsp

用哥斯拉连接url http://localhost:8080/FilterDemo1_war_exploded/1.jsp
从而拿到shell

这里的FilterShell就为内存马
监听器Listen
介绍
监听ServletContext、HttpSession、ServletRequest等域对象创建和销毁事件
监听域对象的属性发生修改的事件
监听在事件发生前、发生后做一些必要的处理
监听器就是用来检测的的动作,有动作就会触发监听器里的方法,不是一定要访问路由才能触发;当与监听器关联的特定事件在Web应用中发生时,监听器会被触发
监听session的创造与销毁
ListenSession文件
package com.example.listendemo1.listener; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; @WebListener public class ListenSession implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("监听器监听到了session创建"); } @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("监听器监听到了session销毁"); } }
|
CSession文件(创建session)
package com.example.listendemo1.Servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; @WebServlet("/cs") public class CSession extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet里面创建Session"); req.getSession(); } }
|
DSession文件(销毁session)
package com.example.listendemo1.Servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/ds") public class DSession extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet里面销毁Session"); req.getSession().invalidate(); } }
|
启动时监听器监听到了, ListenSession中的sessionCreated方法就会被调用,打印监听器监听到了session创建

当我们访问cs,调用了Servlet中CSession中的doGet方法,打印Servlet里面创建Session

当我们访问ds,调用Servlet中DSession中的doGet方法,打印Servlet里面销毁Session,同时监听器马上就监听到了这一属性的变化,ListenSession中的sessionDestroyed方法被调用

