blob: 5b030a7ec58e233636bf58798fdee267065701d1 [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Aliased Files and Symbolic links</title><link rel="stylesheet" type="text/css" href="css/docbook.css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.76.1"><meta name="keywords" content="jetty, servlet-api, cometd, http, spdy, eclipse, maven, java, software"><link rel="home" href="index.html" title="Jetty : The Definitive Reference"><link rel="up" href="configuring-security.html" title="Chapter&nbsp;6.&nbsp;Configuring Security"><link rel="prev" href="configuring-form-size.html" title="Limiting Form Content"><link rel="next" href="configuring-security-secure-passwords.html" title="Secure Password Obfuscation"><link xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" rel="shortcut icon" href="images/favicon.ico"><script type="text/javascript" src="js/shCore.js"></script><script type="text/javascript" src="js/shBrushJava.js"></script><script type="text/javascript" src="js/shBrushXml.js"></script><script type="text/javascript" src="js/shBrushBash.js"></script><script type="text/javascript" src="js/shBrushJScript.js"></script><script type="text/javascript" src="js/shBrushSql.js"></script><script type="text/javascript" src="js/shBrushProperties.js"></script><script type="text/javascript" src="js/shBrushPlain.js"></script><link type="text/css" rel="stylesheet" href="css/shCore.css"><link type="text/css" rel="stylesheet" href="css/shThemeEclipse.css"><link type="text/css" rel="stylesheet" href="css/font-awesome.min.css"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times"><tr><td style="width: 25%"><a href="http://www.eclipse.org/jetty"><img src="images/jetty-header-logo.png" alt="Jetty Logo"></a><br><span style="font-size: small">
Version: 9.0.6.v20130930</span></td><td style="width: 50%"><script type="text/javascript"> (function() {
var cx = '016459005284625897022:obd4lsai2ds';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script><gcse:search></gcse:search></td></tr></table><div xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Aliased Files and Symbolic links</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="configuring-form-size.html"><i class="icon-chevron-left"></i> Previous</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;6.&nbsp;Configuring Security<br><a accesskey="p" href="index.html"><i class="icon-home"></i> Home</a></th><td width="20%" align="right">&nbsp;<a accesskey="n" href="configuring-security-secure-passwords.html">Next <i class="icon-chevron-right"></i></a></td></tr></table><hr></div><div xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" class="jetty-callout"><h5 class="callout"><a href="http://www.webtide.com/support.jsp">Contact the core Jetty developers at
<span class="website">www.webtide.com</span></a></h5><p>
private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ...
scalability guidance for your apps and Ajax/Comet projects ... development services from 1 day to full product delivery
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="serving-aliased-files"></a>Aliased Files and Symbolic links</h2></div></div></div><div class="toc"><dl><dt><span class="section"><a href="serving-aliased-files.html#d0e4114">Good Security Practise</a></span></dt><dt><span class="section"><a href="serving-aliased-files.html#file-alias-detection">Alias detection</a></span></dt><dt><span class="section"><a href="serving-aliased-files.html#file-alias-serving">Serving Aliases and Symbolic Links</a></span></dt></dl></div><p>Web applciations will often server static content from the file system provided by the operating system running
underneatth the JVM. However because file systems often implement multiple aliased names for the same file, then
security constraints and other servlet URI space mappings my inadvertantly be bypassed by aliases.</p><p>I key example of this is case insensitivety and 8.3 names implemented by the Windows File system. If a file
within a webapplication called <code class="code">/mysecretfile.txt</code> is protected by a security constraint on the URI <code class="code">
/mysecretfile.txt</code>, then a request to <code class="code">/MySecretFile.TXT</code> will not match the URI constraint because
URIs are case sensitive, but the windows file system will report that a file does exist at that name and it will be
served despite the security constraint. Less well known than case insensitivity is that windows files systems also
support <a class="link" href="http://en.wikipedia.org/wiki/8.3_filename" target="_top">8.3 filenames</a> for compatibility with legacy
programs. Thus a request to a URI like <code class="code">/MYSECR~1.TXT</code> will again not match the security constraint, but
will be reported as an existing file by the file system and served.</p><p>There are many examples of aliases, not just on windows:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>OpenVMS support file versionig so that <code class="code">/mysecret.txt;N</code> refers to version N of <code class="code">
/mysecret.txt</code> and is essentially an alias.</p></li><li class="listitem"><p>The clearcase software configuration management system provides a file system where @@ in a file name is an
alias to a specific version.</p></li><li class="listitem"><p>The unix files system supports <code class="code">/./foo.txt</code> as and alias for <code class="code">/foo.txt</code></p></li><li class="listitem"><p>Many JVM implementations incorrectly assume the null character is a string terminator, so that a file name
resulting from <code class="code">/foobar.txt%00</code> is an alias for <code class="code">/foobar.txt</code></p></li><li class="listitem"><p>Unix symbolic links and hard links are a form of aliases that allow the same file or directory to have
multiple names.</p></li></ul></div><p>In addition, it is not just URI security constraints that can be bypassed. For example the mapping of the URI
pattern <code class="code">*.jsp</code> to the JSP Servlet may be bypassed by an a request to an alias like <code class="code">
/foobar.jsp%00</code>, thus rather than execute the JSP, the source code of the JSP is returned by the file
system.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4114"></a>Good Security Practise</h3></div></div></div><p>Part of the problem with aliases is that the standard webapplication security model is to allow all requests
except the ones that are specifically denied by security constraints. A best practise for security is to deny all
requests and to permit only those that are specifically identified as allowable. While it is possible to design web
application security constraints in this style, it can be difficult in all circumstances and it is not the default.
Thus it is important for Jetty to be able to detect and deny requests to aliased static content.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="file-alias-detection"></a>Alias detection</h3></div></div></div><p>It is impossible for Jetty to know of all the aliases that may be implemented by the file system running
beneath it, thus it does not attempt to make any specific checks for any know aliases. Instead jetty detects
aliases by using the canonical path of a file. If a file resource handled by jetty has a canonical name that
differs from the name used to request the resource, then Jetty determines that the resource is an aliased request
and it will not be returned by the <code class="code">ServletContext.getResource(String)</code> method (or similar) and thus
will not be served as static content nor used as the basis of a JSP.</p><p>This if Jetty is running on a windows operation system, then a file called <code class="code">/MySecret.TXT</code> will
have a cannonical name that exactly matches that case. So while a request to <code class="code">/mysecret.txt</code> or <code class="code">
/MYSECR~1.TXT</code> will result in a File Resource that matches the file, the different canonical name will
indicate that those requests are aliases and they will not be served as static content and instead a 404 response
returned.</p><p>Unfortunately this approach denies all aliases, including symbolic links, which can be useful in assembling
complex web applications.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="file-alias-serving"></a>Serving Aliases and Symbolic Links</h3></div></div></div><p>Not all aliases are bad nor should be seen as attempts to subvert security constratints. Specifically
symbolic links can be very useful when assembling complex web applications, yet by default Jetty will not serve
them. Thus Jetty contexts support an extensible AliasCheck mechanism to allow aliases resources to be inspected an
conditionally served. In this way, "good" aliases can be detected and served. Jetty provides several utility
implementations of the AliasCheck interface as nested classes with ContextHandler:</p><div class="variablelist"><dl><dt><span class="term">ApproveAliases</span></dt><dd><p>Approve all aliases (USE WITH CAUTION!).</p></dd><dt><span class="term">ApproveSameSuffixAliases</span></dt><dd><p>Approve Aliases with same suffix. Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would
be approved because both the resource and alias end with ".html".</p></dd><dt><span class="term">ApprovePathPrefixAliases</span></dt><dd><p>Approve Aliases with a path prefix. Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html
would be approved because both the resource and alias end with "/foobar.html".</p></dd></dl></div><p>An application is free to implement its own Alias checking. Alias Checkers can be installed in a context via
the following XML used in a context deployer file or <code class="code">WEB-INF/jetty-web.xml</code>:</p><div class="informalexample"><script type="syntaxhighlighter" class="brush: xml;toolbar: false">
<![CDATA[
...
<!-- Allow directory symbolic links -->
<Call name="addAliasCheck">
<Arg>
<New class="org.eclipse.jetty.server.handler.ContextHandler$ApprovePathPrefixAliases"/>
</Arg>
</Call>
<!-- Allow file symbolic links -->
<Call name="addAliasCheck">
<Arg>
<New class="org.eclipse.jetty.server.handler.ContextHandler$ApproveSameSuffixAliases"/>
</Arg>
</Call>
]]>
</script></div></div></div><script type="text/javascript">
SyntaxHighlighter.all()
</script><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="configuring-form-size.html"><i class="icon-chevron-left"></i> Previous</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="configuring-security.html"><i class="icon-chevron-up"></i> Top</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="configuring-security-secure-passwords.html">Next <i class="icon-chevron-right"></i></a></td></tr><tr><td width="40%" align="left" valign="top">Limiting Form Content&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html"><i class="icon-home"></i> Home</a></td><td width="40%" align="right" valign="top">&nbsp;Secure Password Obfuscation</td></tr></table></div><p xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times"><div class="jetty-callout">
See an error or something missing?
<span class="callout"><a href="http://github.com/jetty-project/jetty-documentation">Contribute to this documentation at
<span class="website"><i class="icon-github"></i> Github!</span></a></span><span style="float: right"><i>(Generated: 2013-10-30T13:20:21-05:00)</i></span></div></p><script xmlns:jfetch="java:org.eclipse.jetty.xslt.tools.JavaSourceFetchExtension" xmlns:fetch="java:org.eclipse.jetty.xslt.tools.SourceFetchExtension" xmlns:d="http://docbook.org/ns/docbook" xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0" xmlns:xslthl="http://xslthl.sf.net" xmlns:gcse="http://www.google.com" xmlns:date="http://exslt.org/dates-and-times" type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1149868-7']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script></body></html>