首先要提到的是Java Web的第三大组件:Servlet、Filter、Listener,这三个组件在Java Web中提供不同的功能,但对于Java安全来讲,这三个必须要进行了解,因为后续会涉及到这三个组件的使用。

Servlet服务

Servlet是运行在Web服务器或应用服务器上的程序,它是作为来自HTTP客户端的请求和HTTP服务器的数据库或应用程序之间的中间层。它负责处理用户的请求,并根据请求生成相应的返回信息提供给用户。

工作流程

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:

  1. Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第4步,否则,执行第2步。

  2. 装载并创建该Servlet的一个实例对象。

  3. 调用Servlet实例对象的init()方法。

  4. 创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。

  5. WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

创建和使用

创建包名为 com.example.javaweb

创建Servlet

创建一个类继承HttpServlet(以 IndexServlet 为例)

public class IndexServlet extends HttpServlet  {
}

注册Servlet

web.xml

webapp/WEB-INF中的 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"
         metadata-complete="true">
    <servlet>
        <servlet-name>Index</servlet-name>
        <servlet-class>com.example.javaweb.IndexServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Index</servlet-name>
        <url-pattern>/Index</url-pattern>
    </servlet-mapping>
</web-app>

WebServlet
@WebServlet("/Index")
public class IndexServlet extends HttpServlet  {

}

内置方法(常见五种)

调用方法时都是调用最新的(重写情况)

方法

描述

定义

init()

在第一次访问或创建Servlet的时候调用,后续的请求将不会再调用init方法

void init()

service()

是执行实际任务的主要方法,通过service方法来处理来自客户端的请求,并将格式化的响应返回给客户端。(service方法是Servlet中真正用于处理请求的方法,其检查HTTP请求类型,然后调用请求相对应的方法,如doGet()、doPost()等)

void service(HttpServletRequest req, HttpServletResponse resp)

void service(ServletRequest req, ServletResponse res)

doGet()

用于处理Get请求,通常需要重写

void doGet(HttpServletRequest req, HttpServletResponse resp)

doPost()

用于处理Post请求,通常需要重写

void doPost(HttpServletRequest req, HttpServletResponse resp)

destory()

Servlet容器中都是子对象,当修改当前Servlet服务程序的逻辑结构或者顺序时,服务器就会更新(Reloading重新加载程序),这个时候就会执行destory方法,摧毁当前的Servlet子对象,当再次请求这个Servlet时,就会重新执行构造方法。

void destroy()

方法顺序

方法顺序为 init()->[service()->doGet()/doPost()]->destory()

生命周期

ServletLife.png

处理接受和回显

HttpServletRequest方法

HttpServletRequest是ServletRequest的子接口,它有获取一系列传入参数、值的方法,详见:https://www.runoob.com/servlet/servlet-client-request.html

方法

描述

定义

getCookies()

返回客户端发送请求的的所有Cookie对象

Cookie[] getCookies()

getSession()

返回请求关联的当前Session会话;若不存在,则创建一个

HttpSession getSession()

getSession(boolean create)

返回请求关联的当前Session会话;若不存在,且传入的值为真,则创建一个新的Session会话

HttpSession getSession(boolean create)

getLocale()

根据 Accept-Language 头,返回客户端接受内容的首选区域设置

Locale getLocale()

getAuthType()

返回用于保护 Servlet 的身份验证方案的名称。(如:BASIC,SSL等,如果没有返回 null)

String getAuthType()

getCharacterEncoding()

返回请求主体中使用的字符编码的名称

String getCharacterEncoding()

getContentType()

返回请求主体的 MIME 类型,如果无法识别返回 null

String getContentType()

getContextPath()

返回指示请求上下文中的请求URI部分

String getContextPath()

getHeader(String name)

返回指定请求头的值(name 为请求头名称)

String getHeader(String name)

getMethod()

返回请求的HTTP方法名称,如:GET、POST、PUT等

String getMethod()

