I have the following in web.config...
<httpCookies httpOnlyCookies="true" requireSSL="true" />
These settings are being applied to my site's cookies correctly except for a cookie called 'UMB_PANEL' with a path of '/umbraco'.
I have tried adding a web.config file with duplicate settings into the '/umbraco' folder but it has no effect.
How can I get these cookie settings to apply to the whole site?
Bit late to the party with this but you can achieve what you need with Outbound Rules.
This will rewrite any cookies without Secure=true to be secure:
<outboundRules>
<rule name="Add Secure Cookies" preCondition="No Secure">
<match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false"/>
<action type="Rewrite" value="{R:0}; Secure=true"/>
<conditions/>
</rule>
<preConditions>
<preCondition name="No Secure">
<add input="{RESPONSE_Set_Cookie}" pattern="."/>
<add input="{RESPONSE_Set_Cookie}" pattern="; Secure=true" negate="true"/>
</preCondition>
</preConditions>
</outboundRules>
You can tweak the pattern if you need it to match a specific cookie, e.g: ^(UMB_PANEL).*
I believe that cookie only is set if you log in to the Umbraco admin area.
http://our.umbraco.org/forum/using/ui-questions/20674-Does-Umbraco-make-use-of-Cookies-anywhere-in-the-core-product
My guess is that your main web site users would never get that cookie. I realize that isn't directly answering the question, but perhaps it makes it a moot point?
Related
We're experiencing a weird problem with the payment process of our web application which results in loss of session data.
In this process, after our check-out page user is redirected to payment provider's page and redirected back to our site (to a url we specify) as soon as s/he's done there. This last redirect is done by browser's evaluation of the payment provider's html code which basically consists of a form that posts to our site and a few lines of javascript code that posts that form on page load. At this point browser makes the post request but does not set the "ASP.NET_SessionId" cookie which is present in the previous requests made to the exact same domain (our application's domain). What's more weird is that it sets another cookie we use named "AcceptCookie". It just simply chooses to drop "ASP.NET_SessionId" cookie.
To illustrate the situation I took some screenshots. (In these screenshots orange and green rectangles contain exactly the same value.)
This is the request that made (to our application) when user presses "Check Out" button. After this request user is redirected to payment provider's page.
check-out request
This is the final page that is served by payment provider after user is done there. As you can see it's just a simple form that is automatically posted to our domain on page load.
payment provider's final response
But this post request does not include "ASP.NET_SessionId" cookie which results in acquiring a new session id and the loss of previous session data. And again, just "ASP.NET_SessionId" is missing, not the other one named "AcceptCookie".
post request that brings the user back to our site (made with javascript in the previous step)
Finally we figured that on the older versions of browsers this problem does not occur. On Firefox 52 it works like a charm but on Firefox 71 the above problem happens.
Any ideas?
Note: It's an ASP.NET MVC application with targetFramework="4.5.2"
Have a nice day.
We figured it out.
Somehow "ASP.NET_SessionId" cookie's "SameSite" attribute defaults to "Lax" and this causes session cookie not being added to the request that made by payment gateway's javascript code.
We added following rule to the web.config file in order to override this value and set it to "None".
<configuration>
<system.webServer>
<rewrite>
<outboundRules>
<rule name="Add SameSite" preCondition="No SameSite">
<match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
<action type="Rewrite" value="{R:0}; SameSite=None" />
<conditions>
</conditions>
</rule>
<preConditions>
<preCondition name="No SameSite">
<add input="{RESPONSE_Set_Cookie}" pattern="." />
<add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=None" negate="true" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
UPDATE 1: Just adding above configuration solved the problem for modern browsers but we realized that we were still having issues with older versions of Micosoft Edge and Internet Explorer.
So we needed to add cookieSameSite="None" attribute to sessionState node in web.config file.
<sessionState cookieSameSite="None" />
Be careful with this configuration change though, as older .net framework versions do not support it and cause your site to display error page.
By the way we're still having issues with browsers in IOS 12. But I think it's related to this confirmed bug
UPDATE 2: see zemien's answer for possible fix about IOS issue
UPDATE 3: By combining our findings with the suggestions in zemien's answer we've come up with the following rewrite rules. We've been using this configuration in production. But beware: it marks all the cookies with "SameSite:None" attribute for compatible browsers and excludes SameSite attribute, if exists, for incompatible browsers. It may seem complicated but I tried to explain via comment lines.
This is the FINAL configuration we use in production:
<configuration>
<system.webServer>
<rewrite>
<outboundRules>
<preConditions>
<!-- Browsers incompatible with SameSite=None -->
<preCondition name="IncompatibleWithSameSiteNone" logicalGrouping="MatchAny">
<add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" />
<add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" />
<add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" />
</preCondition>
<!-- Rest of the browsers are assumed to be compatible with SameSite=None -->
<preCondition name="CompatibleWithSameSiteNone" logicalGrouping="MatchAll">
<add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" negate="true" />
<add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" negate="true" />
<add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" negate="true" />
</preCondition>
</preConditions>
<!-- Rule 1: Remove SameSite part from cookie for incompatible browsers if exists -->
<rule name="Remove_SameSiteCookie_IfExists_ForLegacyBrowsers" preCondition="IncompatibleWithSameSiteNone">
<match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=.*)" />
<action type="Rewrite" value="{R:1}" />
</rule>
<!-- Rule 2: Override SameSite's value to None if exists, for compatible browsers -->
<rule name="Override_SameSiteCookie_IfExists_ForModernBrowsers" preCondition="CompatibleWithSameSiteNone">
<match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=.*)" />
<action type="Rewrite" value="{R:1}; SameSite=None" />
</rule>
<!-- Rule 3: Add SameSite attribute with the value None if it does not exists, for compatible browsers -->
<rule name="Add_SameSiteCookie_IfNotExists_ForModernBrowsers" preCondition="CompatibleWithSameSiteNone">
<match serverVariable="RESPONSE_Set-Cookie" pattern=".*"/>
<!-- Condition explanation: Cookie data contains some string value but does not contain SameSite attribute -->
<conditions logicalGrouping="MatchAll">
<add input="{R:0}" pattern="^(?!\s*$).+"/>
<add input="{R:0}" pattern="SameSite=.*" negate="true"/>
</conditions>
<action type="Rewrite" value="{R:0}; SameSite=None" />
</rule>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
I modified upon several SO answers to come up with this URL rewrite that adds SameSite=None to session cookies, and also remove SameSite=None from all cookies for most incompatible browsers. The aim of this rewrite is to preserve the "legacy" behaviour pre-Chrome 80.
Full write-up in my Coder Frontline blog:
<rewrite>
<outboundRules>
<preConditions>
<!-- Checks User Agent to identify browsers incompatible with SameSite=None -->
<preCondition name="IncompatibleWithSameSiteNone" logicalGrouping="MatchAny">
<add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" />
<add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" />
<add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" />
</preCondition>
</preConditions>
<!-- Adds or changes SameSite to None for the session cookie -->
<!-- Note that secure header is also required by Chrome and should not be added here -->
<rule name="SessionCookieAddNoneHeader">
<match serverVariable="RESPONSE_Set-Cookie" pattern="((.*)(ASP.NET_SessionId)(=.*))(SameSite=.*)?" />
<action type="Rewrite" value="{R:1}; SameSite=None" />
</rule>
<!-- Removes SameSite=None header from all cookies, for most incompatible browsers -->
<rule name="CookieRemoveSameSiteNone" preCondition="IncompatibleWithSameSiteNone">
<match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=None)" />
<action type="Rewrite" value="{R:1}" />
</rule>
</outboundRules>
</rewrite>
This should work for most ASP .Net and ASP .Net Core applications, although newer Frameworks have proper code and config options to let you control this behaviour. I would recommend researching all the options available to you before using my rewrite above.
If you don't want to deploy secure, SameSite=None cookies then another option is to simply have the browser set the cookie in JavaScript on page load. This approach works for all browsers without requiring any special cases for various browsers. In an ASP.NET MVC application, it can be accomplished by simply adding the following to the layout.cshtml page:
<script type="text/javascript">
// If being rendered in an iFrame, set a client-side cookie for the ASP.NET Session ID
if (window != window.top) {
document.cookie = "ASP.NET_SessionID=#HttpContext.Current.Session.SessionID";
}
</script>
This is effectively passing the cookie value to the client through the HTML payload, and the client then overwrites the ASP.NET_SessionID cookie that may or may not have been accepted by the browser. Once the cookie is set, then any request that is made will pass the cookie back to the server. Note that this approach does not let you specify HttpOnly for the session cookie.
I wouldn't recommend this approach for public facing websites, but for intranet applications this is a pretty quick workaround.
Using the following web.config file properties I am not able to have my site either remove a session cookie or force the cookie to use HTTPOnly. I am using a basic classic asp website with the below configuration in my web.config file
<configuration>
<system.web>
<httpCookies httpOnlyCookies="true" />
<sessionState mode="Off" cookieless="true"/>
</system.web>
</configuration>
I have tried to use the following outbound rule to rewrite the URL however when the site gets scanned using Qualys it does not rewrite the cookie before the website is scanned. Here is the below property code that is not working:
<outboundRules>
<rule name="Add HttpOnly" preCondition="No HttpOnly">
<match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
<action type="Rewrite" value="{R:0}; HttpOnly" />
<conditions>
</conditions>
</rule>
<preConditions>
<preCondition name="No HttpOnly">
<add input="{RESPONSE_Set_Cookie}" pattern="." />
<add input="{RESPONSE_Set_Cookie}" pattern="; HttpOnly" negate="true" />
</preCondition>
</preConditions>
</outboundRules>
You could always ask the client to 'kill' the cookie (with code attached below) and hope it does so. If this doesn't happen, it could be that there is a bug on the client side or that a user has copied the cookie out of the browser before the expiration, and copies it back in. Anyway... If you can't find a fix, the workaround would be to kill the cookie EVERYTIME you use it.
HttpCookie cookieToKill= new HttpCookie(cookieName);
cookieToKill.Expires = DateTime.UtcNow.AddDays(-1); //any negative value will do)
Response.Cookies.Add(cookieToKill);
In modern CMS, there are a number of places that redirect users by using returnUrl querystring. For example, redirect user to an internal Url after a successful login.
The problem is that the returnUrl is modifiable by anyone and is hence vulnerable. One way to handle this is to validate the parameters of the application script/program before sending 302 HTTP code (redirect) to the client browser. However, this requires changing of application code.
How can I handle it in IIS level? Is it possible to show an error page if the user is redirected to other domain without touching the application code?
I figured it out.
Install IIS URL Rewrite Module and then edit web.config of the web application and add the following in system.webServer node:
<rewrite>
<outboundRules>
<rule name="Rewrite Location Header" preCondition="IsRedirection" enabled="true">
<match serverVariable="RESPONSE_Location" pattern="http[s]{0,1}://localhost/(.*)" negate="true" />
<conditions>
</conditions>
<action type="Rewrite" value="http://{HTTP_HOST}/error.html" replace="true" />
</rule>
<preConditions>
<preCondition name="IsRedirection">
<add input="{RESPONSE_STATUS}" pattern="3\d\d" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
I need to set the httponly and the secure flag to all the cookies of my site to pass the security scans of my customer.
The web.config is configured correctly I think
<system.web>
<httpCookies httpOnlyCookies="true" requireSSL="true" lockItem="true" />
And it is working for all the cookies I create inside my application, but not for google analitycs ones (I know I can not do anything about it) and what I suppose are the session cookies of asp.net (ai_user and ai_session).
Searching for this two cookies lead to nothing.
How can I force the httponly and secure flags?
I do not know if it is related, but I have also this rewrite rule
<rewrite>
<rules>
<rule name="HTTP to HTTPS redirect" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
</rule>
</rules>
</rewrite>
I tried to disable it, but nothing changed
I stumbled upon "ai_session" and "ai_user" cookies now with my project and I think they are from application insights. If you investigate further, please report back to community.
The right way to require SSL is via a global filter
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new System.Web.Mvc.AuthorizeAttribute());
filters.Add(new System.Web.Mvc.RequireHttpsAttribute());
}
I was stuck by a simple outbound rule, I want to modify the HTTP Content-Type to application/atom+xml, if the URL exactly matches http://wayneye.com/Feeds/Atom
My rule XML:
<outboundRules>
<rule name="AtomFeedsIMEType" patternSyntax="ExactMatch">
<match serverVariable="RESPONSE_CONTENT_TYPE" pattern="http://{HTTP_HOST}/Feeds/Atom" />
<action type="Rewrite" value="application/atom+xml" />
</rule>
Need help...
You are matching the server variable against the full URL, including domain name. That's not going to work ;-). It doesn't really matter what the value of the Content-Type is, you're going to replace it anyway so you can match is against anything. To make sure you don't replace it on every page, you need to add a precondition to match only requests starting with /Feeds/Atom (on {REQUEST_URI} ). Here's an example:
<outboundRules>
<rule name="AtomFeedsIMEType" preCondition="Match atom feeds">
<match serverVariable="RESPONSE_Content_Type" pattern="(.*)" negate="false" />
<action type="Rewrite" value="application/atom+xml" replace="true" />
</rule>
<preConditions>
<preCondition name="Match atom feeds">
<add input="{REQUEST_URI}" pattern="^/Feeds/Atom" />
</preCondition>
</preConditions>
</outboundRules>
For this to work, the server has to be set up to allow changing of the Content-Type header. This can be done either on the server level or on the site level but needs to be done by the Administrator. It's set in the applicationHost.config and not in the web.config. Here is a part of the applicationHost.config that allows that:
<location path="your_site_name">
<system.webServer>
<rewrite>
<allowedServerVariables>
<add name="CONTENT_TYPE" />
</allowedServerVariables>
</rewrite>
</system.webServer>
</location>
You can also allow this from the GUI, with the View Server Variables link under actions from the main URLRewrite screen. Hope this helps.