java安全(4)JavaWeb 三大件 + Tomcat 架构梳理

一点闲话:

学java安全一周:什么?反序列化?学一下,readObject,还有好多链子…挨个看一遍不就结了?我甚至还把 tomcat 所有 nday 都复现过一遍,java安全也不难啊?不过如此

学java安全一月:内存马?学一下,ServletContext、呃…(陌生名词轰炸中),文章怎么也看不懂我嘞个,搜索 javaweb 入门,全是研发这块撸项目的也看不动啊…艰难学习中,我承认我之前太大声了(

学java安全一年:不知道,还没到一年呢,其实一个月都没有,只有两三周吧大概,也差不多一月就是了,甚至攻防都只刚刚入门了两个月左右,刚刚开始撸 java 安全这块,在这之前还喜欢云安全(

闲话到此为止了,进入正题!

javaweb 三大组件:listener filter servlet

想必对 tomcat 的那些漏洞熟悉的师傅们不会对三大组件陌生,CVE-2020-1938 的 http 和 ajp 的 connector,还有 CVE-2017-12615 那个处理 jsp 的 servlet,如数家珍了属于是

Servlet

一句话概括:后端处理请求的接口

介于请求和后端数据库或者应用程序之间的中间层

处理请求的过程

客户端发起 http 请求,get 类型请求

Servlet容器接收到请求,根据请求的信息,封装成 HttpServletRequest 和 HttpServletResponse 对象

Servlet 容器调用 HttpServlet 的 init() 方法,只在第一次请求的时候被调用

Servlet 容器调用 service() 方法

service() 方法会根据请求类型,这里是get类型,分别调用 doGet 或者 doPost 或者别的,这里调用 doGet 方法

doXXX方法中写着软件应用实现的业务逻辑

业务逻辑处理完成之后,再返回给Servlet容器,然后容器将结果返回给客户端

容器关闭时候,会调用 destory 方法

生命周期

  1. 服务启动时(需要 web.xml 中配置 load-on-startup=1)或者第一次请求该 servlet 时,就会初始化一个 Servlet 对象
  2. servlet对象去处理请求
  3. 服务关闭时,销毁 servlet 对象,调用 destroy() 方法
  4. JVM 进行垃圾回收

配置内容

web.xml

<servlet>
    <servlet-name>EvilServlet</servlet-name>
    <servlet-class>com.example.filtershell.EvilServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>EvilServlet</servlet-name>
    <url-pattern>/evil</url-pattern>
</servlet-mapping>

懒得配置也可以在写好 Servlet 实现之后加一条 @WebServlet 在头上,更快捷

实现示例:

package org.web;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;


public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<h1>Hello, I'm a Servelt!</h1>");

    }
}

Servlet 主要涉及到的三个方法:

  • init(ServletConfig config): Servlet 初始化时调用,正常情况下用于读取配置信息和初始化资源。每个 Servlet 实例只会被初始化一次。
  • service(ServletRequest req, ServletResponse res): Servlet 处理请求的核心方法。对于 HTTP 请求,通常会调用 HttpServlet 的 doGet、doPost 等方法。
  • destroy(): Servlet 销毁时调用,用于释放资源。每个 Servlet 实例只会被销毁一次。

Filter

一句话概括:在请求到达 servlet 之前做过滤,偏向安全性的组件

处理请求的过程

Filter 是实现了特殊接口的 java 类,和 servlet 类似,也是由 servlet 容器进行调用和执行的

要在 web.xml 注册了 Filter 来对某个 servlet 起作用才可以

当 servlet 容器开始调用某个 servlet 程序的时候,当已经注册了 filter ,那就不会再直接调用 Servlet 的 service 方法,而是调用 Filter 的 doFilter 方法,之后再决定要不要来激活目标 service 方法

Filter.doFilter 方法中不直接 Servlet 的 service 方法,而是调用 FilterChain.doFilter 方法来激活,FilterChain 对象是调用 Filter.doFilter 的时候通过参数传参进来的

在 Filter.doFilter 中调用 FilterChain.doFilter 方法的时候前后增加语句可以在 Servlet 响应前后实现一些特殊功能

如果在 Filter.doFilter 方法没有调用 FilterChain.doFilter 则 Servlet 的 service 不被激活,不调用,这个请求也就被拦下了,通过如此可以达到组织非法请求的作用

生命周期

  1. web 应用程序启动时,web 服务器将创建 Filter 的实例对象,并调用其init方法,读取 web.xml 配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter 对象只会创建一次,init 方法也只会执行一次) 开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象 (内存马涉及重点内容)
  2. Filter 对象创建后会驻留在内存,当 web 应用移除或服务器停止时才销毁,调用 destroy(),该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源
  3. filterChain 当多个 filter 同时存在的时候,组成了 filter 链。web 服务器根据 Filter 在 web.xml文件中的注册顺序,决定先调用哪个Filter。当第一个 Filter 的 doFilter 方法被调用时,web 服务器会创建一个代表 Filter 链的 FilterChain 对象传递给该方法,通过判断 FilterChain 中是否还有 filter 决定后面是否还调用 filter

