Java安全开发(第一部分)
安全开发-JavaEE应用&Servlet路由技术&JDBC&Mybatis数据库&生命周期1、serverlet是什么?2、创建项目 web程序   javaee 8  3、认识目录4、创建jav 2025-11-20 12:41:2 Author: www.freebuf.com(查看原文) 阅读量:3 收藏

安全开发-JavaEE应用&Servlet路由技术&JDBC&Mybatis数据库&生命周期

1、serverlet是什么?
2、创建项目 web程序   javaee 8  
3、认识目录
4、创建java类文件
5、修改web.xml
(1) 设置名字对应类,设置名字对应映射路径
(2) 也可以直接在页面加入 @WebServlet('/路径')

6、执行顺序和方法
实例化 -- 初始化 -- 服务 -- 销毁
7、获取参数,打印显示
8、设置路由
9、连接数据库
10、预编译语句防止SQL注入的原理 -- 固定逻辑一切均视为参数,即使恶意语句也无法改变查询逻辑


实践:
(1) 成功运行HelloServlet.java文件
(2) 创建一个IndexServlet文件 配置路由,成功启动服务器并访问,输出提示信息'
问题:编码问题
解决方法:System.setOut(new PrintStream(System.out, true, StandardCharsets.UTF_8)); 设置
(3) 编写IndexServlet.java 文件
使用@WebServlet('/a')来直接设置路由
使用doGet、doPost来在页面接收参数并输出数据
接收参数:req.getParameter()
输出数据; PrintWriter out = resp.getWriter(); out.printer();
(4) 通过上方页面执行结果了解
init() -- 初始化
destory() -- 销毁 均只执行一次
service() -- doGet()/doPost()   Servlet service / http Service 后者专门处理http请求,前者处理各种请求

//使用@快捷键即可快速构建下方doget等的框架
package org.example.demo2;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
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.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;


@WebServlet("/a")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("--------------doGet");
String id =req.getParameter("id");

resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("这是GET请求的数据:");
out.println("id:"+id+"<br>");
out.flush();
out.close();
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String name = req.getParameter("name");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("这是post提交的数据");
out.println(name);
out.flush();
out.close();
System.out.println("--------------doPost");


}

@Override
public void init(ServletConfig config) throws ServletException{
System.out.println("--------------init");
//       try {
//           Class.forName("com.example.servletdemo.NewsServlet");
//
//       } catch (ClassNotFoundException e) {
//           throw new RuntimeException(e);
//       }

}

@Override
public void destroy() {
System.out.println("--------------destroy");
super.destroy();
}

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("--------------http service");
super.service(req, resp);
}

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("--------------Servlet service");
super.service(req, res);
}
}

5、使用数据库操作连接并输出数据

(1) 按照数据库.jar包 -- 新建目录lib -- 将.jar包放入 -- 右键目录 -- 设置为库即可
(2) 编写代码,进行数据库连接操作
package org.example.demo2;
import java.sql.*;

public class NewsServlet {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
//添加数据库驱动
String url = "jdbc:mysql://localhost:3306/demo1";
//设置数据库连接
Connection connection = DriverManager.getConnection(url,"root","rooter");
System.out.println(connection);
String sql = "select * from new";
Statement statement = connection.createStatement();
//添加数据库执行语句对象
ResultSet resultSet = statement.executeQuery(sql);
//执行数据库查询
while (resultSet.next()) {
int id = resultSet.getInt("id");
String page_title = resultSet.getString("page_title");
String heading = resultSet.getString("heading");
String subheading = resultSet.getString("subheading");
String content = resultSet.getString("content");
String item = resultSet.getString("item");
System.out.println(id+"|"+page_title+"|"+heading+"|"+subheading+"|"+content+"|" + item);
}
}
}
6、预编译语句可以预防SQL注入
本质原因是 预编译语句提前就定死了执行逻辑,常见的注入payload都是改变了执行逻辑
比如加 and 1=1 就是想要将查询逻辑变为恒真
当使用预编译语句
那么就会将 1 and 1=1 整体作为参数(字段值)代入去查是否有字段名为 1 and 1=1 本质上不会改变执行逻辑,还是查询
总之就是无论输入什么,都会作为参数而不会改变语句执行逻辑

1763642285_691f0bad46601b653e841.png!small

安全开发-JavaEE应用&SQL预编译&Filter过滤器&Listener监听器&访问控制

1、使用不安全写法演示sql注入  1 and 1=1  ||  1 or 1=1
2、使用预编译语句进行防御,进行注入尝试
3、过滤器(访问触发)
过滤器创建 过滤器过滤 XSS 未授权访问
模拟内存马的简单使用
4、监听器(动作触发 -- 比如创建等)
分类:
监听对象创建和销毁的监听器
监听对象中属性变更的监听器
监听HttpSession 中的对象状态改变的监听器
1、通过对原生写法和预编译写法进行SQL注入来测试二者的不同

//不安全的写法
String sql="select * from news where id="+s;       System.out.println(sql);
Statement statement= connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);

//正常运行及SQL注入测试结果如下图

1763642282_691f0baae7bafb2690a34.png!small

