boxmoe_header_banner_img

梦中的登神殿,天才的乱葬岗

加载中

文章导读

Java安全开发基础&servlet路由技术&JDBC&Mybatis数据库&生命周期


avatar
RootReapers 2026年2月8日 197

虽然我是真的不想学Java,但是没办法,人总得吃饭吧,光学个php安全

,出去找工作,💩都没得吃啊

打CTF遇到Java就睡大觉,不太行,只能硬着头皮学

干了!

JavaEE-HTTP-Servlet技术

JavaEE-数据库-JDBC&Mybatis

servlet:处理HTTP请求

创建好JavaEE项目之后,直接运行的话效果大概是这样的image

分析一下servlet的作用:定义一个路由,当用户触发时(访问这个路由),页面如何进行输出,输出什么内容

image2

文件访问和路由访问:

文件访问:http://127.0.0.1/test/index.php

这就叫文件访问

表示访问网站根目录下的test文件夹内的index.php文件

这有什么坏处?

容易直接泄露目录内所有文件

当我将index.php作为变量,然后用字典去爆破的时候

根据返回的状态码即可得知有哪些文件存在

路由访问:定义一段代码/一个文件,将其捆绑在一个路由上

比如http://127.0.0.1/route

当访问/route时,默认指向index.php文件/默认输出hello

这样的好处就是防止被目录扫描,攻击者无法直接访问文件,得通过路由关系去访问

http://127.0.0.1/index

http://127.0.0.1/login

http://127.0.0.1/register

http://127.0.0.1/info

诸如此类,都是通过路由访问

例如/login

它的后端可能绑定了一个处理登录逻辑的文件,但是这个文件的文件名是什么,无从得知

大大地降低了安全风险

路由就像一个代号一样

在上网的时候为了不泄露真实姓名,大部分人都会选择用网名代替(不会真有人实名上网吧)

你现实中的朋友知道你的网名,自然也就知道,这个网名代表的就是你

路由就相当于网名,文件名就相当于真名

如何去写一个servlet路由呢?

demo代码,这是一个类,继承HttpServlet,当检测到web通过get访问时就会触发它,但是路由呢?web访问哪里才会触发它

package org.example.xiaodi_javasec;


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;
public class indexServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //super.doGet(request,response);
        System.out.println("get访问的");
    }

}

接下来就是配置路由的第一种方式

打开webapp目录,找到web.xml文件,最开始的时候是这样的

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
</web-app>

配置路由之后是这样的

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>index</servlet-name>
        <servlet-class>org.example.xiaodi_javasec.indexServlet</servlet-class>
    </servlet>
        <servlet-mapping>
            <servlet-name>index</servlet-name>
            <url-pattern>/index</url-pattern>
        </servlet-mapping>

</web-app>

servlet-name:路由名字

servlet-class:路由对应的类

servlet-mapping:路由映射

url-pattern:访问哪里触发org.example.xiaodi_javasec.indexServlet这个类里面的代码

启动后在浏览器访问index路由,回到idea,发现控制台输出了”get访问的“

那如何在网页中输出?

package org.example.xiaodi_javasec;

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;

public class indexServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //super.doGet(request,response);
        String name=request.getParameter("name");
        PrintWriter out=response.getWriter();
        out.println("name:"+name);
        System.out.println("get访问的");
    }

}

首先定义一个String,获取参数为name的值

再利用PrintWriter类进行读取输出到浏览器上进行渲染

(时间充足的话,我建议可以了解一下这些类的底层)

package org.example.xiaodi_javasec;

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;

public class indexServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //super.doGet(request,response);
        String name=request.getParameter("name");
        PrintWriter out=response.getWriter();
        out.println(name);
        System.out.println("get访问的");
    }

}

此时打开浏览器,访问/index路由,对name进行传参,就可以在页面上看到传入的内容,Java代码会把用户传入的东西直接输出到页面上,这里也就是xss(跨站脚本攻击)的造成原因

浏览器的展示逻辑:

用户发请求->浏览器接收并且向后端发送请求->后端处理请求->将内容返回->浏览器接收内容并且解析渲染到页面上->用户看到

问题就出在渲染这一步,浏览器内核负责处理html和css,JavaScript引擎负责处理JavaScript代码

image3

传入正常的文本数据/html标签语句,被内核处理