getParameter(String name)

返回请求参数的值,若参数不存在则返回 null(name 为参数名称)

String getParameter(String name)

getPathInfo()

当请求发出时,返回与客户端发送的 URL 相关的任何额外的路径信息

String getPathInfo()

getProtocol()

返回请求协议的名称和版本

String getProtocol()

getQueryString()

返回在路径后的请求 URL 的查询的字符串

String getQueryString()

getRemoteAddr()

返回发送请求客户端的IP地址

String getRemoteAddr()

getRemoteHost()

返回发送请求客户端的完全限定名称

String getRemoteHost()

getRemoteUser()

如果用户已通过身份验证,返回发出请求的登录用户,反之返回 null

String getRemoteUser()

getRequestURI()

从协议名称直到HTTP请求的第一行查询字符串中,返回请求 URL 的一部分

String getRequestURI()

getRequestedSessionId()

返回由客户端指定的 SessionID

String getRequestedSessionId()

getServletPath()

返回调用 JSP 的请求URL 的一部分

String getServletPath()

getParameterValues(String name)

返回给定参数名称所对应的所有值,若不存在返回 null(name 为参数名称)

String[] getParameterValues(String name)

isSecure()

返回一个布尔值,指示请求是否使用安全通道(如 HTTPS)

boolean isSecure()

getContentLength()

返回请求主体的长度

int getContentLength()

getIntHeader(String name)

返回请求头的值为一个 int 值(name 为请求头名称)

int getIntHeader(String name)

HttpServletResponse方法

HttpServletResponse是ServletResponse的子接口,它有一系列设置、修改返回值的方法,详见:https://www.runoob.com/servlet/servlet-server-response.html

PrintWriter getWriter()

PrintWriter out = resp.getWriter();
// 获取一个 'PrintWriter' 字符输出流输出数据的对象

out.write("Hello Hacker!");
// 在页面上输出 "Hello Hacker!"

Filter过滤器

Filter被称为过滤器,其作用是对Web资源进行拦截,做完一系列的处理后交给下一个Filter或Servlet进行处理,既可以对Request请求进行拦截处理,也可以对Response响应进行拦截修改。

工作流程

web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源(Servlet)。

创建和使用

创建Filter

创建一个HttpFilter类的对象,(以 IndexFilter(对象) 为例)

public class IndexFilter extends HttpFilter {
}

注册Filter

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"
         metadata-complete="true">
    <filter>
        <filter-name>Index</filter-name>
        <filter-class>com.example.javaweb.IndexFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Index</filter-name>
        <url-pattern>/Index</url-pattern>
    </filter-mapping>
</web-app>
WebFilter
@WebFilter("/Index")
public class IndexFilter extends HttpFilter {

}

内置方法

方法

描述

定义

init()

在启动Web程序时,Web服务创建Filter对象,并且调用init方法,完成对象的初始化。

void init()

doFilter()

完成实际过程的方法,客户端请求的路径与Filter的路径相匹配时调用,FilterChain用于访问后续过滤器

void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)

void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain)

destory()

Servlet销毁过滤器实例前调用该方法,用于释放Servlet过滤器占用的资源。

void destroy()

方法顺序

方法顺序为 init()->doFilter()->destory()

生命周期

init()方法:程序启动时调用(创建)

destory():程序停止时调用(摧毁)

doFilter():收到访问请求符合条件调用,并且都会在 doGet()和 doPost()之前;程序第一次运行会在Servlet调用init()后调用。

安全场景

Payload检测,权限访问控制,内存马植入,清理内存马等

内存马参考:https://mp.weixin.qq.com/s/hev4G1FivLtqKjt0VhHKmw

Listener监听器

Listener监听器是用来监听ServletText、HttpSession和ServletRequest等域对象发生修改的事件(如创建,销毁),它可以在事件发生前、后执行一段程序。

监听器类型