1763642279_691f0ba7b07ddf9122e8d.png!small

1763642279_691f0ba7b1de01a10e7c6.png!small

// 预编译写法
String safesql="select * from news where id=?";
PreparedStatement preparedStatement=connection.prepareStatement(safesql);
preparedStatement.setString(1,s);
ResultSet resultSet=preparedStatement.executeQuery();       System.out.println(safesql);

//下面是正常执行的结果

1763642279_691f0ba7af1709434825d.png!small

使用 1 or 1=1 结果任然是查询 id = 1 成功防止了一般的SQL注入攻击

1763642279_691f0ba7b020dab8bbc0a.png!small


2、过滤器的创建及内置方法 以及过滤器内存马

(1)什么是过滤器?
Filter被称为过滤器,过滤器实际上就是对Web资源进行拦截,做一些处理后再交给下一   个过滤器或Servlet处理,通常都是用来拦截request进行处理的,也可以对返回的       response进行拦截处理。开发人员利用filter技术,可以实现对所有Web资源的管理,   例如实现权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

(2)过滤器应用(XSS 和 未授权 过滤器编写)
// 正常接收参数并显示页面
package org.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 {
String code = req.getParameter("code");
PrintWriter out = resp.getWriter();
out.println(code);
out.flush();
//刷新
out.close();
}
}

//当输入XSS所属的payload时 <script>alert(1)</script> -- 存在漏洞

1763642285_691f0bad5e27a3813d5f4.png!small

编写Xss过滤器
过滤器中涉及到的知识点:
init -- 初始化   destory() -- 销毁  doFilter() -- 过滤
filterChain.doFilter(servletRequest,servletResponse); -- 放行
如果不加上方这条语句,那么请求就会被拦截

package org.example.filterdemo1.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
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攻击");
//继续拦截 只要不放行,就不会触发攻击

}
}
}
函数执行顺序 当启动服务器 init()函数就已经启动,访问/test doFilter()函数启动
当关闭服务器时 destory()函数启动

1763642294_691f0bb61955ff72c4923.png!small

效果:当我们再次输入 XSS payload时,不会再弹框了

1763642302_691f0bbe0ab50394b11cd.png!small

/**补充:
问题情况:
当我们在服务器使用的System,out.println()函数输出的中文为乱码,
但是服务器像上面的(已连接到服务器文本)还是正常显示无乱码,解决方法:

【升级到tomcat10和Java 21后,idea控制台system.out.println输出中文乱码问题 - CSDN App】https://blog.csdn.net/weixin_42127613/article/details/139746374?sharetype=blog&shareId=139746374&sharerefer=APP&sharesource=2301_81242582&sharefrom=link

问题:如果在页面传参值为中文,但是页面显示为乱码,建议加上
*/
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
未授权过滤器编写  解决问题:未经登录就可以访问后台登录页面
// 正常页面的编写

package org.example.filterdemo1.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AdminServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("欢迎进入管理员页面");
}
}
//注意:mybatis注释不敢加分号在末尾
//过滤器
// 原理很简单就是判断COokie中是否包含所要字段及值
package org.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 AdminFileter implements Filter {
@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();
//获取字段名
String cValue = c.getValue();
//获取相应的值
System.out.println(cName);
System.out.println(cValue);
if (cName.contains("user") && cValue.contains("aedmin")) {
filterChain.doFilter(servletRequest,servletResponse);
}else {
System.out.println("非管理员访问");
}
}
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("admin身份检测开启");
}
}
//效果如下图

1763642310_691f0bc6703d750e6743f.png!small

当对Cookie进行添加后,成功登录

1763642310_691f0bc6926008e6279e3.png!small

3、内存马(过滤器)
操作:使用哥斯拉生成一个后门文件,

1763642314_691f0bca23bd747d52e43.png!small

/**
首先在浏览器进行访问,直接在根目录后跟上/11.jsp 出现空白页即表明成功执行
如图,我们点击Filtershell就是内存马
点击getAllFilter即可获取所有过滤器
当然也可以向内写入
*/

/**
核心答案:WebApp 目录可直接访问的本质原因
WebApp(也常写为webapp/WebContent)是 Java Web 项目的默认 “静态资源根目录”,Tomcat 等 Servlet 容器遵循 Servlet 规范,会将该目录下的文件(HTML/CSS/JS/ 图片等)视为 “可直接对外暴露的静态资源”,无需通过 Servlet/Controller 转发,就能通过 URL 直接访问。

1763642322_691f0bd2bf2dde6546205.png!small

4、监听器 

编写正常的生成session和销毁session页面

//生成session    
package org.example.listendemo1.Servlert;

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("/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();
}
}

//销毁session
package org.example.listendemo1.Servlert;

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");
//销毁session
req.getSession().invalidate();
}
}


//监听器
package org.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) {
//监听检测有session创建就会执行这里
System.out.println("监听器听到了session创建");
}

@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("监听器监听到了session销毁");
}
}

1763642328_691f0bd85ee869329d65d.png!small


文章来源: https://www.freebuf.com/articles/vuls/458283.html
如有侵权请联系:admin#unsafe.sh