3

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!

2
  • 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, 2011 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, 2011 at 19:47

5 Answers 5

0

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.

0

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

0

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.

2
  • 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, 2011 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, 2011 at 1:11
0

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.

2
  • "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, 2011 at 19:14
  • What about if JSOM is used to access list data and your solution is implemented? Will calls from JSOM be treated as authenticated calls?
    – Ali
    Jul 24, 2015 at 8:11
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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