根据监听事件的类型可以分成三类:

  • 对象的创建与销毁

  • 对象的属性变更

  • HttpSession 中的对象状态改变

监听对象

事件源

监听器

描述

方法

调用条件

ServletContext

ServletContextListener

用于监听ServletContext对象的创建与销毁

void contextInitialized(ServletContextEvent sce)

ServletContext对象创建

void contextDestroyed(ServletContextEvent sce)

ServletContext对象销毁

HttpSession

HttpSessionListener

用于监听HttpSession对象的创建与销毁

void sessionCreated(HttpSessionEvent se)

HttpSession对象创建

void sessionDestroyed(HttpSessionEvent se)

HttpSession对象销毁

ServletRequest

ServletRequestListener

用于监听ServletRequest对象的创建与销毁

void requestInitialized(ServletRequestEvent sre)

ServletRequest对象创建

void requestDestroyed(ServletRequestEvent sre)

ServletRequest对象销毁

监听属性

事件源

监听器

描述

方法

调用条件

ServletContext

ServletContextAttributeListener

用于监听ServletContext对象的属性变更

void attributeAdded(ServletContextAttributeEvent event)

ServletContext对象中新增一个属性

void attributeRemoved(ServletContextAttributeEvent event)

删除 ServletContext 对象中的一个属性

void attributeReplaced(ServletContextAttributeEvent event)

ServletContext 对象中的一个属性被替换

HttpSession

HttpSessionAttributeListener

用于监听HttpSession对象的属性变更

void attributeAdded(HttpSessionBindingEvent event)

HttpSession对象中新增一个属性

void attributeRemoved(HttpSessionBindingEvent event)

删除 HttpSession 对象中的一个属性

void attributeReplaced(HttpSessionBindingEvent event)

HttpSession 对象中的一个属性被替换

ServletRequest

ServletRequestAttributeListener

用于监听ServletRequest对象的属性变更

void attributeAdded(ServletRequestAttributeEvent srae)

ServletRequest对象中新增一个属性

void attributeRemoved(ServletRequestAttributeEvent srae)

删除 ServletRequest 对象中的一个属性

void attributeReplaced(ServletRequestAttributeEvent srae)

ServletRequest 对象中的一个属性被替换

监听HttpSession状态

事件源

监听器

描述

方法

调用条件

HttpSession

HttpSessionBindingListener

用于监听 JavaBean 对象绑定到 HttpSession 对象和从 HttpSession 对象解绑

void valueBound(HttpSessionBindingEvent event)

当对象被绑定(添加)至 HttpSession 对象中

void valueUnbound(HttpSessionBindingEvent event)

当对象从 HttpSession 对象中解除绑定(移除)

HttpSessionActivationListener

用于监听 HttpSession 对象的活化和钝化过程

void sessionWillPassivate(HttpSessionEvent se)

当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被钝化之前

void sessionDidActivate(HttpSessionEvent se)

当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被活化之后

创建和使用

创建Listener

创建三个类(ListenObject、ListenAttribute、ListenState),实现三种监听器接口(Listener)

// ListenObject 监听对象的创建与销毁
public class ListenObject implements ServletContextListener,
        HttpSessionListener,
        ServletRequestListener {
				}



// ListenAttribute 监听对象属性的变更
public class ListenAttribute implements ServletContextAttributeListener,
        HttpSessionAttributeListener,
        ServletRequestAttributeListener {
				}



// ListenState 监听对象状态的变化
public class ListenState implements HttpSessionBindingListener,
        HttpSessionActivationListener {
        }

注册Listener(以 ListenObject 为例)

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">
    <listener>
        <listener-class>com.example.javaweb.ListenObject</listener-class>
    </listener>
</web-app>

WebListener
@WebListener
public class ListenObject implements ServletContextListener,
        HttpSessionListener,
        ServletRequestListener {
				}

监听器启动顺序

Listener.png

使用场景

常用于统计网站在线人数、系统加载时进行信息初始化、统计网站访问量等等