瀏覽代碼

SEC-1584: Documentation of request-checking and matching process. Logging of servletPath and and pathInfo in DebugFilter for comparison.

Luke Taylor 15 年之前
父節點
當前提交
f455e9a5a4

+ 2 - 0
config/src/main/java/org/springframework/security/config/debug/DebugFilter.java

@@ -41,6 +41,8 @@ class DebugFilter extends OncePerRequestFilter {
         List<Filter> filters = getFilters(request);
         logger.log("Request received for '" + UrlUtils.buildRequestUrl(request) + "':\n\n" +
                 request + "\n\n" +
+                "servletPath:" + request.getServletPath() + "\n" +
+                "pathInfo:" + request.getPathInfo() + "\n\n" +
                 formatFilters(filters));
 
         fcp.doFilter(new DebugRequestWrapper(request), response, filterChain);

+ 14 - 11
docs/manual/src/docbook/namespace-config.xml

@@ -142,17 +142,20 @@
                 <literal>&lt;http></literal> element is the parent for all web-related namespace
                 functionality. The <literal>&lt;intercept-url></literal> element defines a
                 <literal>pattern</literal> which is matched against the URLs of incoming requests
-                using an ant path style syntax. You can also use regular-expression matching as an
-                alternative (see the namespace appendix for more details). The
-                <literal>access</literal> attribute defines the access requirements for requests
-                matching the given pattern. With the default configuration, this is typically a
-                comma-separated list of roles, one of which a user must have to be allowed to make
-                the request. The prefix <quote>ROLE_</quote> is a marker which indicates that a
-                simple comparison with the user's authorities should be made. In other words, a
-                normal role-based check should be used. Access-control in Spring Security is not
-                limited to the use of simple roles (hence the use of the prefix to differentiate
-                between different types of security attributes). We'll see later how the
-                interpretation can vary<footnote>
+                using an ant path style syntax<footnote>
+                <para>See the section on <link xlink:href="#request-matching">Request
+                    Matching</link> in the Web Application Infrastructure chapter for more details
+                    on how matches are actually performed.</para>
+                </footnote>. You can also use regular-expression matching as an alternative (see the
+                namespace appendix for more details). The <literal>access</literal> attribute
+                defines the access requirements for requests matching the given pattern. With the
+                default configuration, this is typically a comma-separated list of roles, one of
+                which a user must have to be allowed to make the request. The prefix
+                <quote>ROLE_</quote> is a marker which indicates that a simple comparison with the
+                user's authorities should be made. In other words, a normal role-based check should
+                be used. Access-control in Spring Security is not limited to the use of simple roles
+                (hence the use of the prefix to differentiate between different types of security
+                attributes). We'll see later how the interpretation can vary<footnote>
                 <para>The interpretation of the comma-separated values in the
                     <literal>access</literal> attribute depends on the implementation of the <link
                     xlink:href="#ns-access-manager">AccessDecisionManager</link> which is used. In

+ 96 - 31
docs/manual/src/docbook/web-infrastructure.xml

@@ -55,15 +55,16 @@
         </section>
         <section xml:id="filter-chain-proxy">
             <title><classname>FilterChainProxy</classname></title>
-            <para> It should now be clear that you can declare each Spring Security filter bean that
-                you require in your application context file and add a corresponding
+            <para>Spring Security's web infrastructure should only be used by delegating to an
+                instance of <classname>FilterChainProxy</classname>. The security filters should not
+                be used by themselves In theory you could declare each Spring Security filter bean
+                that you require in your application context file and add a corresponding
                 <classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename>
-                for each filter, making sure that they are ordered correctly. This is a cumbersome
-                approach and clutters up the <filename>web.xml</filename> file quickly if we have a
-                lot of filters. We would prefer to just add a single entry to
-                <filename>web.xml</filename> and deal entirely with the application context file for
-                managing our web security beans. This is where Spring Secuiryt's
-                <classname>FilterChainProxy</classname> comes in. It is wired using a
+                for each filter, making sure that they are ordered correctly, but this would be
+                cumbersome and would clutter up the <filename>web.xml</filename> file quickly if you
+                have a lot of filters. <classname>FilterChainProxy</classname> lets us add a single
+                entry to <filename>web.xml</filename> and deal entirely with the application context
+                file for managing our web security beans. It is wired using a
                 <literal>DelegatingFilterProxy</literal>, just like in the example above, but with
                 the <literal>filter-name</literal> set to the bean name
                 <quote>filterChainProxy</quote>. The filter chain is then declared in the
@@ -89,8 +90,8 @@
                     context XML file in order to use this syntax.</para>
                 </footnote>. It maps a particular URL pattern to a chain of filters built up from
                 the bean names specified in the <literal>filters</literal> element. Both regular
-                expressions and Ant Paths are supported, and the most specific URIs appear first. At
-                runtime the <classname>FilterChainProxy</classname> will locate the first URI
+                expressions and Ant Paths are supported, and the most specific URLs appear first. At
+                runtime the <classname>FilterChainProxy</classname> will locate the first URL
                 pattern that matches the current web request and the list of filter beans specified
                 by the <literal>filters</literal> attribute will be applied to that request. The
                 filters will be invoked in the order they are defined, so you have complete control
@@ -106,18 +107,10 @@
                 <classname>SecurityContextPersistenceFilter</classname> (with its default
                 <literal>allowSessionCreation</literal> as <literal>true</literal>) would likely be
                 sufficient.</para>
-            <para>In relation to lifecycle issues, the <classname>FilterChainProxy</classname> will
-                always delegate <methodname>init(FilterConfig)</methodname> and
-                <methodname>destroy()</methodname> methods through to the underlaying
-                <interfacename>Filter</interfacename>s if such methods are called against
-                <classname>FilterChainProxy</classname> itself. In this case,
-                <classname>FilterChainProxy</classname> guarantees to only initialize and destroy
-                each <literal>Filter</literal> bean once, no matter how many times it is declared in
-                the filter chain(s). You control the overall choice as to whether these methods are
-                called or not via the <literal>targetFilterLifecycle</literal> initialization
-                parameter of <literal>DelegatingFilterProxy</literal>. By default this property is
-                <literal>false</literal> and servlet container lifecycle invocations are not
-                delegated through <literal>DelegatingFilterProxy</literal>.</para>
+            <para>Note that <classname>FilterChainProxy</classname> does not invoke standard filter
+                lifecycle methods on the filters it is configured with. We recommend you use
+                Spring's application context lifecycle interfaces as an alternative, just as you
+                would for any other Spring bean.</para>
             <para> When we looked at how to set up web security using <link
                 xlink:href="#namespace-auto-config">namespace configuration</link>, we used a
                 <literal>DelegatingFilterProxy</literal> with the name
@@ -126,15 +119,15 @@
                 namespace. </para>
             <section>
                 <title>Bypassing the Filter Chain</title>
-                <para> As with the namespace, you can use the attribute <literal>filters =
-                    "none"</literal> as an alternative to supplying a filter bean list. This will
-                    omit the request pattern from the security filter chain entirely. Note that
-                    anything matching this path will then have no authentication or authorization
-                    services applied and will be freely accessible. If you want to make use of the
-                    contents of the <classname>SecurityContext</classname> contents during a
-                    request, then it must have passed through the security filter chain. Otherwise
-                    the <classname>SecurityContextHolder</classname> will not have been populated
-                    and the contents will be null.</para>
+                <para> You can use the attribute <literal>filters = "none"</literal> as an
+                    alternative to supplying a filter bean list. This will omit the request pattern
+                    from the security filter chain entirely. Note that anything matching this path
+                    will then have no authentication or authorization services applied and will be
+                    freely accessible. If you want to make use of the contents of the
+                    <classname>SecurityContext</classname> contents during a request, then it must
+                    have passed through the security filter chain. Otherwise the
+                    <classname>SecurityContextHolder</classname> will not have been populated and
+                    the contents will be null.</para>
             </section>
         </section>
         <section>
@@ -201,6 +194,78 @@
                 </listitem>
                 </orderedlist></para>
         </section>
+        <section xml:id="request-matching">
+            <title>Request Matching and <interfacename>HttpFirewall</interfacename></title>
+            <para>Spring Security has several areas where patterns you have defined are tested
+                against incoming requests in order to decide how the request should be handled. This
+                occurs when the <classname>FilterChainProxy</classname> decides which filter chain a
+                request should be passed through and also when the
+                <classname>FilterSecurityInterceptor</classname> decides which security constraints
+                apply to a request. It's important to understand what the mechanism is and what URL
+                value is used when testing against the patterns that you define.</para>
+            <para>The Servlet Specification defines several properties for the
+                <interfacename>HttpServletRequest</interfacename> which are accessible via getter
+                methods, and which we might want to match against. These are the
+                <literal>contextPath</literal>, <literal>servletPath</literal>,
+                <literal>pathInfo</literal> and <literal>queryString</literal>. Spring Security is
+                only interested in securing paths within the application, so the
+                <literal>contextPath</literal> is ignored. Unfortunately, the servlet spec does not
+                define exactly what the values of <literal>servletPath</literal> and
+                <literal>pathInfo</literal> will contain for a particular request URI. For example,
+                each path segment of a URL may contain parameters, as defined in <link
+                xlink:href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</link><footnote>
+                <para>You have probably seen this when a browser doesn't support cookies and the
+                    <literal>jsessionid</literal> parameter is appended to the URL after a
+                    semi-colon. However the RFC allows the presence of these parameters in any path
+                    segment of the URL</para>
+                </footnote>. The Specification does not clearly state whether these should be
+                included in the <literal>servletPath</literal> and <literal>pathInfo</literal>
+                values and the behaviour varies between different servlet containers. There is a
+                danger that when an application is deployed in a container which does not strip path
+                parameters from these values, an attacker could add them to the requested URL in
+                order to cause a pattern match to succeed or fail unexpectedly.<footnote>
+                <para>The original values will be returned once the request leaves the
+                    <classname>FilterChainProxy</classname>, so will still be available to the
+                    application.</para>
+                </footnote>. Other variations in the incoming URL are also possible. For example, it
+                could contain path-traversal sequences (like <literal>/../</literal>) or multiple
+                forward slashes (<literal>//</literal>) which could also cause pattern-matches to
+                fail. Some containers normalize these out before performing the servlet mapping, but
+                others don't. To protect against issues like these,
+                <classname>FilterChainProxy</classname> uses an
+                <interfacename>HttpFirewall</interfacename> strategy to check and wrap the request.
+                Un-normalized requests are automatically rejected by default, and path parameters
+                and duplicate slashes are removed for matching purposes.<footnote>
+                <para>So, for example, an original request path
+                    <literal>/secure;hack=1/somefile.html;hack=2</literal> will be returned as
+                    <literal>/secure/somefile.html</literal>.</para>
+                </footnote>. It is therefore essential that a
+                <classname>FilterChainProxy</classname> is used to manage the security filter chain.
+                Note that the <literal>servletPath</literal> and <literal>pathInfo</literal> values
+                are decoded by the container, so your application should not have any valid paths
+                which contain semi-colons, as these parts will be removed for matching purposes. </para>
+            <para>As mentioned above, the default strategy is to use Ant-style paths for matching
+                and this is likely to be the best choice for most users. The strategy is implemented
+                in the class <classname>AntPathRequestMatcher</classname> which uses Spring's
+                <classname>AntPathMatcher</classname> to perform a case-insensitive match of the
+                pattern against the concatenated <literal>servletPath</literal> and
+                <literal>pathInfo</literal>, ignoring the <literal>queryString</literal>.</para>
+            <para>If for some reason, you need a more powerful matching strategy, you can use
+                regular expressions. The strategy implementation is then
+                <classname>RegexRequestMatcher</classname>. See the Javadoc for this class for more
+                information.</para>
+            <para>In practice we recommend that you use method security at your service layer, to
+                control access to your application, and do not rely entirely on the use of security
+                constraints defined at the web-application level. URLs change and it is difficult to
+                take account of all the possible URLs that an application might support and how
+                requests might be manipulated. You should try and restrict yourself to using a few
+                simple ant paths which are simple to understand. Always try to use a
+                <quote>deny-by-default</quote> approach where you have a catch-all wildcard
+                (<literal>/**</literal>) defined last and denying access.</para>
+            <para>Security defined at the service layer is much more robust and harder to bypass, so
+                you should always take advantage of Spring Security's method security
+                options.</para>
+        </section>
         <section>
             <title>Use with other Filter-Based Frameworks</title>
             <para>If you're using some other framework that is also filter-based, then you need to