Hi Aspose,
I’m using Java to generate documents. To be able to do so, I have to pass a Document object and data source to ReportingEngine. I want to ask if there’s any way to access that Document object from the template.
Best regards,
Thai
You can access a Document
instance while building a report by passing the document as yet another data source. In this case, you can access public Document
instance members the same way you do for other data source objects.
However, if your intent is to modify the same document on your own whilte building a report, please be aware that this technique is not officially supported and may not succeed. A recommended way to modify the same document while building a report is using of Template Syntax. If you have a requirement that cannot be fulfilled using template syntax, please share more details, so we could assist you further.
Thanks a lot for your explanation, Ivan. I’ll discuss with my team to see what to do next. I’ll get back to you if further assistance is needed.
Hi @ivan.lyagin,
The reason I asked about accessing a Document
object is that we have a security concern. If someone who writes a template gains access to that object, he can get the application classloader. From the classloader, he can access all classes, and our system will be compromised.
So, my main question is: does Aspose have a way to prevent access to the classloader? If yes, is it built into the library or we’ll need to do something to set it up?
Best regards,
A template author cannot access a Document
instance unless the instance is passed as a data source object.
Actually, a class loader of your application can be obtained from any data source object. Please check the following code:
DocumentBuilder builder = new DocumentBuilder();
builder.write("<<[data.getClass().getClassLoader()]>>");
ReportingEngine engine = new ReportingEngine();
engine.buildReport(builder.getDocument(), new TestClass(), "data");
System.out.println(builder.getDocument().getText().trim());
//-------------------------
public class TestClass {}
LINQ Reporting Engine enables access only to public class members without breaking encapsulation. By looking at public ClassLoader members, I do not see a way to get access to all classes. It is possible only to get access to a class by its name (using ClassLoader.loadClass(...)
, for example), but an intruder would not know the exact name.
If access through reflection is concerned, then it is not possible to call AccessibleObject.setAccessible
within a template (because the method does not return a value), thus access to non-public members of any class including ClassLoader
cannot be obtained.
No, LINQ Reporting Engine does not provide a way to restrict access to a class loader.
To recap, the engine’s functionality is limited - it is not pure Java. So even if a template author gets access to a class loader, there is not much that they can do with it using a template.
If you still have a concern regarding the matter, please feel free to share it for further consideration.
Hi @ivan.lyagin,
Thanks for the clarification.
Yes, we’re aware of that issue, so we plan not to provide a normal Java object, but rather a JSON string. That way, the template will have access to the bootstrap classloader only, which won’t see any resources loaded by the application classloader. Is it making us safer?
Yes, this was my concern. Thanks for clearing it up.
I see.
All in all, the question now is can we prevent access to our application code by using JSON strings as the data source? Even in that case, an intruder still has access to the bootstrap classloader. Do we need to do anything to keep it safe?
As a side note, we had a pen test and the tester could do a lot of harmful things, including deleting the template itself. He claimed that he could bring down the whole system or download our application JAR file (is it possible?). We didn’t let him go ahead, but security has become a big concern for us since then.
Regards,
I am afraid, using of JsonDataSource
does not make any difference in your case, because internally, JSON is deserialized into objects. Please check the following code:
DocumentBuilder builder = new DocumentBuilder();
builder.write("<<[data.getClass().getClassLoader()]>>");
String json = "{ property: \"value\" }";
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
ReportingEngine engine = new ReportingEngine();
engine.buildReport(builder.getDocument(), new JsonDataSource(stream), "data");
System.out.println(builder.getDocument().getText().trim());
I am afraid that we cannot comment on actions of third parties, so we cannot know whether the tester was indeed able to compromise your application and whether access to a class loader through a template was indeed an entry point for harmful actions.
However, since security is a big concern of yours, I would suggest using built-in Java capabilities to restrict unwanted activity with your code - SecurityManager. For example, by overriding its checkMemberAccess
method, you can restrict reflective access to members of classes that you consider potentially insecure such as ClassLoader
, Thread
, System
, and so on.
I see method buildReport(Document document, Object[] dataSources, String[] dataSourceNames)
in ReportingEngine
. My idea is to pass an array of String
s to the dataSources
parameter, so the template won’t have access to the application classloader.
In your example, I see System.out.println(builder.getDocument().getText().trim());
, but can I execute it in the template?
The problem is SecuriryManager has been deprecated, and replacement methods haven’t been there yet. If there’s nothing protecting us from potential harm, we feel like going to the battlefield without armor.
Regards,
The example is Java code, it is not intended to be used in a template. If your question is about using of System.out.println(...)
in a template, then it is not possible, because it does not return a value.
Since further destiny of a security mechanism in Java is not clear, we could consider forbidding using of members for a configurable set of types in template expressions to resolve issues like yours. This feature request is logged as WORDSNET-23863. You will be notified through the forum thread, once it is implemented.
Meanwhile, you can use SecurityManager
. Although deprecated, it is still working.
It is to let you know that after Aspose.Words for Java 24.1 is released, you will be able to use the following code to restrict access to type members that you consider insecure:
ReportingEngine.setRestrictedTypes(SomeClass1.class, SomeClass2.class);
Please note that the code must be run once before building the very first report.
The issues you have found earlier (filed as WORDSNET-23863) have been fixed in this Aspose.Words for Java 24.1 update.