Page 1 of 1
Security: media is publicly available, bypassing login
Posted:
Thu Jan 21, 2016 3:55 pm
by dest41
I don't think this "feature" is desired: knowing the url of any Subsonic server, it is possible to download media from it with the following URL scheme:
http://server:port/stream?id=Nwhere N is the number of the song in the library. To dump a library, simply iterate over N.
Anybody can reproduce this behavior? If confirmed, a token should be provided with the request to authenticate the requester.
Re: Security: media is publicly available, bypassing login
Posted:
Thu Jan 21, 2016 10:08 pm
by frnx
I can definitely reproduce this. I'm disabling external access until we know more, but did you send an email to Sindre about this? He may want to know about it rather sooner than later.
EDIT: Also, using an ID that does not exist when the Subsonic server was just restarted results in downloading (very slowly) a file full of ones (0xFF everywhere), then any subsequent accesses to the main page gives :
- Code: Select all
Exception java.lang.NullPointerException
Message null
Java version Oracle Corporation 1.8.0_72
Operating system Linux 4.3.3-3-ARCH
Server jetty-6.1.x
Memory Used 43 of 112 MB
Stack trace java.lang.NullPointerException
at net.sourceforge.subsonic.service.SecurityService.getMusicFolderForFile(SecurityService.java:240)
at net.sourceforge.subsonic.service.SecurityService.isInMusicFolder(SecurityService.java:235)
at net.sourceforge.subsonic.service.SecurityService.isReadAllowed(SecurityService.java:203)
at net.sourceforge.subsonic.service.MediaFileService.getMediaFile(MediaFileService.java:99)
at net.sourceforge.subsonic.service.MediaFileService.getMediaFile(MediaFileService.java:81)
at net.sourceforge.subsonic.controller.NowPlayingController.handleRequestInternal(NowPlayingController.java:54)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:265)
at org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107)
at org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:166)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:135)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:81)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.ui.basicauth.BasicProcessingFilter.doFilter(BasicProcessingFilter.java:173)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.ui.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
at org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:149)
at org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at net.sourceforge.subsonic.filter.RequestEncodingFilter.doFilter(RequestEncodingFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at net.sourceforge.subsonic.filter.ParameterDecodingFilter.doFilter(ParameterDecodingFilter.java:54)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at net.sourceforge.subsonic.filter.BootstrapVerificationFilter.doFilter(BootstrapVerificationFilter.java:59)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
Re: Security: media is publicly available, bypassing login
Posted:
Thu Jan 21, 2016 10:22 pm
by daneren2005
There was another thread about it here somewhere so sindre probably already knows about it. I believe it's for the external playlist feature. But you are right it definitely should be authenticated with a token instead of just left wide open like that.
Re: Security: media is publicly available, bypassing login
Posted:
Thu Jan 21, 2016 10:30 pm
by frnx
Ah, it makes sense then, but it's definitely not ideal. It should at least be possible to disable the external playlist feature (I for one have never used it).
Re: Security: media is publicly available, bypassing login
Posted:
Fri Jan 22, 2016 10:36 am
by dest41
Just to be sure, I just sent a mail to Sindre Mehus.
Re: Security: media is publicly available, bypassing login
Posted:
Fri Jan 22, 2016 8:02 pm
by frnx
Thanks! The same thing appears to happen on coverArt.view. I'm going to look at all the routes and see if I can make a list.
Re: Security: media is publicly available, bypassing login
Posted:
Sat Jan 23, 2016 12:52 pm
by sindre_mehus
Thanks for bringing this up.
The stream and coverart endpoints are intentionally unauthenticated to make it work with external players (e.g., Sonos and Chromecast), but I will find a way to make it more secure.
Thanks
Sindre
Re: Security: media is publicly available, bypassing login
Posted:
Sun Jan 24, 2016 3:39 pm
by frnx
Thanks for the quick reply, and the quick commits! Using the file hash seems enough to prevent library iteration, I think that's all we needed.
Re: Security: media is publicly available, bypassing login
Posted:
Tue Feb 23, 2016 9:01 pm
by manwithaplan
Sindre or others,
I need to understand this better - couple questions:
1. Does this impact Subsonic 5.2.1?
2. Are we saying that even if you don't allow downloads as a user privilege for any of your users, that this vulnerability allows people to download every single song or album in your database?
3. Is there some workaround I can make in 5.2.1 to mitigate this access? (I have no problem doing custom file changes, but am not willing to upgrade off of 5.2.1 anytime soon).
Thanks all!