projectkudu / kudu

Kudu is the engine behind git/hg deployments, WebJobs, and various other features in Azure Web Sites. It can also run outside of Azure.
Apache License 2.0
3.12k stars 654 forks source link

outboundRules that modify response headers don't seem to work #1879

Closed gregjhogan closed 8 years ago

gregjhogan commented 8 years ago

The following applicationHost.xdt does not change the Server and X-Powered-By response headers

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <location path="%XDT_SITENAME%" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
        <system.webServer xdt:Transform="InsertIfMissing">
            <rewrite xdt:Transform="InsertIfMissing">
                <outboundRules rewriteBeforeCache="true" xdt:Transform="InsertIfMissing">
                    <rule name="replace Server header">
                        <match serverVariable="RESPONSE_Server" pattern=".+" />
                        <action type="Rewrite" value="" />
                    </rule>
                </outboundRules>
            </rewrite>
        </system.webServer>
    </location>
</configuration>

It seems like it should based on the documentation

http://www.iis.net/learn/extensions/url-rewrite-module/url-rewrite-module-20-configuration-reference#Setting_Response_Headers

davidebbo commented 8 years ago

There are two possible reasons for this kind of issues:

  1. Your xdt transform does not do what you expect, and you end up with an applicationhost.config that is not what you want. This would be an xdt issue.
  2. applicationhost.config has exactly what you expected after the transform, but it doesn't work as you expect. This would be more of an IIS thing, not directly related to xdt transforms.

I'd start without isolating between these two.

gregjhogan commented 8 years ago

@davidebbo the xdt transform is doing what I expect to the applicationhost.config. I then copied the inserted element from the applicationhost.config in the web app into my local IIS installation applicationhost.config, and it behaves as I would expect (clears the Server header). If you think this shouldn't work as I would expect, what should I do next? Thanks!

kamranayub commented 8 years ago

I can confirm it does work (if everything is correct), since I use outbound rules to add CORS support and it's been working for months now.

davidebbo commented 8 years ago

Ok, let's close this one as it doesn't seem like there is an issue.

gregjhogan commented 8 years ago

@davidebbo @kamranayub did you try the example I cited? The issue may not be as broad as the subject indicates, but I would appreciate some help on how you think I should proceed. This seems to be the defacto way to overwrite the Server header for IIS, and it doesn't seem to work for Azure web apps. As I indicated earlier, the applicationhost.config that is generated works perfectly on local IIS 8.5 and above. Thanks!

davidebbo commented 8 years ago

Can you clarify exactly what this is supposed to change? Is this easy to repro on an empty site with simply this xdt added? Can you show exactly what response headers you are getting back vs what you expect?

davidebbo commented 8 years ago

Looking at your xsd, I'm confused where the string "RESPONSE_Server" is coming from. I'm not aware of a server variable by this name. Should this instead be the actual name of the variable you're trying to change?

gregjhogan commented 8 years ago

@davidebbo the goal is to clear the "Server" header to pass security scans. This isn't as easy as you might expect, and the XDT transform creates the applicationhost.config needed to match multiple examples on the web where you use the method to clear the "Server" header. You can reproduce it on an empty site using the above xdt (the "Server" header will not be cleared, but it is if you copy/paste the resulting applicationhost.config into local IIS).

http://www.henrylee.link/2015/09/10/how-to-remove-all-information-about-iis-server-from-response-header/ https://blogs.msdn.microsoft.com/chiranth/2014/06/13/url-rewrite-part-3outbound-rules-rewrite-maps/

IIS creates a variable for each response header named RESPONSE_<header>. Let me know if you think there is a better approach. It would be preferable to remove the "Server" header completely, but I haven't found a way to accomplish that. Thanks!

davidebbo commented 8 years ago

What you have works fine and can remove various headers generated from the site (e.g. try ETag). But I think these two are special.

Try this completely different xdt (and read this):

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add xdt:Transform="Remove" />
      </customHeaders>
    </httpProtocol>
    <security>
      <requestFiltering removeServerHeader="true" xdt:Transform="SetAttributes(removeServerHeader)" />
    </security>
  </system.webServer>
</configuration>
gregjhogan commented 8 years ago

That works perfect to remove the Server header, thank you so much!

davidebbo commented 8 years ago

Should also work for X-Powered-By, no?

gregjhogan commented 8 years ago

It does work for removing the Server and X-Powered-By headers, but I cannot get it to remove the X-AspNet-Version header for some reason. Any idea why? Thanks again!

applicationhost.xdt

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <location path="%XDT_SITENAME%" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
        <system.webServer xdt:Transform="InsertIfMissing">
            <httpProtocol xdt:Transform="InsertIfMissing">
                <customHeaders xdt:Transform="InsertIfMissing">
                    <remove name="X-Powered-By" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
                </customHeaders>
            </httpProtocol>
            <security xdt:Transform="InsertIfMissing">
                <requestFiltering removeServerHeader="true" xdt:Transform="SetAttributes(removeServerHeader)" />
            </security>
        </system.webServer>
        <system.web xdt:Transform="InsertIfMissing">
            <httpRuntime enableVersionHeader="false" xdt:Transform="SetAttributes(enableVersionHeader)" />
        </system.web>
    </location>
</configuration>

applicationhost.config (section modified by xdt)

  <location path="MySiteName">
    <system.webServer>
      <defaultDocument>
        <files>
          <clear />
          <add value="Default.htm" />
          <add value="Default.html" />
          <add value="Default.asp" />
          <add value="index.htm" />
          <add value="index.html" />
          <add value="iisstart.htm" />
          <add value="default.aspx" />
          <add value="index.php" />
          <add value="hostingstart.html" />
        </files>
      </defaultDocument>
      <handlers />
      <httpProtocol>
        <customHeaders>
          <remove name="X-Powered-By" />
        </customHeaders>
      </httpProtocol>
      <security>
        <requestFiltering removeServerHeader="true" />
      </security>
    </system.webServer>
    <system.web>
      <httpRuntime enableVersionHeader="false" />
    </system.web>
  </location>
davidebbo commented 8 years ago

Not sure if httpRuntime can go in applicationHost.config. Try adding <httpRuntime enableVersionHeader="false" /> to your web.config instead. If that doesn't work, then I'm not sure...

gregjhogan commented 8 years ago

It does work if I set it directly in the web.config. So do you think some other method will be necessary to remove X-AspNet-Version in a site extension, such as a module? Thanks!

davidebbo commented 8 years ago

Yes, a module might be needed. xdt is only for applicationhost.config, which just doesn't support that section.