代码之家  ›  专栏  ›  技术社区  ›  Juriy

Tomcat安全静态内容

  •  6
  • Juriy  · 技术社区  · 15 年前

    照片存储在上下文之外的文件夹中。

    我需要做的是执行一些检查时,用户要求的照片,然后如果检查是确定的-服务文件。我想避免做一个轮子,只让tomcat像处理静态文件一样处理图像。你能给我一些建议吗?

    1 回复  |  直到 15 年前
        1
  •  9
  •   Juriy    15 年前

    好的,伙计们。

    在努力解决这个问题之后,我想我终于找到了解决这个问题的办法。首先,看起来问题实际上分解为两个独立的任务。其中一个是保护对某些资源的访问,第二个是从上下文之外的文件夹中提供资源。

    第一个任务很简单,可以通过编写一个挂在“/”上的简单过滤器来解决。

    第二项任务不那么琐碎,但幸运的是也可以解决。Tomcat使用javax.naming.directory.DirContext的实现来加载给定web应用程序的所有资源,包括类文件。它还允许您提供此接口的自定义实现,并在context.xml文件中对其进行配置。默认实现是org.apache.naming.resources.FileDirContext。详情如下: http://tomcat.apache.org/tomcat-6.0-doc/config/resources.html

    我通过简单地扩展FileDirContext创建了自己的DirContext实现。幸运的是,只有一个方法必须被覆盖才能“连接”文件发现。该方法称为file()。

    /**
     * TODO: add javadocs
     *
     * @author Juriy Bura
     */
    public class VirtualFolderDirContext extends FileDirContext {
        private String virtualName;
        private String realName;
    
        private File virtualBase;
        private String absoluteVirtualBase;
    
    
        public VirtualFolderDirContext() {
            super();
        }
    
        public VirtualFolderDirContext(Hashtable env) {
            super(env);
        }
    
        public void setVirtualName(String path) {
            virtualName = path;
        }
    
        public void setVirtualBase(String base) {
            this.realName = base;
            virtualBase = new File(realName);
            try {
                virtualBase = virtualBase.getCanonicalFile();
            } catch (IOException e) {
                // Ignore
            }
            this.absoluteVirtualBase = virtualBase.getAbsolutePath();
        }
    
        protected File file(String name) {
            File file = null;
            boolean virtualFile = name.startsWith(virtualName + "/");
            if (virtualFile) {
                file = new File(virtualBase, name.substring(virtualName.length()));
            } else {
                file = new File(base, name);
            }
    
            if (file.exists() && file.canRead()) {
    
                if (allowLinking)
                    return file;
    
                // Check that this file belongs to our root path
                String canPath = null;
                try {
                    canPath = file.getCanonicalPath();
                } catch (IOException e) {
                }
                if (canPath == null)
                    return null;
    
                // Check to see if going outside of the web application root
                if (!canPath.startsWith(absoluteBase) && !canPath.startsWith(absoluteVirtualBase)) {
                    return null;
                }
    
                // Case sensitivity check
                if (caseSensitive) {
                    String fileAbsPath = file.getAbsolutePath();
                    if (fileAbsPath.endsWith("."))
                        fileAbsPath = fileAbsPath + "/";
                    String absPath = normalize(fileAbsPath);
                    if (canPath != null)
                        canPath = normalize(canPath);
                    if (virtualFile) {
                        if ((absoluteVirtualBase.length() < absPath.length())
                            && (absoluteVirtualBase.length() < canPath.length())) {
                            absPath = absPath.substring(absoluteVirtualBase.length() + 1);
                            if ((canPath == null) || (absPath == null))
                                return null;
                            if (absPath.equals(""))
                                absPath = "/";
                            canPath = canPath.substring(absoluteVirtualBase.length() + 1);
                            if (canPath.equals(""))
                                canPath = "/";
                            if (!canPath.equals(absPath))
                                return null;
                        }                   
                    } else {
                        if ((absoluteBase.length() < absPath.length())
                            && (absoluteBase.length() < canPath.length())) {
                            absPath = absPath.substring(absoluteBase.length() + 1);
                            if ((canPath == null) || (absPath == null))
                                return null;
                            if (absPath.equals(""))
                                absPath = "/";
                            canPath = canPath.substring(absoluteBase.length() + 1);
                            if (canPath.equals(""))
                                canPath = "/";
                            if (!canPath.equals(absPath))
                                return null;
                        }
                    }
                }
    
            } else {
                return null;
            }
            return file;
    
        }
    }
    

    <?xml version="1.0" encoding="UTF-8"?>
    <Context antiResourceLocking="true" antiJARLocking="true">
    
        <Resources
                className="com.juriy.tomcat.virtualdir.VirtualFolderDirContext"
                virtualName="/upload"
                virtualBase="c:/temp/up">
        </Resources>
        ...
        ...
    

    现在,任何时候用户请求/upload/它都会被解析为c:\temp。使用这种技术,您可以实现从几乎任何位置加载资源:http、共享文件夹、数据库,甚至版本控制系统。所以很酷。

    顺便说一句,我已经花了一整天的时间来让这一切一起工作,所以如果你喜欢答案,请不要犹豫,给我你的一票:-)

    干杯