配置内容

在 web.xml 中,如下配置 filter

<filter>
    <filter-name>EvilFilter</filter-name>   //过滤器名称
    <filter-class>com.example.filtershell.EvilFilter</filter-class>        //过滤器对应的具体实现的类
</filter>

<filter-mapping>
    <filter-name>Evilfilter</filter-name>
    <url-pattern>/test</url-pattern>    //触发filter的路由
</filter-mapping>

对应的具体实现类的格式:

public class EvilFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化成功");
    }

    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException, ServerletException {
        System.out.println("开始处理请求");
    }

    public void destroy() {
        System.out.println("资源被释放");
    }
}

实现了 init,doFilter,destroy 三大方法

内存马的核心部分在 doFilter 里面

Listener

一句话概括:事件发生时执行特定操作,管理生命周期

感觉很类似于 hook (钩子)

功能

JavaWeb开发中的监听器(Listener)就是Application、Session和Request三大对象创建、销毁或者往其中添加、修改、删除属性时自动执行代码的功能组件

ServletContextListener:对Servlet上下文的创建和销毁进行监听

ServletContextAttributeListener:监听Servlet上下文属性的添加、删除和替换

HttpSessionListener:对Session的创建和销毁进行监听。Session的销毁有两种情况,一个中Session超时,还有一种是通过调用Session对象的invalidate()方法使session失效

HttpSessionAttributeListener:对Session对象中属性的添加、删除和替换进行监听

ServletRequestListener:对请求对象的初始化和销毁进行监听

ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听

用途

可以使用监听器监听客户端的请求、服务端的操作等。通过监听器,可以自动出发一些动作,比如监听在线的用户数量,统计网站访问量、网站访问监控等。

配置内容

web.xml

<listener>
  <listener-class>com.example.MyServletContextListener</listener-class>
</listener>

与过滤器(Filter)和 Servlet 不同,Listener 不需要定义访问路由。服务器部署完成后,定义的类会自动被触发

public void requestDestroyed(ServletRequestEvent sre) {
    //请求结束时的处理,可以为空
}

public void requestInitialized(ServletRequestEvent sre) {
    try {
        //获取请求对象
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        //获取cmd参数
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
        //执行命令
            Process process = Runtime.getRuntime().exec(cmd);
            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }
        }
    }
}

上述例子配置的功能:

  • requestInitialized(ServletRequestEvent sre):此方法在每个 HTTP 请求开始时触发,如果 cmd 参数存在,它将 cmd 的值作为系统命令执行(使用 Runtime.getRuntime().exec())。
  • requestDestroyed(ServletRequestEvent sre):此方法在每个 HTTP 请求结束时调用。

Tomcat

简介

Tomcat 是一个开源的 Java Servlet 容器,由 Apache 软件基金会开发。它实现了 Java Servlet 和 JavaServer Pages (JSP) 规范,用于运行 Java Web 应用程序。Tomcat 提供了 Web 服务器功能,支持 HTTP 协议,能够处理客户端请求并返回响应。它既可以独立运行,也可以作为其他 Web 服务器(如 Apache HTTP Server)的后端应用服务器。

//以上内容来自 kimi ,懒得写介绍了(

从功能的角度简单理解,tomcat 就是 http 服务器 + servlet 容器

Tomcat 作为 Servlet 容器,将 http 请求接收并解析,然后封装成HttpServletRequest 类型的 request 对象,传递给 servlet,同时会将响应的信息封装为 HttpServletResponse 类型的 response 对象,然后将 response 交给 tomcat,tomcat 就会将其变成响应包的格式发送给浏览器

tomcat 的架构设计

一个 tomcat 服务器 = 一个 Server 服务器 = 多个 Service 服务

直观如下图:

img

Tomcat 默认的服务是 catalina ,一个服务会包含多个连接器(CVE-2020-1938就是因为 ajp 协议的连接器产生的问题)不同协议有不同的连接器

一个 Service 服务还会包括一个容器,容器外部会有一层 Engine 包裹,负责与连接器的请求与响应,连接器与容器之间通过 ServletRequest 和 ServletResponse 对象进行交流

一个 Engine 包含多个 Host(虚拟主机),再对应多个 context ,也就是 web应用,再对应多个 Wrapper( Servlet 封装而成的),

这一大堆关系,都在 Mapper 组件里面(图中的大方框)mapper组件保存了Web应用的配置信息,容器组件与访问路径的映射关系。Host容器的域名,Context容器中的web路径

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