com.thoughtworks.xstream.security.ForbiddenClassException
Asked Answered
B

6

20

I came across this exception while updating xstream (1.4.8) lib to the latest version in one of our web applications. The exception was being thrown in a pojo from a dependent jar that was compiled using an older version of xstream (1.3.1). I recompiled and built the new jar (dependent jar) using the xstream-1.4.8 and deployed the war file again, but still get the same exception. Initially I thought this was due to version mismatch, I'm not sure now whats causing this exception and there's not much documentation online. Any thoughts?

Thanks, Karthik

The actual call that throwing the exception:

TestList list = (TestList)xs.fromXML(new StringReader(testData));

where testData is xml string

TestList.java class

@XStreamAlias("Assets")
public class TestList extends ParentObject {

@XStreamImplicit(itemFieldName = "item")
protected List<Item> item= new ArrayList<Item>();

public void add(Item item) {
item.add(item);
}

public List<Item> getItems() {
    if(item== null)
        return new ArrayList<Item>();
    else
        return item;
}

@Override
public String getStringData() {
StringBuilder builder = new StringBuilder();

for (Item item : items) {
    builder.append(item.getStringData());
    builder.append("---------------\n");
}

return builder.toString();
}

@Override
public String getDataType() {
// TODO Auto-generated method stub
return null;
}

Item.java class:

 @XStreamAlias("Item")
public class Item extends ParentItem {
@XStreamAsAttribute
public String access_test;

@XStreamAsAttribute
public int test_num;

@XStreamAsAttribute
public int test_type;

@XStreamAsAttribute
public boolean tst_item;

@XStreamAsAttribute
public int test_test_est;

@XStreamAlias("eset_test")
public List<Integer> eset_test;

And of course I have the getters and setters that I am not including here.

Exception:

com.thoughtworks.xstream.security.ForbiddenClassException: com.test.cp.test123.pojo.TestList
    at com.thoughtworks.xstream.security.NoTypePermission.allows(NoTypePermission.java:26)
    at com.thoughtworks.xstream.mapper.SecurityMapper.realClass(SecurityMapper.java:74)
    at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
    at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30)
    at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:47)
    at com.thoughtworks.xstream.core.util.HierarchicalStreams.readClassType(HierarchicalStreams.java:29)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:133)
    at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1206)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1190)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1061)
Baronetage answered 12/6, 2015 at 21:16 Comment(1)
Some actual code would be helpful.Justitia
W
25

Using it as a security framework

You need to configure the security framework in XStream.

It is designed to prevent attacks to your deserialization entry point. If you can state that no unfriendly third party will ever use it, you are safe with the solutions provided so far.

I tend to be in the cautious side of the line. So I just allowed the basics, those that are mine, and some I use.

The basics

As stated in other answers, start by using the default

XStream xstream = new XStream();
xstream .addPermission(NoTypePermission.NONE); //forbid everything
xstream .addPermission(NullPermission.NULL);   // allow "null"
xstream .addPermission(PrimitiveTypePermission.PRIMITIVES); // allow primitive types

Those that are mine

These I allowed by package:

xstream.allowTypesByWildcard(new String[] { 
        "com.mydomain.mynewapp.**",
        "com.mydomain.utilitylibraries.**
        });

Some I use

For specific classes that I use, they can be allowed to feed your parser on a "by class" fashion.

xstream.allowTypes(new Class[] {
        com.google.common.base.Present.class,
        org.apache.commons.math3.random.GaussianRandomGenerator.class
        });

To get rid of the exception in the question, the OP may choose to add something like:

xstream.allowTypes(new Class[] {com.test.cp.test123.pojo.TestList.class});

Conclusion

XStream allows you to tune the security of the deserialization of your classes as tight as you want it to be. It probably is enough with the bare minimum. But it is not enough to not ask yourself the question: "how tight need I this security to be?" Once you've reflected about the matter, act accordingly.

Whitewash answered 27/4, 2021 at 17:47 Comment(6)
XStream.setupDefaultSecurity(xstream); is done by default as of 1.4.18Saffier
@Saffier Thanks for the theads up. I addedd a comment in the code snippet to indicate that.Whitewash
@Saffier the method has been deprecated, it's there just for backward compatibility with an empty implementation. From javadoc, This method was a pure helper method for XStream 1.4.10 to 1.4.17. It initialized an XStream instance with a whitelist of well-known and simply types of the Java runtime as it is done in XStream 1.4.18 by default. This method will do therefore nothing in XStream 1.4.18 or higher.Codi
@OlgunKaya If you refer to setupDefaultSecurity it is not in the suggested solution any more. If you refer to other method, please indicate which one.Whitewash
@Whitewash now you need to setup security level based on types, package etc.. there are proper methods in the related classes. On mobile now, so not sure about the exact methods but one can easily check them in javadoc or source itself easily. Xstream.allowTypes ı suppose as per mentioned below comments and answers.Codi
@OlgunKaya As per current documentation (x-stream.github.io/security.html#framework) it is correct to use addPermission(TypePermission), allowTypes(Class[]), and allowTypesByWildcard(String[]) as I suggested in my answer. Although allow(Class) is indeed the basic and main interface method, the facade offers all those convenience methods (and more).Whitewash
R
13

http://x-stream.github.io/security.html

Try to limit to the minimum permissions required.

That would remove all limitations (read link above): xstream.addPermission(AnyTypePermission.ANY);

Rad answered 18/1, 2016 at 18:21 Comment(1)
While this works, it rather defeats the purpose of the new security features.Edile
C
3

I solved my problem using something like:

Class<?>[] classes = new Class[] { TestList.class, Item.class, ... };
XStream xstream = new XStream();
XStream.setupDefaultSecurity(xstream);
xstream.allowTypes(classes);
Cassondra answered 17/10, 2017 at 16:14 Comment(0)
A
3

Following @Kokeb answer, I had a spring bean with the following line of codes:

  XStreamMarshaller marshaller = new XStreamMarshaller();
  Map<String, Class<MyMessage>> aliases = new HashMap<>();
  aliases.put("myMessages", MyMessage.class);
  marshaller.setAliases(aliases);

I added:

 marshaller.getXStream().allowTypes(new Class[]{MyMessage.class});

and it solved the issue.

a bit of context, I was using XStream for a project with spring batch, spring integration and ActiveMQ, I set a bean that converts ActiveMQ messages into a message class. the full bean:

    @Bean
    public MessageConverter messageConverter() {
        XStreamMarshaller marshaller = new XStreamMarshaller();
        Map<String, Class< MyMessage >> aliases = new HashMap<>();
        aliases.put("myMessages", MyMessage.class);
        marshaller.setAliases(aliases);
        marshaller.getXStream().allowTypes(new Class[]{MyMessage.class});

        MarshallingMessageConverter messageConverter = new MarshallingMessageConverter(marshaller);
        messageConverter.setTargetType(MessageType.TEXT);
        return messageConverter;
    }
Aquatic answered 13/12, 2022 at 10:43 Comment(0)
S
2

I also faced this issue and I got the resolution with adding AnyTypePermission,

xstream.addPermission(AnyTypePermission.ANY);
Strew answered 10/3, 2023 at 7:48 Comment(0)
H
0

I have a derived class of XStreamMarshaller, where the "XStreamMarshaller.supports" method is overridden. I added getXStream().allowTypes(classes), see snippet below.

@Override
public boolean supports(Class<?> clazz) {
    Class<?>[] classes = new Class[] {clazz};
    getXStream().processAnnotations(classes);
    getXStream().allowTypes(classes);
    return super. Supports(clazz);
}
Harriman answered 27/10, 2022 at 20:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.