Link Search Menu Expand Document

Mass Assignment in Java

Using GSON

Vulnerable Example

GSON is a serialization/deserialization library that allows for convenient and transparent Java class conversion, to and from their JSON representation, with zero configuration. Developers might be tempted to process user-originated JSON requests with this library to obtain Java objects that ultimately will be passed around in the actual business code. When these intermediate Java objects are also used to hold internal fields, it is easy to forget to implement proper validation mechanisms that prevent a malicious user to mass-assign an internal field.

Imagine having the following class:

class AssetUploadParameters {
    String root = Constants.ASSETS_ROOT; // Some /path/to/assets
    String name;
    String data;
}

Also imagine that such a class is used like this:

public void saveAsset(AssetUploadParameters params) {
    File assetPath = new File(params.root, params.name);

    PrintWriter writer = new PrintWriter(assetPath, "UTF-8");
    writer.print(params.data);
    writer.close();
}

Now assume that the AssetUploadParameters object is created using some user-controlled JSON:

Gson gson = new Gson();
AssetUploadParameters params = gson.fromJson(userControlledJson, AssetUploadParameters.class);

A legit JSON object might look like the following:

{
    "name": "foo.pdf",
    "data": "%PDF-1.5..."
}

A malicious user might exploit this vulnerability to obtain an arbitrary file write privilege on the application server, for example with:

{
    "name": "webshell.jsp",
    "data": "MALICIOUS_CONTENT_HERE",
    "root": "/path/to/webcontent/"
}

Prevention

There are several ways to prevent these kinds of vulnerabilities. Probably the most straightforward way is to create a separation between the user input and the internal data structure so that no contamination is possible; in this case, individual fields are cherry-picked. This is basically an allow list approach concerning which fields the user can assign. In the above example, this could be implemented as follows:

Gson gson = new Gson();
AssetUploadParameters userParams = gson.fromJson(userControlledJson, AssetUploadParameters.class);

AssetUploadParameters params = new AssetUploadParameters();
params.name = userParams.name;
params.data = userParams.data;

saveAsset(params);

Alternatively, marking a member as transient has the effect of excluding it from the serialization/deserialization process. For example, using this class in the above example resolves the exposure:

class AssetUploadParameters {
    transient String root = Constants.ASSETS_ROOT; // Some /path/to/assets
    String name;
    String data;
}

Yet another option is to demand the allow list approach to the library. In the case of GSON, see ExclusionStrategy.