same site issue for .net apps hosted on Azure IAAS with Azure AD integration - asp.net

We have ASP.NET Webforms as well as ASP.NET MVC apps with Azure AD Integration which is hosted on Azure IAAS environment. Due to recent Chrome security release version > 80 and above, most of the apps started breaking. Please find below framework version
All the APPS were running on 4.5.2 and also dependent NuGet package
To fix the issue we explored the below option. As we have multiple options we need expert inputs on what option is best for APPS with Azure AD Integration.
To set IIS rewrite rule under the system.webServer tag. It is working without any code changes and framework upgrade
<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="(.*)(SameSite=.*)?" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="localhost" negate="true" />
</conditions>
<action type="Rewrite" value="{R:1}; SameSite=None; Secure" />
</rule>
<!-- Removes SameSite=None header from all cookies, for most incompatible browsers -->
<rule name="CookieRemoveSameSiteNone" preCondition="IncompatibleWithSameSiteNone">
<match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=.*)?" />
<action type="Rewrite" value="{R:1}" />
</rule>
</outboundRules>
</rewrite>
The other option we tried to update the Framework version to 4.7.2 and respective nuget packages. It required code changes at OpenIDconnect. We tried to implement the same based on documentation provided by Microsoft
https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-handle-samesite-cookie-changes-chrome-browser?tabs=dotnet
The third was to try to downgrade the framework version to 4.5.0 and respective NuGet packages. This option is also working fine.

Related

Angular App Won't Load After Publishing On IE11

I'm currently developing an app in Angular with an ASP.NET backend. I've configured the project to work fine locally in IE11 (Update polyfills, browserlist, and add ES5 TsConfig files), but when I've published it to the server via IIS the page will not load and is stuck at "Loading..."
To test out publishing I've attempted to publish the default Angular/ASP.NET app to the same results.
The console displays four errors:
SCRIPT1002: Syntax error
runtime.458556a34b891ea32398.js (1,1)
SCRIPT1002: Syntax error
polyfills-es5.7119ad0e4b3aeae98a0b.js (1,1)
SCRIPT1002: Syntax error
polyfills.4efda4a4618e08b621be.js (1,1)
SCRIPT1002: Syntax error
main.59969322f93fb24d6bee.js (1,1)
polyfills.ts
import 'classlist.js';
import 'web-animations-js';
import 'zone.js/dist/zone';
web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Angular Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
<defaultDocument enabled="true">
<files>
<add value="ClientApp/dist/index.html" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
your application may throw errors in IE11, even when it is working fine in other browsers. There can be numerous reasons why your Angular application is not working, including:
Missing polyfills in polyfills.ts.
Using a TypeScript target version which IE11 does not support
Importing third-party dependencies using a TypeScript target version
which IE11 does not support
Refer this : https://medium.com/better-programming/how-to-fix-your-angular-app-when-its-not-working-in-ie11-eb24cb6d9920
Thanks #Deepak-MSFT for the answer, turns out I didn't have the .NET Hosting Bundle installed on the host machine. Once I installed that, the website displayed as it was supposed to -- barring a couple issues not related to what I'm talking about here.
For those curious, I was having issues with database connection string, I found another project being hosted on the server and modified its connection string:
data source=[database];initial catalog=[table];persist security info=True;user id=[user id];password=[password];MultipleActiveResultSets=True;App=EntityFramework
I also removed the web.config file I'd created, as it would probably get in the way of the one generated during publishing.

Vue.js not scaling after deployment to windows server 2019 IIS

After npm run serve everything's working fine. After i deployed my app with API in ASP.NET application doesnt scale at all. I use Router and History. Authentication for annonymous users is enabled and static content is installed. Console doesn't show any errors.enter image description here
Links to screenshots:
Local run
IIS
What do you mean that vue.js not scaling? The second component display abnormally, is it right?
It might be something wrong with Javascript code snippets working.
Did you install the URL Rewrite extension in IIS and add the below rules in the webconfig file?
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Handle History Mode and custom 404/500" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.html" />
</rule>
</rules>
</rewrite>
Here is URL Rewrite extension.
https://www.iis.net/downloads/microsoft/url-rewrite

Browser won't set ASP.NET_SessionId cookie on payment gateway's post request to our site

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.

Azure Web App - redirect all traffic from http to https

We have an Asp.Net Core web application which is running on .Net framework (net452), and hosted in Azure as a Web App.
I'm trying to redirect all http requests to https.
My current understanding is:
I can't specify IIS rewrite rules in web.config as the application
is an Asp.Net Core application
I can't use the
Microsoft.AspNetCore.Rewrite middleware as of version 2.0.0.0 it
requires .Net Standard 2.0, and net452 only supports .Net Standard
1.5.
If the above are correct, what is the best way of doing this?
I'm currently considering writing a small piece of middleware, but feels like there must be an easier way...
i really doubt for point 1.
because it is an IIS setting.
anything under <system.webServer> is only related to IIS not the tech you are using, even with PHP/Java/pureHtml applications, you can still use that section to add rewrite rules. the rewrite will happen before your requests reach your application. BUT for azure apps, you mean need to enable ARR, it used to have some issue with rewrite rules, but now it should be fine because recently i just set some rules for a PHP application in a new Azure app
You could use an App Service custom extension.
For example, there's an extension that forces traffic to go via HTTPS, described in this post.
This redirects all http traffic to https. It also makes sure that the site warmup request gets through, which makes things work correctly in site swap and Always On scenarios.
<?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">
<applicationInitialization xdt:Transform="InsertIfMissing">
<add initializationPage="/" xdt:Transform="InsertIfMissing"/>
</applicationInitialization>
<rewrite xdt:Transform="InsertIfMissing">
<rules xdt:Transform="InsertIfMissing">
<rule name="Force HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
<add input="{WARMUP_REQUEST}" pattern="1" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>

is it possible to apply URL rewrite rule only to IE browsers on Windows XP?

I have the following URL rewrite rule currently (thanks to smarx's post):
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to HTTPS">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{SERVER_NAME}/{R:1}" redirectType="SeeOther" />
</rule>
</rules>
</rewrite>
</system.webServer>
it redirects all HTTP traffic to HTTPS - so all sites are secured right away. For some reasons (SNI, Azure, Windows XP - it's complicated - read here if you want) I need to keep HTTP for Windows XP IE browsers. Is it possible to do in web.config? If yes - how would I do it? I guess I need to inspect HTTP headers, but how?..
I'm using II8 & ASP.NET MVC4 if that matters.
technically Robert's answer is correct - i just want to share the exact regex I came up with:
<add input="{HTTP_USER_AGENT}" pattern="^(?=.*?MSIE)(?=.*?Windows NT 5\.).*$" negate="true" />
that will exclude Windows XP IE browsers from my rule.
Yes, you can do this. See this question for more details and example code: Is it possible to do conditional URL rewrites dependent on user-agent in ASP.NET/IIS?
<conditions>
<add input="{HTTP_USER_AGENT}" pattern="YOUR_REGEX_HERE" />
</conditions>

Resources