Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I asked this question originally on StackOverflow. I was referred here, so I'll repost:


After upgrading some of our external websites running on SharePoint 2007 to 2010, we ran a link checker to find problems. We noticed the log showed requests for a file called spsdisco.aspx. Indeed, when examining the source of our web pages, SharePoint is adding the following link element to the page HEAD:

<link href="_vti_bin/spsdisco.aspx" rel="alternate" type="text/xml" />

This is a web service discovery file listing out the names and locations of all of SharePoint's web service endpoints. Even worse, this file is starting to show up in search indexes. At best it is embarrassing; at worst it's a potential vulnerability (these are external websites). Because it's a virtual file, it shows up under every site and subsite, so a manual approach to "hiding" each one is difficult and clumsy.

I can't seem to find any actual documentation about it -- a few references on updating it to include a custom web service, but that's about it. How might we approach a reliable, top-down approach to disabling access to these pages? I think we can find a way to suppress the LINK element in the page, but that's just obscuring the problem.

Is there a location in SharePoint (Site or Central Admin) to turn it off? Would you just add some request filtering to IIS to disallow access to SPSdisco.aspx and the ASMX files?


Update: As promised, I have provided the solution we used. Thanks for all of your suggestions!

share|improve this question
    
For Crawls I made an exclusion rule for files like this, the name itself actually made me laugh first, then second I excluded it since it did come up EVERYWHERE and was filling up the Crawl Log. Interesting information about it though, you dug into this more than I have. –  MichaelF Apr 20 '11 at 12:05
    
Thanks for your answers. I haven't abandoned this question. We've discussed potential solutions with our SP admins and haven't arrived at a great approach. We're checking with some Microsoft folks to get their opinion. I will follow up here with the results of that. –  CBono Apr 21 '11 at 19:47
add comment

5 Answers 5

I have used ISAPI_Rewrite to block these requests. http://www.isapirewrite.com/ The download includes a sample that shows you how to block a request.

share|improve this answer
add comment

If you are using UAG or similar proxy, you could block the access to this (and other) files.

share|improve this answer
add comment

In addition to using a reverse proxy, you can also lock down access to vti_bin in the web.config file: http://technet.microsoft.com/en-us/library/ee191479(office.12).aspx.

I think the defaults allow you to read the wsdl but deny access when a service operation is attempted.

share|improve this answer
    
But if you've got a lot of subsites, don't you need to add an entry for each subsite? I want a way to apply this centrally for a whole site, and automatically apply to any new subsites that get created. –  CBono Apr 22 '11 at 15:38
    
No. All service urls within one web application (subsites included) would end in _vti_bin/<service>, so the rule would still match. I just tested the following url patterns http://<site>/_vti_bin/Lists.asmx and http://<site>/<subsite>/_vti_bin/Lists.asmx and the same config rule worked for both. –  Chuck Apr 23 '11 at 1:11
add comment

I would disable anonymous access to the _vti_bin directory in the web.config:

<location path="_vti_bin">
    <system.web>                  
        <authorization>
            <deny users="?" />
        </authorization>
    </system.web>
</location>

Some tips to help lock down your SharePoint site.

share|improve this answer
add comment
up vote 0 down vote accepted

Here is the solution that we arrived at. It was in part based on recommendations by our Microsoft representative, so you might consider this an unofficial, "official" approach.

First, we need keep SharePoint from advertising the disco file to the world (i.e. Google). Simply remove the following line in your master pages:

<SharePoint:SoapDiscoveryLink runat="server"/>

This will suppress the <link href="/_vti_bin/spsdisco.aspx" rel="alternate" type="text/xml"> reference in the HEAD of your pages.

Next, we want to make sure that unauthorized users don't have access to the web services described by the disco file, or anything in _vti_bin for that matter. If your site only runs internal to your firewall (an intranet, for example), then this isn't as important. But if you've got anonymous endpoints that can be accessed externally, you want them locked down.

This is an excellent application for an HttpModule. We'll build one that intercepts any request containing _vti_bin in the path, and if the current user is unauthorized will return a 404 NOT FOUND status code. I chose to return a 404 rather than a 401 UNAUTHORIZED because I don't just want to lock those paths down, I want to hide the fact that anything even exists at those paths.

