SharePoint 2010: Disable / Hide references to SPSDisco.aspx
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: On Kev's suggestion, I've cross-posted to sharepoint.stackexchange.com.
Update 2: See, I开发者_JS百科 hadn't abandoned this question. We finally had time to get some MS guidance and build a deployable SharePoint solution to address the issue.
As a quick fix I would add a request filtering rule to deny access to SPSDisco.aspx
.
But you might want to ask on the new SharePoint Stack Exchange site about a more robust fix:
https://sharepoint.stackexchange.com/
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
.
精彩评论