I believe Dmitry's solution will only work for assets on the classpath (under src/main/resources/META-INF/assets), because it is a ClasspathAssetProtectionRule. However, the same directory listing problem seems to exist for context asset directories (subdirectories under src/main/webapp), so a different solution is needed there.
ContextAssetRequestHandler is an internal Tapestry service, but it's a very small class that one could maybe override by contributing a new AssetRequestHandler implementation for the RequestConstants.CONTEXT_FOLDER folder. I haven't tried, though. On Fri, Jan 17, 2020, 4:40 AM Dmitry Gusev <dmitry.gu...@gmail.com> wrote: > My previous rule didn't work for JAR resources, here's an improved version > of regex pattern rule: > > import org.apache.tapestry5.SymbolConstants; > import org.apache.tapestry5.ioc.annotations.Symbol; > import org.apache.tapestry5.services.ClasspathAssetProtectionRule; > > import java.util.regex.Matcher; > import java.util.regex.Pattern; > > public class DirectoryListingAssetProtectionRule implements > ClasspathAssetProtectionRule > { > public static final Pattern LAST_SEGMENT_PATTERN = > Pattern.compile("[^/\\\\]+$"); > > private final String modulePathPrefixGZ; > > public DirectoryListingAssetProtectionRule( > @Symbol(SymbolConstants.MODULE_PATH_PREFIX) String > modulePathPrefix) > { > this.modulePathPrefixGZ = modulePathPrefix.toLowerCase() + ".gz"; > } > > @Override > public boolean block(String path) > { > final Matcher matcher = LAST_SEGMENT_PATTERN.matcher(path); > > if (!matcher.find()) > { > // Empty last segment? > return true; > } > > final String match = matcher.group().toLowerCase(); > > return match.equals(modulePathPrefixGZ) || !match.contains("."); > } > } > > > On Thu, Jan 16, 2020 at 1:35 PM Dmitry Gusev <dmitry.gu...@gmail.com> > wrote: > > > Looking a bit further, it does make sense to me to block all directory > > requests in ClasspathAssetRequestHandler by default, > > as directory listing is not something you'd expect to receive via HTTP. > > > > That workaround won't work if you have folder with dot in the name > though, > > so something more type-safe may be required. > > > > At first glance I couldn't find any existing API that would expose > > underlying File object from an instance of Resource, but for > > ClasspathResource (and maybe some other resources, like FileResource, > > ContextResource, etc.) this implementation could probably work better > (not > > tested): > > > > @Contribute(ClasspathAssetProtectionRule.class) > > public static void contributeClasspathAssetProtectionRule( > > OrderedConfiguration<ClasspathAssetProtectionRule> configuration, > > AssetSource assetSource) > > { > > configuration.add("DirectoryListing", path -> > > { > > Resource resource = assetSource.resourceForPath(path); > > > > if (resource == null) > > { > > // Nothing to serve > > return true; > > } > > > > URL resourceUrl = resource.toURL(); > > > > if (resourceUrl != null) > > { > > try > > { > > return > Path.of(resourceUrl.toURI()).toFile().isDirectory(); > > } > > catch (URISyntaxException e) > > { > > throw new RuntimeException(e); > > } > > } > > > > return false; > > }); > > } > > > > > > On Thu, Jan 16, 2020 at 1:19 PM Nicolas Bouillon <nico...@bouillon.net> > > wrote: > > > >> Hi, > >> Thank you for the quick reply, I've added the following rule in my > >> AppModule. > >> > >> @Contribute(ClasspathAssetProtectionRule.class) > >> public static void contributeClasspathAssetProtectionRule( > >> OrderedConfiguration<ClasspathAssetProtectionRule> > configuration) > >> { > >> ClasspathAssetProtectionRule fileWithDot = (s) -> > >> !s.toLowerCase().matches(".*\\.[^/]+"); > >> configuration.add("DirectoryListing", fileWithDot); > >> } > >> > >> Note that the directory listing is displayed even without any ending > >> forwarding slash. Then I've forced the requested file name to end with > >> a . followed by some chars (anything but a forward slash). > >> > >> I wonder if that configuration should be put by default, or activable > >> using a configuration switch described in > >> https://tapestry.apache.org/security.html > >> > >> Thank you again. > >> Nicolas. > >> > >> Le jeu. 16 janv. 2020 à 10:43, Dmitry Gusev <dmitry.gu...@gmail.com> a > >> écrit : > >> > > >> > Hi, > >> > > >> > I wasn't aware of it, thanks for bringing it up. > >> > > >> > From what I found in code, AssetsModule contributes three asset > >> protection > >> > rules: for .xml, .class, and .properties files: > >> > > >> > public static void contributeClasspathAssetProtectionRule( > >> > OrderedConfiguration<ClasspathAssetProtectionRule> > >> configuration) > >> > { > >> > ClasspathAssetProtectionRule classFileRule = (s) -> > >> > s.toLowerCase().endsWith(".class"); > >> > configuration.add("ClassFile", classFileRule); > >> > ClasspathAssetProtectionRule propertiesFileRule = (s) -> > >> > s.toLowerCase().endsWith(".properties"); > >> > configuration.add("PropertiesFile", propertiesFileRule); > >> > ClasspathAssetProtectionRule xmlFileRule = (s) -> > >> > s.toLowerCase().endsWith(".xml"); > >> > configuration.add("XMLFile", xmlFileRule); > >> > } > >> > > >> > So as a possible workaround you could contribute another rule that > >> vetoes > >> > asset requests that have no file extension (or end with forward > slash), > >> > which should cover directory entries. > >> > > >> > On Thu, Jan 16, 2020 at 12:22 PM Nicolas Bouillon < > nico...@bouillon.net > >> > > >> > wrote: > >> > > >> > > Hi all, > >> > > > >> > > Following a pen-test of our application, it has been raised that the > >> > > list of assets if visible as a directory listing. > >> > > > >> > > For example, we have a javascript file available at this location > >> > > /assets/meta/z58f7f3d4/javascript/library.js but when we access > >> > > /assets/meta/z58f7f3d4/javascript/ the web server lists all files > >> > > available in META-INF.assets.javascript directory of the project. > >> > > > >> > > Do you know how to prevent this listing? > >> > > > >> > > Looks like to me it's happening in > >> > > > >> > > > >> > org.apache.tapestry5.internal.services.assets.ClasspathAssetRequestHandler#handleAssetRequest > >> > > and then in > >> > > > >> > org.apache.tapestry5.internal.services.ResourceStreamerImpl#streamResource(org.apache.tapestry5.ioc.Resource, > >> > > org.apache.tapestry5.services.assets.StreamableResource, > >> > > java.lang.String, > >> > > > >> > > > >> > java.util.Set<org.apache.tapestry5.internal.services.ResourceStreamer.Options>) > >> > > > >> > > Thank you, > >> > > Nicolas. > >> > > > >> > > > --------------------------------------------------------------------- > >> > > To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org > >> > > For additional commands, e-mail: users-h...@tapestry.apache.org > >> > > > >> > > > >> > > >> > -- > >> > Dmitry Gusev > >> > > >> > AnjLab Team > >> > http://anjlab.com > >> > >> --------------------------------------------------------------------- > >> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org > >> For additional commands, e-mail: users-h...@tapestry.apache.org > >> > >> > > > > -- > > Dmitry Gusev > > > > AnjLab Team > > http://anjlab.com > > > > > -- > Dmitry Gusev > > AnjLab Team > http://anjlab.com >