Our HttpModule looks like this:

using System;
using System.Web;

namespace Custom.SharePoint.HttpModule.SpSecureVtiBin {

    public class SpSecureVtiBinModule : IHttpModule {

        #region IHttpModule Members

        public void Dispose() { }

        public void Init( HttpApplication context ) {
            context.AuthorizeRequest += new EventHandler( context_AuthorizeRequest );
        }

        protected virtual void context_AuthorizeRequest( object sender, EventArgs e ) {
            HttpApplication app = (HttpApplication)sender;
            string requestedPath = app.Request.Path;

            if ( requestedPath.ToLowerInvariant().Contains( "_vti_bin" ) ) {
                if ( !app.Request.IsAuthenticated ) {
                    app.Response.StatusCode = 404;
                    app.Response.StatusDescription = "Not Found";
                    app.Response.Write( "404 NOT FOUND" );
                    app.Response.End();
                }
            }
        }

        #endregion
    }
}

Simple enough. To use the HttpModule, it needs to be registered in the site's web.config file with an entry under \configuration\system.webServer\modules:

<add name="SpSecureVtiBinModule" type="Custom.SharePoint.HttpModule.SpSecureVtiBin.SpSecureVtiBinModule, Custom.SharePoint.HttpModule.SpSecureVtiBin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=[your_public_key_token]" />

Of course, we don't want to modify a SharePoint application's web.config file manually. We'll create an SPFeatureReceiver to do the job:

using System.Collections.ObjectModel;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace Custom.SharePoint.HttpModule.SpSecureVtiBin {

    public class ModuleFeatureReceiver : SPFeatureReceiver {

        private static string _owner = "SpSecureVtiBinModule";

        public override void FeatureActivated( SPFeatureReceiverProperties properties ) {
            SPWebApplication app = (SPWebApplication)properties.Feature.Parent;

            app.WebConfigModifications.Add( GetModificationForSystemWebServer() );
            app.WebService.ApplyWebConfigModifications();
            app.Update();
        }

        public override void FeatureDeactivating( SPFeatureReceiverProperties properties ) {

            SPWebApplication app = (SPWebApplication)properties.Feature.Parent;
            Collection<SPWebConfigModification> mods = app.WebConfigModifications;

            int modCount = mods.Count;
            bool modRemoved = false;

            for ( int i = modCount - 1; i >= 0; i-- ) {
                SPWebConfigModification mod = mods[i];
                if ( mod.Owner.Equals( _owner ) || mod.Owner.Equals( "CHK.SharePoint.HttpModule.SpSecureVtiBin.SpSecureVtiBinModule" ) ) {
                    app.WebConfigModifications.Remove( mod );
                    modRemoved = true;
                }
            }

            if ( modRemoved ) {
                app.WebService.ApplyWebConfigModifications();
                app.Update();
            }
        }

        private SPWebConfigModification GetModificationForSystemWebServer() {
            return new SPWebConfigModification {
                Name = "add[@name='SpSecureVtiBinModule']",
                Owner = _owner,
                Path = "configuration/system.webServer/modules",
                Value = @"<add name=""SpSecureVtiBinModule"" type=""Custom.SharePoint.HttpModule.SpSecureVtiBin.SpSecureVtiBinModule, Custom.SharePoint.HttpModule.SpSecureVtiBin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=[your_public_key_token]"" />",
                Sequence = 0
            };
        }
    }
}

Now all that's left is to package up the HttpModule. You'll need to define a Feature in the package and reference the SPFeatureReceiver class. This will cause the web.config entry to be added when the Feature is activated, and the entry to be removed when the Feature is deactivated. Target the Feature for a WebApplication and the assembly deployment target to GlobalAssemblyCache.

share|improve this answer
    
"Simple enough. To use the HttpModule, it needs to be registered in the site's web.config file with an entry under \configuration\system.webServer\modules: " Shouldn't it be in configuration/system.web/httpModules instead of configuration\system.webServer\modules? I can´t get it to work while inside the configuration\system.webServer\module entry. Regards, P –  user6038 Dec 15 '11 at 19:14
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.