将安全数据放在Java Web应用程序中

时间:2015-06-16 09:05:52

标签: java security tomcat

问题是关于tomcat的安全性,但首先考虑以下示例:

假设你有apache web服务器。然后,在www文件夹下,创建名为dist的文件夹,并在文件夹dist下创建名为bdf23b1c-ddd3-4d5b-8fdf-948693674011的文件夹。在此文件夹下创建一些包含安全信息的文件:

www/dist/bdf23b1c-ddd3-4d5b-8fdf-948693674011/pic.png

这显然是个坏主意,因为任何用户都可以转到yoursite.com/dist并查看此文件夹中包含的所有内容。

另一方面,假设情况相同,但在tomcat web应用程序中创建了文件夹dist。如果您的web.xml中包含以下内容:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/dist/*</url-pattern>some java tool from outside
</servlet-mapping>

然后你可以使用它的URL安全地下载pic.png。如果你去yoursite.com/dist,那么默认情况下tomcat不会显示你这个文件夹的内容。

但我的问题是:它是如何安全的?也许你可以使用服务器外部的一些java工具连接到tomcat并以某种方式确定你宝贵数据的完整路径?我知道java中的安全性,它将是最终的解决方案,但我不想在这里进行任何基于密码的身份验证。

UPD#1:如果存在某些此类漏洞(与外部或其他任何Java工具连接),请在此处发布。假设使用我们的应用程序替换ROOT应用程序的默认tomcat安装。也许对server.xml进行一些调整以禁止“恶意java工具”的不需要的连接?

顺便说一句,我已经设置了防火墙,拒绝除http,https和ssh之外的所有网站流量。

UPD#2:正如我在评论中提到的,我想为Dropbox功能创建最便宜的替代方案。我不想使用密码,因为它对我们的客户来说很不方便(我们希望为客户提供游戏的预发布访问权限)

5 个答案:

答案 0 :(得分:3)

您正在做的是&#34; security through obscurity&#34;。

但实际上它会“工作”#34;只有知道该URL的人才能下载该文件,只要您确保目录列表一直被拒绝,并且该文件的链接不存在于Google等网络浏览器可以获取的位置。并且没有人会扫描与您的gf共享链接的媒体。

这绝对不是完全安全的,取决于你想要分享的数据类型,我会选择不同的解决方案......

答案 1 :(得分:3)

首先,您可以将Apache配置为不显示目录内容(我很惊讶它显然(显然)),因此这里不需要Tomcat。 / p>

至于从外面连接到Tomcat,你不会允许那是你吗?当你去上班时,你不会把你的前门解锁。

最后,用户必须猜测路径(并且足够关心那里的内容),所以它不太可能泄漏(除非你必须小心关于像Marged指出的网络玩家一样。)

但是,您可以在Apache中配置基本身份验证,而不是依赖于长时间的神秘路径。这样你就不用担心Tomcat或Java了。

答案 2 :(得分:2)

使用servlet本身不会生成任何内容secure。您不需要Java工具来连接,您甚至可以使用Telnet,任何脚本语言或创建自己的套接字。只需使用某个地方的下载servlet,至少Basic authentication(&#34;信息隐藏&#34;没有安全方面;)。

  

&#34;我想为Dropbox功能创建最便宜的替代方案......&#34;

然后使用WebDav。 Apache WebServer已经准备好共享和保护数据的模块。我想没有类似DropBox的客户端,但是你可以让你的客户端连接到共享文件夹或其他东西。

答案 3 :(得分:1)

我喜欢Stefan Lindenberg关于WebDav用法的评论,我一定会仔细研究它。但我无法抗拒重新发明轮子,所以我设法创建了这个简单的Java解决方案,这为我的安全性增加了更多的默默无闻。 :)对于这一小段代码的任何评论和批评,我将不胜感激。

package com.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author Anton P. Kolosov
 */
public class ObscureSecureServlet extends HttpServlet {

    private static final Pattern UUID_PATTERN = Pattern.compile("^[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}$", Pattern.CASE_INSENSITIVE);
    private String basePath;

    /**
     * Initialization routines
     * @param config Servlet configuration
     * @throws ServletException
     */
    public void init(ServletConfig config) throws ServletException {

        super.init(config);

        basePath = config.getInitParameter("basePath");
    }

    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String res = request.getParameter("res");
        String name = request.getParameter("name");
        Matcher matcher = UUID_PATTERN.matcher(res);
        if (matcher.matches()) {
            // Only UUIDs are allowed for res parameter
            File file = new File(basePath + "/" + res, name);
            if (file.exists()) {
                sendFile(file, request, response);
                return;
            }
        }

        // Can redirect to jsp if you wish...
        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>File not found</title>");            
            out.println("</head>");
            out.println("<body>");
            out.println("File for res = " + res + " and name = " + name + " was not found!");
            out.println("</body>");
            out.println("</html>");
        }
    }

    private void sendFile(File file, HttpServletRequest request, HttpServletResponse response) throws IOException {
        long fileSize = file.length();
        response.setHeader("Content-length", Long.toString(fileSize));
        response.setContentType("application/octet-stream");
        response.setHeader( "Content-Disposition", "filename=\"" + file.getName() + "\"" );
        ServletOutputStream out = response.getOutputStream();
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out);

        write(file, bufferedOutputStream);
        bufferedOutputStream.flush();
    }

    /**
     * Writes a document to the passed stream.
     * @param bufferedOutput The method writes name to this output stream
     * @throws IOException IOException
     */
    public void write(File file, BufferedOutputStream bufferedOutput) throws IOException {
        byte buffer[] = new byte[1024 * 4];
        BufferedInputStream  bufferedInput = null;
        try {
            FileInputStream inputStream = new FileInputStream(file);
            bufferedInput = new BufferedInputStream(inputStream);
            int lengthRead = 0;
            int offset = 0;
            while (true) {
                lengthRead = bufferedInput.read(buffer, 0, buffer.length);
                if (lengthRead == -1) {
                    break;
                }

                bufferedOutput.write(buffer, 0, lengthRead);
                offset += lengthRead;
            }
        } finally {
            if (bufferedInput != null) {
                bufferedInput.close();
            }
        }
    }


    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Servlet for 'obscure secure' file retrieving";
    }// </editor-fold>

}

答案 4 :(得分:0)

通过考虑你能想象到的东西,安全无效,这完全取决于攻击者可以想象的内容。攻击你的计划的一些方法:

  • 您的计算机或您女朋友的计算机可能感染了一个木马,该木马共享您与攻击者一起访问的每个网址
  • 如果您通过邮件将URL提供给您的女朋友,攻击可以拦截邮件并阅读链接,除非它已加密。国家安全局现在就这样做了,顺便说一句。
  • 如果您没有使用SSL(https://),所有数据都将通过互联网发送,服务器和浏览器之间的任何人都可以看到您正在做的事情(并保存图像副本) )。国家安全局就是这么做的。
  • 您的浏览器可能会在您键入时与浏览器供应商共享您的URL。例如,Chrome会执行此操作,除非您正确配置隐私选项。
  • 如果有人控制了您的服务器,他们就可以在硬盘上看到该文件。
  • 如果您使用的是有缺陷的SSH版本,攻击者可能会破坏您的服务器并随时访问它。

这些只是我自己帽子里的想法。在2015年,通过自己考虑或“聪明”的安全性不再起作用。如果你关心安全问题,你必须投入大量的时间和金钱才能实现安全。