0

I use Tomcat8/Java

I currently allow sensitive user-generated Excel files (created in Java/POI) to be downloaded from the server by creating a file name with a GUID and then saving it in a publicly available directory, and providing the link for this file.

Stage 1

The User selects various parameters, which the JSP sends to a Java file

String fileName = "excelFiles/"
                + myReports
                        .createExcel(listCompanyDetails);

public static String createExcel(List listCompanyDetails) {
        String fileName = "MyFile"+UUID.randomUUID() + ".xls";
        String fileFullPath="\..."+fileName;
        FileInputStream inputStream = new FileInputStream(new File(APPCodeTable.templateExcelFile));
        Workbook wb=new HSSFWorkbook(inputStream);
        FileOutputStream out = new FileOutputStream(fileFullPath);
        wb.write(out);
        out.close();
}

Stage 2

The JSP then displays the file in an iFrame

<iframe id="target_upload" name="target_upload" width="100%"
src="<%=fileName%>" height="100%"></iframe>

The results of a Penetration Test done on our system said that we should instead produce the file in a stream from a jsp file, and this would be more secure, as it would avoid the use of GUID's, and would avoid having a direct link to the file which would bypass the login authorization.

It seems however that it is better coding practice to use a servlet. For instance Implementing a simple file download servlet.

I was considering saving the document on the server, identified by a GUID, and then passing this GUID to the servlet. However this seems to defeat my original intentions of improving security.

If I implement a simple download servlet (as in the attached link), how can I get my created file inside that servlet?

Community
  • 1
  • 1
gordon613
  • 2,770
  • 12
  • 52
  • 81
  • simply streaming this through a servlet wouldn't seem to address any security issue -- especially since static resources served through Tomcat are already being served up by a servlet (the catalina DefaultServlet). So answering this question requires a better understanding of what the security finding actually is (vs. the finding's proposed solution) – jamey graham Aug 17 '16 at 14:51
  • I updated my question slightly with regard to the security issues – gordon613 Aug 17 '16 at 14:55
  • "however i would still need to save the document on the server"....this statement isn't necessarily true (or the reasoning behind why it would be true isn't clear). If you were actually generating the XLSX "on the fly" (i.e. triggered by an HttpServletRequest), then instead of writing the Workbook out to a FileOutputStream, you'd write it out to HttpServletResponse's outputStream. e.g. new Workbook().write(httpServletResponse.getOutputStream()) There's a little bit more to it than this, but if this approach seems viable i'll write up the details in the form of an answer – jamey graham Aug 17 '16 at 15:17
  • Thanks @jamey graham. I rewrote my question so that it would give you an inkling whether your suggested approach is viable in my particular situation... – gordon613 Aug 17 '16 at 15:49

2 Answers2

0

instead of writing to a file in Stage 1 and reading that file in Stage 2, you can effectively collapse the two steps into 1 by writing the Workbook to HttpServletResponse.getOutputStream().

1. collect user parameters (assuming this is done in a <form>) and POST them targeting the IFRAME. e.g.

 <form action="reportservlet/MyReport.xls" method="POST" target="target_upload">

2. setup a new servlet + mapping (the * mapping allows the MyReport.xls part to be anything..including something you build on the fly when submitting the form).

<servlet>
    <servlet-name>ReportServlet</servlet-name>
    <servlet-class>foo.ReportServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ReportServlet</servlet-name>
    <url-pattern>/reportservlet/*</url-pattern>
</servlet-mapping>

3. in your servlet, something like (ignore "bad design" of business logic in a servlet..this is demonstrative only)

public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws ServletException {
    // all the security stuff and stuff to produce List listCompanyDetails
    FileInputStream inputStream = new FileInputStream(new File(APPCodeTable.templateExcelFile));
    Workbook wb=new HSSFWorkbook(inputStream);
    rsp.setContentType("application/vnd.ms-excel");
    wb.write(rsp.getOutputStream()); // this is the key...write directly to the request output vs. a temp file
}

some commentary..

  1. i'm assuming you're developing for a well-controlled set of users who will be a) using IE and b) have Excel installed - targeting excel content in an IFRAME is a pretty bad idea
  2. definitely don't use a JSP in place of my suggested Servlet - using JSP to produce binary data is just a "bad idea". Its technically possible, but unless you structure your JSP correctly, you're likely to introduce character data (most likely a hard-to-see newline and/or trailing space) that will corrupt the XLS
jamey graham
  • 1,194
  • 1
  • 10
  • 16
  • Thanks. Just came back from holiday - sorry for delay in replying... How would I pass my 'List listCompanyDetails' to the 'doPost' servlet? – gordon613 Aug 28 '16 at 11:25
0

I implemented @wen's answer from Implementing a simple file download servlet

Additionally I removed direct web access to the directory where the files were saved using @Ramesh PVK's suggestion in How to deny web access to a Tomcat directory

<security-constraint>
  <web-resource-collection>
    <web-resource-name >precluded methods</web-resource-name>
    <url-pattern >/excelFiles/*</url-pattern>
    </web-resource-collection>
    <auth-constraint/>
</security-constraint>
Community
  • 1
  • 1
gordon613
  • 2,770
  • 12
  • 52
  • 81