I need to use IIS only for directory browsing. The directory contains ASP.NET Core files and IIS automatically attempts to serve them normally.
Is there a way to force IIS to display all files as static files?
In order to let IIS serves everything as static content, you have to
Keep only Static Files handlers
enable directory browsing
Add mime type for every file. Without that IIS won't know how to serve unknown file type
Disable request filtering to download .config file, bin folder content, etc.
You will find below the corresponding web.config
WARNING : big security issue. Be sure to understand the risk before applying this configuration
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<clear />
<add name="StaticFiles" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
</handlers>
<directoryBrowse enabled="true" />
<staticContent>
<mimeMap fileExtension=".*" mimeType="application/octet-stream" />
</staticContent>
<security>
<requestFiltering>
<hiddenSegments>
<clear />
</hiddenSegments>
<fileExtensions>
<clear />
</fileExtensions>
</requestFiltering>
</security>
</system.webServer>
</configuration>
The MVC project has a Startup.cs file in its root. When i run the project it throws
HTTP Error 404.7 - `Not Found. The request filtering module is configured to deny the file extension
web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<defaultDocument>
<files>
<add value="Startup.cs" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
I added the following lines of config inside system.webserver tag - but there is no change:
<security>
<requestFiltering>
<fileExtensions allowUnlisted="true">
<remove fileExtension="." />
<add fileExtension="." allowed="true" />
</fileExtensions>
</requestFiltering>
</security>
You do not need to add any defaultDocuments, and should not use cs files there.
If you are using the default route, it is sufficient to add a Home controller with a Index action, which will be called by default. You can adapt the default route to use another controller/action.
this is my web.config file
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<directoryBrowse enabled="false" />
<defaultDocument>
<files>
<clear />
<add value="index.php" />
<add value="index.asp" />
<add value="index.htm" />
<add value="index.html" />
<add value="Default.asp" />
<add value="Default.htm" />
<add value="Home.htm" />
<add value="Home.html" />
<add value="Default.aspx" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
when I run run the website www.blah.co.za I get the following error
Runtime Error
Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.
Details: To enable the details of this specific error message to be viewable on remote machines, please create a tag within a "web.config" configuration file located in the root directory of the current web application. This tag should then have its "mode" attribute set to "Off".
<!-- Web.Config Configuration File -->
<configuration>
<system.web>
<customErrors mode="Off"/>
</system.web>
</configuration>
Notes: The current error page you are seeing can be replaced by a custom error page by modifying the "defaultRedirect" attribute of the application's configuration tag to point to a custom error page URL.
<configuration>
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
</system.web>
</configuration>
We have many (more than 100) redirects in our web.config like
<configuration>
<system.webServer>
<httpRedirect enabled="true" exactDestination="true" httpResponseStatus="Found">
<add wildcard="/a" destination="/a/dfdf/default.htm" />
<add wildcard="/sad" destination="/aasd/dfdf/defsadault.htm" />
<add wildcard="/asdsaa" destination="/aasdas/dfasddf/default.htm" />
<add wildcard="/aasdsa" destination="/asdsaa/dfdf/defsdault.htm" />
<add wildcard="/aasd" destination="/adsa/dfdf/default.htm" />
..... more than 100
</httpRedirect>
</system.webServer>
</configuration>
Is there way we can have this section managed in separate web.config or any other best solution?
You can move some config elements into their own config file to reduce clutter in the web.config.
<configuration>
<system.webServer>
<httpRedirect configSource="httpRedirects.config" />
</system.webServer>
</configuration>
This is achieved by adding the configSource attribute as shown above.
And in your seperate httpRedirects.config
<httpRedirect enabled="true" exactDestination="true" httpResponseStatus="Found">
<add wildcard="/a" destination="/a/dfdf/default.htm" />
<add wildcard="/sad" destination="/aasd/dfdf/defsadault.htm" />
<add wildcard="/asdsaa" destination="/aasdas/dfasddf/default.htm" />
<add wildcard="/aasdsa" destination="/asdsaa/dfdf/defsdault.htm" />
<add wildcard="/aasd" destination="/adsa/dfdf/default.htm" />
</httpRedirect>
Note I have only tried this with other config elements.
You can store that in Separate Config file as shown here: SectionInformation.ConfigSource Property
In order to avoid cluttering the configuration file - web.config - it can be defined in a separate configuration file. That file can then be referenced from the web.config file as below:
<httpRedirect configSource="httpRedirects.config" />
The configSource attribute tells IIS configuration that the <httpRedirect> section is defined in a separate file httpRedirects.config.
EDIT:
Please make sure you have httpRedirect attribute set to enabled=true as the default value is false.
<httpRedirect enabled="true" configSource="httpRedirects.config" />
I have a website running on a IIS 7.5 server with ASP.NET 4.0 on a shared host, but in full trust.
The site is a basic "file browser" that allows the visitors to login and have a list of files available to them displayed, and, obviously, download the files. The static files (mostly pdf files) are located in a sub folder on the site called data, e.g. http://example.com/data/...
The site uses ASP.NET form authentication.
My question is: How do I get the ASP.NET engine to handle the requests for the static files in the data folder, so that request for files are authenticated by ASP.NET, and users are not able to deep link to a file and grab files they are not allowed to have?
If you application pool is running in Integrated mode then you can do the following.
Add the following to your top level web.config.
<system.webServer>
<modules>
<add name="FormsAuthenticationModule" type="System.Web.Security.FormsAuthenticationModule" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<remove name="DefaultAuthentication" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
</modules>
</system.webServer>
Now you can use the standard ASP.NET permissions in your web.config to force forms authentication for all files in the directory.
<system.web>
<authorization>
<deny users="?" />
</authorization>
<authentication mode="Forms" />
</system.web>
I had the same problem with getting roles to authenticate. Through trial and error I finally got it to work with a small edit to #Joel Cunningham's code:
<modules runAllManagedModulesForAllRequests="true" >
I used these two sites as references: http://forums.iis.net/t/1177964.aspx and http://learn.iis.net/page.aspx/244/how-to-take-advantage-of-the-iis-integrated-pipeline/
This is an old thread, but I happened on it and ran into the same problem as Egil. Here is the version of Joel's fix that includes roles:
<modules runAllManagedModulesForAllRequests="false">
<remove name="FormsAuthenticationModule" />
<add name="FormsAuthenticationModule" type="System.Web.Security.FormsAuthenticationModule" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<remove name="RoleManager" />
<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
<remove name="DefaultAuthentication" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
</modules>
Addendum:
As #eych noted the accepted answer also blocks access to the ~/Content folder (or wherever you have your CSS), and ~/Scripts, and so on.
If you want to allow exceptions -- i.e. allow certain files/folders to be accessible by unauthenticated users -- you can do that by means of the location element. Add the following to web.config:
<location path="Content">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
Update:
An alternative solution is to is to leave access on by default -- which will allow access to your CSS / JavaScript / etc. -- and apply the "lock" (only) to the folder where the static content is stored:
<location path="data">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>
Caveat: in our case (an MVC site) we needed to decorate all our controller actions (except login) with [AuthorizeAttribute]. Which is a good idea anyway, but had previously not been necessary (because previously any unauthorized request was redirected to the login page).
I wanted to know why it would be required to re-add modules (with default options) that are added by default for the Integrated Pipeline, so I dug a little deeper.
You need to remove and re-add the modules because, by default, the modules aren't added with the default options. They have a precondition added for backwards compatibility to run only for content handled by a registered ASP.NET handler (e.g., .aspx pages).
The default looks like this:
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"
preCondition="managedHandler" />
By removing the modules and re-adding them without a precondition, those individual modules run for every request (including your static content). It is more granular than enabling runAllManagedModulesForAllRequests.
You can read about it in a couple articles from when the Integrated Pipeline was introduced with IIS 7:
ASP.NET Integration with IIS 7
How to Take Advantage of the IIS 7.0 Integrated Pipeline
Note that there is a typo or the module name in the second article (and #John's answer) was changed from FormsAuthenticationModule to FormsAuthentication at some point.
The set of working modules in IIS 7.5 thru 8.5 looks like this for me:
<system.webServer>
<modules>
<!-- Re-add auth modules (in their original order) to run for all static and dynamic requests -->
<remove name="FormsAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<remove name="DefaultAuthentication" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
<remove name="RoleManager" />
<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
</modules>
</system.webServer>
If you application pool is running in Classic mode, you can do the following. You will have to repeat these steps for each file extension you'd like to handle, but I'm using .html here.
First, add a page build provider to the Web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation>
<buildProviders>
<add type="System.Web.Compilation.PageBuildProvider" extension=".html"/>
</buildProviders>
</compilation>
</system.web>
</configuration>
Then add a page handler factory:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<httpHandlers>
<add type="System.Web.UI.PageHandlerFactory" path="*.html" verb="*"/>
</httpHandlers>
</system.web>
</configuration>
Then add a page handler:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add scriptProcessor="C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" requireAccess="Script" preCondition="classicMode,runtimeVersionv2.0,bitness32" path="*.html" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" name="HtmlHandler-Classic-32" />
<add scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" requireAccess="Script" preCondition="classicMode,runtimeVersionv2.0,bitness64" path="*.html" verb="GET,HEAD,POST,DEBUG" name="HtmlHandler-Classic-64"/>
</handlers>
</system.webServer>
</configuration>
This worked for me. (Credit: http://www.ifinity.com.au/Blog/EntryId/66/How-To-301-Redirect-htm-or-html-pages-to-DotNetNuke-aspx-pages.)