image4
image5

但是如果传入的内容返回到浏览器时,包含了JavaScript代码呢?

<script>alert(1)</script>

这是JavaScript的语句,触发一个弹窗

image6

代码被成功执行,而不是原样输出到页面,说明传入的内容被JavaScript引擎解析处理

仅仅是弹窗?JavaScript还支持读取cookie以及动态处理页面资源(修改页面文字,处理跳转)等

如果被恶意攻击者利用,那就可以执行任意js代码了

html和css只是负责外观,执行它们,并没有什么大作用

但是js负责的是页面与用户的交互,并且js能够通过dom控制html

任意执行js代码,相当于整个页面的交互都会被控制,你的一举一动都在攻击者的布局之中

浏览器只要遇到<script></script>就会交由JavaScript引擎处理,防护办法也就只有让浏览器接收不到<script></script>

也就是在输出前进行检测,检测用户输入的内容是否含有script,对它们进行\转义,让它们变成普通文本

扯远了点

回到代码

package org.example.xiaodi_javasec;

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;

public class indexServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //super.doGet(request,response);
        String name=request.getParameter("name");
        PrintWriter out=response.getWriter();
        out.println(name);
        System.out.println("get访问的");
    }

}

这是接收GET请求的

主要是doGET起作用,才让代码知道,是接收GET请求

那接收POST呢?就是doPOST了

其他地方不变

刚才介绍了第一种添加servlet的方式(改web.xml),有点麻烦

现在介绍第二种,添加WebServlet注解

package org.example.xiaodi_javasec;

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(name = "new", value = "/new")
public class NewServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //super.doGet(request,response);
        String anew=request.getParameter("anew");
        PrintWriter out=response.getWriter();
        out.println(anew);
        System.out.println("new访问的");
    }
}

@WebServlet(name = “new”, value = “/new”)

显然第二种比较简单便捷

接下来介绍servlet的生命周期

什么是生命周期:

比如人从出生到死亡,就是一个完整的生命周期

servlet也一样,从创建到销毁,一共经历了哪些?

package org.example.xiaodi_javasec;

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.PrintWriter;

@WebServlet(name = "new", value = "/new")
public class NewServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //super.doGet(request,response);
        String anew=request.getParameter("anew");
        PrintWriter out=response.getWriter();
        out.println(anew);
        System.out.println("new访问的");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.service(req, resp);
    }

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        super.service(req, res);
    }
}

分为构造方法(实例化),init(初始化),服务(调用doget、dopost等),消亡(关闭)

重写每个方法,看看它们的运行先后顺序

image7

日志截图(我访问了两次)

可以发现init和destroy只执行一次,其余重复执行

Java与数据库交互

原生JDBC:

第一步:下载导入数据库驱动

https://mvnrepository.com/search?q=MySQL

这里直接下载jar就行

在项目目录下创建一个lib目录,用于存放驱动jar

将MySQL驱动文件放到jar目录,右键,添加为库

第二步:注册MySQL驱动

package org.example.xiaodi_javasec;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class MySelect {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");//通过反射注册驱动
        String url = "jdbc:mysql://localhost:3306/demo01";
        Connection connection= DriverManager.getConnection(url,"root","root" );
    }
}

第三步:创建statement执行SQL语句

package org.example.xiaodi_javasec;

import java.sql.*;

public class MySelect {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");//通过反射注册驱动
        String url = "jdbc:mysql://localhost:3306/数据库名";
        Connection connection= DriverManager.getConnection(url,"root","root" );
        System.out.println(connection);//输出connection反馈连接状态
        String sql= "select * from news";//创建SQL语句
        Statement statement= connection.createStatement();//新建statement
        ResultSet rs=statement.executeQuery(sql);//执行sql语句,存储结果(如果是查询就用query,更新就用update,以此类推)
        while (rs.next()){
        int id = rs.getInt(id);//定义变量存储数据,需要什么类型就get什么类型 
    }
}

SQL预编译:

防止SQL注入

存在注入的语句:select * from users where id=id;

?id=1

?id=1 or 1=1

预编译:select * from users where id=?;

使用?占位

提前把语句的逻辑给编译了,就等传入内容

后面无论再添加什么逻辑,都不会被执行

就像定义好了一个模板,只需要填入数据就能执行



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码