I have an ASP.NET application that validates the user using a separate identity provider (using the OpenID Connect protocol.)
Users are complaining of an itermittent error:
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolInvalidNonceException: IDX21323: RequireNonce is '[PII is hidden]'. OpenIdConnectProtocolValidationContext.Nonce was null, OpenIdConnectProtocol.ValidatedIdToken.Payload.Nonce was not null. The nonce cannot be validated. If you don't need to check the nonce, set OpenIdConnectProtocolValidator.RequireNonce to 'false'. Note if a 'nonce' is found it will be evaluated.
Users experience this error, then discover if they try the login process again it works.
I can reproduce this error by initiating the login process, and while on the identity provider page, clearing the cookie prefixed with OpenIdConnect.nonce.
The error messages suggests setting OpenIdConnectProtocolValidator.RequireNonce to false. I believe this to be an unsatisfactory solution, because it would make the site vulnerable to replay attacks.
Is there a "best practice" way for the website to gracefully deal with this error?
Sometimes the inelegant solution is all you need.
I just display an error, and ask the user to try again.
I suspect the typical user will read the words "Sign In Error", read half of the first sentence, and then click on the button without a second thought.
We thought ours was an intermittent problem but it turned out to be just links coming from Office applications like Word, Excel, PowerPoint. I added a rewrite rule to the web.config file and the error immediately went away:
<rule name="WordBypass" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_USER_AGENT}" pattern="Word|Excel|PowerPoint|ms-office" />
</conditions>
<action type="CustomResponse" statusCode="200" statusReason="Refresh" statusDescription="Refresh" />
</rule>
Related
I assume the errors I'm getting are caused by bots that have:
indexed my previous website under the same domain; and
are probing for vulnerabilities of some kind.
Here are some of the errors:
Code: 404; Type: Http; Error: A public action method 'IPC$' was not found on controller ...
Code: 0; Type: InvalidOperation; Error: The requested resource can only be accessed via SSL.
There are other errors for specific URLs that used to exist, but have since been removed.
Is there a way to prevent bots from hitting these links or is it something I'll have to deal with by filtering out specific requests in ELMAH?
Unfortunately, due to the amount of bots out there and the variety of ways that they are coded to attack or scrape your website, you will not be able to prevent all of these errors. However, you can easily choose to ignore specific types of errors in Elmah. Here is a sample of a filter in the <elmah> section of a web.config file:
<errorFilter>
<test>
<or>
<and>
<!-- filter all errors out that fall in the range 400-499 -->
<greater binding="HttpStatusCode" value="399" type="Int32" />
<lesser binding="HttpStatusCode" value="500" type="Int32" />
</and>
<regex binding="BaseException.Message" pattern="A potentially dangerous \b.+?\b value was detected from the client" caseSensitive="false" />
<regex binding="BaseException.Message" pattern="he provided anti-forgery token was meant for user" caseSensitive="false" />
</or>
</test>
</errorFilter>
That will filter out all the 404s etc. by only including errors less than 400 or greater than 499, and excludes a couple of specific .NET exceptions that are commonly triggered by malicious bots. From there, you can tweak to suit...
I have the next configuration of websites in the IIS:
http://main.domain.com website (ASP.NET MVC 5 app, website binded to the specified host, port 80)
default website binded to :80 with ARR/URL Rewrite module enabled
A wildcard binding *.domain.com is specified in DNS settings.
The desired behavior is to have http://main.domain.com as an entry point and a set of dynamic user-subdomains like http://user1.domain.com, http://user2.domain.com, etc.
Now this behavior is simulated using links like http://main.domain.com/user/user1
I have set up the URL Rewrite rule for main.domain.com in the way like this:
<rule name="user-redirection" enabled="true" stopProcessing="true">
<match url="^.*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true">
<add input="{HTTP_HOST}" pattern="^([\w\d-]+)\.domain\.com$" />
</conditions>
<action type="Rewrite" url="http://main.domain.com/user/{C:1}/{R:0}" logRewrittenUrl="true" />
</rule>
Everything is ok here - I can see that http://user1.domain.com works just like http://main.domain.com/user/user1 as it worked earlier.
Then I try to re-implement a logic of checking the existance of specified user in the database. For instance, when user47 doesn't exist - opening of the http://main.domain.com/user/user47 link leads to redirection to the http://main.domain.com entry point.
In the code-side it is done by adding custom filter attribute to the controller action that implements the needed conditional redirect. I have the next code:
public class UserController : Controller {
[CustomRedirectBehavior]
public ActionResult Index()
{
...
}
}
public class CustomRedirectBehaviorAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
...
if (redirectingCondition) {
filterContext.Result = new RedirectResult("http://main.domain.com");
}
}
}
And here.... I get a cyclic redirection error in the browser! To be certain - I have double-checked this behavior:
When I open http://main.domain.com/user/user47 I'm properly redirected to http://main.domain.com
When I open http://user47.domain.com/ I get a cyclic redirection error.
Then in order to investigate the problem I've modified redirect callback to:
filterContext.Result = new RedirectResult("http://someotherdomain.com/some/other/path");
And.... I can see that:
When I open http://main.domain.com/user/user47 I'm properly redirected to http://someotherdomain.com/some/other/path
When I open http://user47.domain.com/ I'm redirected to http://user47.domain.com/some/other/path !!! (And yes, that's not a typo and I've also double-checked this behavior)
So. I need an idea on how to pass through this problem
I've tried to reproduce your case and it seems you are really getting a redirecting loop. So I added a negative lookahead group ((?!main)) into the pattern and it works for me. This is how my web.config looks:
<rule name="user-redirection" enabled="true" stopProcessing="true">
<match url="^.*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true">
<add input="{HTTP_HOST}" pattern="^(?!main)([\w\d-]+)\.domain\.com$" />
</conditions>
<action type="Rewrite" url="http://main.domain.com/user/{C:1}" logRewrittenUrl="true" />
</rule>
In order to investigate your problem I've tried:
Disable browser cache. If your browser using cache it might you will not see every change of the rule you made.
Change the type of action to be "Redirect" instead of "Rewrite" and watching what's going on in the "Network" tab in the "Developer tools (F12)".
e.g. <action type="Redirect" ...
Well... Finally I got the answer.
The problem was coming from the Application Request Routing (ARR) module being installed in order to make rewriting work with custom subdomains.
The Reverse rewrite host in response headers option was set to true by default after enabling proxy in the Server Proxy Settings area. Disabling this setting makes redirect working correctly under subdomain-based rewriting.
I have got a requirement for generating user friendly urls.I am on IIS.
My dynamic URLs looks like,
www.testsite.com/blog/article.cfm?articleid=4432
Client wants the urls should look like
www.testsite.com/blog/article_title
I know this can be easily done using IIS URL rewiter 2.0.
But the Client wants to do it using ColdFusion only. Basic idea he given like,
User will hit the url www.testsite.com/blog/article_title
I need to fetch the article id using the article_title in the url.
Using the ID to call the article.cfm page and load the output into cfsavecontent and then deliver that output to the browser.
But I do not think its possible at application server level. How IIS will understand our user friendly urls . OR am I missing something important? Is it possible to do it using ColdFusion at application server level?
First, I hate to recommend reinventing the wheel. Webservers do this and do this well.
Cold Fusion can do something like this with #cgi.path_info#. You can jump through some hoops as Adam Tuttle explains here: Can I have 'friendly' url's without a URL rewriter in IIS?.
Option #2: My Favorite: OnMissingTemplate..
Only available to users of Application.cfc (I'm pretty sure .cfm has no counterpart to onMissingTemplate).
You can use this function within application.cfc and all affected pages will throw any "missing" urls at this event. You can then place
<cffunction name="onMissingTemplate">
<cfargument name="targetPage" type="string" required=true/>
<!--- Use a try block to catch errors. --->
<cftry>
<cfset local.pagename = listlast(cgi.script_name,"/")>
<cfswitch expression="#listfirst(cgi.script_name,"/")#">
<cfcase value="blog">
<cfinclude template="mt_blog.cfm">
<cfreturn true />
</cfcase>
</cfswitch>
<cfreturn false />
<!--- If no match, return false to pass back to default handler. --->
<cfcatch>
<!--- Do some error logging here --->
<cfreturn false />
</cfcatch>
</cftry>
</cffunction>
mt_blog.cfm can have contents like, if your url is say just like /blog/How-to-train-your-flea-circus.cfm
<!--- get everything after the slash and before the dot --->
<cfset pagename = listfirst(listlast(cgi.script_name,"/"),".")>
<!--- you may probably cache queries blog posts --->
<cfquery name="getblogpost">
select bBody,bTitle,bID
from Blog
where urlname = <cfqueryparam cfsqltype="cf_sql_varchar" value="#pagename#">
</cfquery>
<!--- This assumes you will have a field, ex: urlname, that has a url-friendly format to match
to. The trouble is that titles are generically, in most blogs, changing every special char
to - or _, so it's difficult to change them back for this sort of comparison, so an add'l
db field is probably best. It also makes it a little easier to make sure no two blogs have
identical (after url-safe-conversion) titles. --->
...
Or if you use a url like /blog/173_How-to-train-your-flea-circus.cfm (where 173 is a post ID)
<!--- get everything after the slash and before the dot --->
<cfset pageID = listfirst(listlast(cgi.script_name,"/"),"_")>
<!--- you may probably cache queries blog posts --->
<cfquery name="getblogpost">
select bBody,bTitle,bID
from Blog
where bID = <cfqueryparam cfsqltype="cf_sql_integer" value="#pageID#">
</cfquery.
...
I don't recommend using a missing file handler (or CF's onMissingTemplate). Otherwise IIS will return a 404 status code and your page will not be indexed by search engines.
What you need to do is identify a unique prefix pattern you want to use and create a web.config rewrite rule. Example: I sometimes use "/detail_"+id for product detail pages.
You don't need to retain a physical "/blog" sub-directory if you don't want to. Add the following rewrite rule to the web.config file in the web root to accept anything after /blog/ in the URL and interpret it as /?blogtitle=[everythingAfterBlog]. (I've added an additional clause in case you want to continue to support /blog/article.cfm links.)
<rules>
<rule name="Blog" patternSyntax="ECMAScript" stopProcessing="true">
<match url="blog/(.*)$" ignoreCase="true" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{SCRIPT_FILENAME}" matchType="IsFile" negate="true" />
<add input="{PATH_INFO}" pattern="^.*(blog/article.cfm).*$" negate="true" />
</conditions>
<action type="Rewrite" url="/?blogtitle={R:1}" appendQueryString="true" />
</rule>
</rules>
I recommend using a "301 Redirect" to the new SEO-friendly URL. I also advise using dashes (-) between word fragments and ensure that the character case is consistent (ie, lowercase) or you could get penalized for "duplicate content".
To add to what cfqueryparam suggested, this post on Using ColdFusion to Handle 404 errors shows how to replace the web server's 404 handler with a CFM script - giving you full rewrite capabilities. It is for an older version of IIS, but you should be able to find the proper settings in the IIS version you are using.
As Adam and other's have said (and the same point is made in the post) this is not something you should do if you can avoid it. Web servers working at the HTTP level are much better equipped to do this efficiently. When you rely on CF to do it you are intentionally catching errors that are thrown in order to get the behavior you want. That's expensive and unnecessary. Typically the issue with most clients or stakeholders is a simple lack of understanding or familiarity with technology like url rewriting. See if you can bend them a little. Good luck! :)
We are building a new mobile based website for an already existing website (that is used heavily by the client).
In this scenario when a user requests certain webpages on the existing web-application from a mobile device, the request for the existing web application must be Redirected to the new mobile web application.
To summarize, we have the following conditions-
If the web page request contains a Query String (jobId), it must be
redirected to a mobile web page (JobDtls.aspx) used with another
Query String parameter name (jId); but with the same query string
value.
If the web page request does not contain a query string, the
Redirection must be to the default.aspx page of the mobile web site.
Both the above conditions must work only if the request is through a
mobile device.
For this Task, I came up with 2 different rewrite rules as described below. However, since I am new to this topic, I wanted to know if someone could optimize on this configuration; with maybe 1 Rule instead.
<rewrite>
<rules>
<rule name="Mobile Entry With QueryString" stopProcessing="true">
<match url="Job.aspx" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_USER_AGENT}" pattern="midp|mobile|phone" />
<add input="{QUERY_STRING}" pattern="jobid=([0-9]+)$" />
</conditions>
<action type="Redirect" url="htps://{HTTP_HOST}/MWeb/mjobitem.aspx?jid={C:1}" rdirectType="Permanent" appendQueryString="false" />
</rule>
<rule name="Mobile Entry Without QueryString" stopProcessing="true">
<match url="Job.aspx" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_USER_AGENT}" pattern="midp|mobile|phone" />
<add input="{QUERY_STRING}" pattern=".+" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/MWeb" redirectType="Permanent" appendQueryString="false" />
</rule>
</rules>
</rewrite>
First, it does not looks like your case may benefit of any form of combination of your rules.
"Combining" redirect rules makes especially sense when you want to avoid redirects chaining. Your case is not leading to redirects chaining. See Combine Multiple IIS7 Rewrite Rules (Redirects) Into One for more on this (and especialy answer link, if the answer is still not completed with the solution provided by the link). Moreover, it is not really combining rules in one, it does allow them to run and accumulates prior to performing the final resulting action.
Then, it looks like we can not have in a same rule some conditions with logicalGrouping MatchAll and others with logicalGrouping MatchAny, which would be required for combining conditions of both rules. An other way would be to elaborate a more complex regular expression matching both query string condition. But it would lead to something harder to understand, so this looks to me undesirable.
And this is just for combining conditions. You would have another trouble to tackle: actions are not the same. I do not think there is a way there to express an action handling both of your cases.
I've found bits and pieces of what I need to make this work, but haven't been able to bring everything together into a workable solution.
I am working on an intranet site, and want to secure *just the logon and logoff actions on my account controller with https. I have the certificate installed correctly, and can successfully redirect traffic to these controller actions to https using a UrlRewrite rule:
<rule name="Redirect to HTTPS" stopProcessing="true">
<match url="^account/logon$|^account/logoff$" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:0}" redirectType="Permanent" />
</rule>
Now, however, I also want to redirect *all of the rest of my site's requests (other than traffic to the two actions) back to http. I'm not interested in debating the merits of this approach, as I have what I consider valid reasons for wanting to redirect back out of https to http.
I've tried writing some code in the Actions to achieve this, but am having major issues with this. I don't know if it is because I'm working with two load-balanced servers or what, but anything I try just gives me a "too many redirects" error message.
So, two questions:
Is it better to use a UrlRewrite rule to redirect out of https or a controller actions?
Does anyone have a working code example or something that can at least get me started down the right path?
Any help is much appreciated!
Better late than never. This might help you or someone else.
<rule name="Redirect to HTTP">
<match url="secureDir/(.*)" negate="true" />
<conditions>
<add input="{HTTPS}" pattern="^ON$" />
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}{REQUEST_URI}" />
</rule>
<rule name="Redirect to HTTPS" stopProcessing="true">
<match url="secureDir/(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" />
</rule>
First, you will have a bit of a challenge here insofar as non-page resources -- how are you referencing images and stylesheets?
As for the question at hand, I think you want to force this upstream of the web servers, such as on the load balancer. I would also backstop the account controller by adding a RequireHttps attribute.
Finally, remember that even if the login process is secured, if that cookie is not transmitted over HTTPS you can easily end up with a firesheep like scenario.
I have some code here which lets you control this with attributes.
MVC already has a [RequireHttps] attribute which you would apply to your logon/logoff pages. My code extends this approach and gives you an additional [ExitHttpsIfNotRequired] attribute. With this attribute applied to your base controller, when you try to access any action with HTTPS that doesn't have [RequireHttps], it will redirect you to HTTP.