How to use HTTPS in an ASP.Net Application - asp.net

I want to use HTTPS in my ASP.NET web application, but only for the Login.aspx page.
How can this be accomplished?

First get or create a certificate
Get the SecureWebPageModule module from http://www.codeproject.com/Articles/7206/Switching-Between-HTTP-and-HTTPS-Automatically-Ver. Instructions for setup can be found in the article.
Add secureWebPages tag to web.config
<configuration>
...
<secureWebPages enabled="true">
...
</secureWebPages>
...
<system.web>
...
</system.web>
</configuration>
Add files and directories to be use for https protocol:
<secureWebPages enabled="true">
<file path="Login.aspx" />
<file path="Admin/Calendar.aspx" ignore="True" />
<file path="Members/Users.aspx" />
<directory path="Admin" />
<directory path="Members/Secure" />
</secureWebPages>
Hope this helps!

You can publish your own certificate or you can purchase one. The caveat is that purchasing one, depending on the company, means that it's already stored in the certificate store for most browsers. Your self published one will not be and your users will have to take the extra step of installing your cert.
You don't say what version of IIS you're using, but here are some detailed instructions for IIS 6
You can purchase relatively cheap certs or you can go with the big boys (verisign) and get an extended validation certificate which turns your address bar in IE, green. It's also a somewhat rigorous validation process and takes time.
If you know all of the users that will be hitting your website, there's no problem with installing your own. However, for an open website with anonymous users (that you don't know), it's probably best to purchase one that is already in most major browsers, certificate stores.
You can enable SSL via IIS and require it for only your login.aspx page and not for the rest.

After you get SSL setup/installed, you want to do some sort of redirect on the login page to https://. Then whatever page the user is sent to after validation, it can just be http://.
Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
If Request.IsSecureConnection = False And _
Not Request.Url.Host.Contains("localhost") Then
Response.Redirect(Request.Url.AbsoluteUri.Replace("http://", "https://"))
End If
End Sub
This may be easier to implement on a master page or just all the pages you require https. By checking for "localhost" you will avoid getting an error in your testing environment (Unless your test server has another name than check for that: "mytestservername").

disclaimer - I was involved in the development of this project
I would recommend using http://nuget.org/packages/SecurePages/ It gives you the ability to secure specific pages or use Regex to define matches. It will also force all pages not matching the Regex or directly specified back to HTTP.
You can install it via NuGet: Install-Package SecurePages
Docs are here: https://github.com/webadvanced/Secure-Page-manager-for-asp.net#secure-pages
Simple Usage:
SecurePagesConfiguration.Urls.AddUrl("/cart");
or
SecurePagesConfiguration.Urls.AddRegex(#"(.*)account", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);

You can enable HTTPS in your IIS config, but it won't be "secure" unless you acquire an SSL Certificate and plug it into IIS. Make sure you have port 443 open.

Related

Trouble logging in with DotnetOpenAuth in asp.net 4.5 sample application

I am just trying to see how open auth works in asp.net 4.5 application.
I just created a new template and it has the deafult code for handling google.
I just un commented the comments as per instructions to enable it, but when i run the application and click on login, it is throwing an exception instead of redirecting to google login page
I have to cross the proxy to make the outbound requests. I guess it is what is blocking it to connect to google.
Is there any way to cross through proxy and make the request ? please suggest
If you are using a proxy then you will need to tell ASP.NET which proxy it should use - this is to do with .NET rather than DotNetOpenAuth. As mentioned by #IsThatSo have a look at Specifying a proxy to use with DotNetOpenID which details that you how you specify the proxy to use.
system.net>
<defaultProxy>
<proxy
usesystemdefault = "False"
proxyaddress="http://myproxyserver:8080"
bypassonlocal="True"
/>
<bypasslist>
<add address="[a-z]+\.mydomain\.com"/>
<add address="[a-z]+\.myotherdomain\.com"/>
</bypasslist>
</defaultProxy>
</system.net>

HTTP error 404: The request resource is not found

I have three systems running on IIS7 with static IP address 192.168.66.5. I have configured the system to run on the same IP address with different ports and subdmain like;
192.168.66.5:81 hostname ams.tpf.go.tz
192.168.66.5:82 hostname gmis.tpf.go.tz
192.168.66.5:83 hostname records.tpf.go.tz
192.168.66.5:84 hostname cmis.tpf.go.tz
I configure all these on IIS7 and defined them in the router.
When the client opens ams.tpf.go.tz without specifying the port number, the error 404 is returned: the requested resource is not found.
This recently occurred to me also - make sure your IIS Website is started - mine had been stopped. This is the error I was receiving in Visual Studio:
Unable to start debugging on the web server. The web server could not find the requested resource.
Right Click on your Website (i.e. Default Website) in IIS Manager and click Manage Web Site --> Start.
Navigating to any applications in the IIS Website was showing this error:
HTTP Error 404. The requested resource is not found.
The easiest way to achieve this is to set the port 80 for the site you want to be the "default" one, since this is the default HTTP port.
Some times IIS Manager -> Manage Web Site -> Start, will not work if the below 2 services are not running
1. Windows Activation Technologies Service
2. World Wide Web Publishing Service
Start these services manually under windows services then start IIS again.
Another cause that happens to me with some frequency is to set the permissions correctly to the physical directory. It can be achieved going to IIS -> clicking on the website and then in the actions panel click over Edit Permissions. Be sure that the user you are going to assign the permissions, are the same as defined on Authentication -> Anonymous Authentication or ASP.NET Impersonation, if any of those authentication methods are enabled.
To know the user assigned on those authentication methods, go to the Authentication icon, select any of the authentication methods mentioned before, right click on it and select edit. After that, you have the option to select the user you want.
Hoping this helps.
My issue for anyone else that comes here from google. I am hosting a django website so in my webconfig file it is set to process requests using the python virtual environment. In the web.config file it is this portion:
<configuration>
<system.webServer>
<handlers>
<add name="Python FastCGI"
path="*"
verb="*"
modules="FastCgiModule"
scriptProcessor="C:\inetpub\wwwroot\receipts\venv\Scripts\python.exe|C:\inetpub\wwwroot\receipts\venv\Lib\site-packages\wfastcgi.py"
resourceType="Unspecified"
requireAccess="Script" />
</handlers>
...
</configuration>
When there was requests to the media folder IIS would say great I know what to do send it through the scriptProcessor (python processor). Requests to the media folder should not do that they only need to serve static files (no extra processing). I placed this web.config in the media directory and it solved my problem!
<configuration>
<system.webServer>
<handlers>
<!-- this configuration overrides the FastCGI handler to let IIS serve these static files -->
<clear />
<add name="StaticFile"
path="*"
verb="*"
modules="StaticFileModule"
resourceType="File"
requireAccess="Read" />
</handlers>
</system.webServer>
</configuration>
In my case IIS server and resolved with the below steps.
Check the security groups - whether we have opened the required ports from ALB SG to EC2 SG.
Login to server and check does IIS server's default site has 443 port opened if your health-check is on 443. (whatever port you are using for health checks).
Use the curl command to troubleshoot the issue.
If you would like to check on HTTPS use the below command to check the response. Use -k or --insecure to ignore the SSL issue.
curl https://[serverIP] -k
For HTTP test use the below command.
curl http://[serverIP]

IIS7 Block request to asp.net app using external IP

I have a asp.net app (IIS7), and I want block access to it using external server IP. I only want to allow access using my domain.
For example, my domain is domain.com and IP 161.0.0.1 and I want to block the access to http://161.0.0.1/webapp/
I prefer do it using web.config
Thx in advance,
In IIS you configure exactly what IP / DNS name combination you want the site to respond to. You can easily force it to only respond on a particular IP.
For IIS 7:
Open the Internet Information Services (IIS) Manager
Expand Sites and right click on your website.
Click on Edit Bindings.
Edit the existing entry and set the IP address to 161.0.0.1. Also set the domain name to domain.com.
Click OK, the Click Close.
Now your site wil only respond to that particular domain name and won't respond via IP address only.
If your site uses an SSL certificate then see the following question which talks about how to configure IIS to force the hostname to be used:
https://serverfault.com/questions/96810/iis7-cant-set-host-name-on-site-with-ssl-cert-and-port-443
which links to:
http://www.sslshopper.com/article-ssl-host-headers-in-iis-7.html
This link is even better for doing it entirely through the UI: http://blog.armgasys.com/?p=80
OK so if you want the Site to be accessible via DNS name but not via IP, the only way to distinguish that is to examine the requested host name in the header. There are two ways to do that I know of:
1) Configure Bindings dialog in IIS Manager. This is the easiest to set up but doesn't work for HTTPS. Just put www.domain.com into the hostname field and requests to the IP will be rejected. For HTTPS if your security certificate is for a specific hostname, the user will get a security warning if they try to connect via IP, but typically they can override the warning (depending on browser settings).
Edit: Chris Lively has linked to a way to make this method work for HTTPS bindings as well, see his answer for more information.
2) Alternately you can examine the header in code. Here is an example of an IHttpModule which accomplishes what you want. It is also a drop-in solution that is configured in web.config.
Code:
Public Class HostNameCheck
Implements IHttpModule
Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
End Sub
Public Sub Init(context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
AddHandler context.BeginRequest, AddressOf context_BeginRequest
End Sub
Private Sub context_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim objApp As HttpApplication = DirectCast(sender, HttpApplication)
If objApp.Request.Url.Host <> ConfigurationManager.AppSettings("AcceptedHostName") Then
objApp.Response.Clear()
objApp.Response.StatusCode = 403
objApp.Response.SubStatusCode = 6
objApp.Response.Flush()
End If
End Sub
End Class
Web.config:
<configuration>
<appSettings>
<add key="AcceptedHostName" value="www.domain.com"/>
</appSettings>
<system.webServer>
<modules>
<add name="HostNameCheck" type="HostNameCheck"/>
</modules>
</system.webServer>
</configuration>

Stopping cookies being set from a domain (aka "cookieless domain") to increase site performance

I was reading in Google's documentation about improving site speed. One of their recommendations is serving static content (images, css, js, etc.) from a "cookieless domain":
Static content, such as images, JS and
CSS files, don't need to be
accompanied by cookies, as there is
no user interaction with these
resources. You can decrease request
latency by serving static resources
from a domain that doesn't serve
cookies.
Google then says that the best way to do this is to buy a new domain and set it to point to your current one:
To reserve a cookieless domain for
serving static content, register a new
domain name and configure your DNS
database with a CNAME record that
points the new domain to your existing
domain A record. Configure your web
server to serve static resources from
the new domain, and do not allow any
cookies to be set anywhere on this
domain. In your web pages, reference
the domain name in the URLs for the
static resources.
This is pretty straight forward stuff, except for the bit where it says to "configure your web server to serve static resources from the new domain, and do not allow any cookies to be set anywhere on this domain". From what I've read, there's no setting in IIS that allows you to say "serve static resources", so how do I prevent ASP.NET from setting cookies on this new domain?
At present, even if I'm just requesting a .jpg from the new domain, it sets a cookie on my browser, even though our application's cookies are set to our old domain. For example, ASP.NET sets an ".ASPXANONYMOUS" cookie that (as far as I'm aware) we're not telling it to do.
Apologies if this is a real newb question, I'm new at this!
Thanks.
This is how I've done in my website:
Setup a website on IIS with an ASP.NET application pool
Set the binding host to your.domain.com
Note: you cannot use domain.com or else the sub-domain will not be cookieless
Create a folder on the website called Static
Setup another website, point it to Static folder created earlier.
Set the binding host to static.domain.com
Use an application pool with unmanaged code
On the settings open Session State and check Not enabled.
Now you have a static website. To setup open the web.config file under Static folder and replace with this one:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<sessionState mode="Off" />
<pages enableSessionState="false" validateRequest="false" />
<roleManager>
<providers>
<remove name="AspNetWindowsTokenRoleProvider" />
</providers>
</roleManager>
</system.web>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00" />
</staticContent>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
This is going to cache the files for 30 days, remove a RoleManager (I don't know if it changes anything but I removed all I could find), and remove an item from Response Headers.
But here is a problem, your content will be cached even when a new version is deployed, so to avoid this I made an helper method for MVC. Basically you have to append some QueryString that will change every time you change these files.
default.css?v=1 ?v=2 ...
My MVC method gets the last write date and appends on the file url:
public static string GetContent(this UrlHelper url, string link)
{
link = link.ToLower();
// last write date ticks to hex
var cacheBreaker = Convert.ToString(File.GetLastWriteTimeUtc(url.RequestContext.HttpContext.Request.MapPath(link)).Ticks, 16);
// static folder is in the website folders, but instead of
// www.domain.com/static/default.css I convert to
// static.domain.com/default.css
if (link.StartsWith("~/static", StringComparison.InvariantCultureIgnoreCase))
{
var host = url.RequestContext.HttpContext.Request.Url.Host;
host = String.Format("static.{0}", host.Substring(host.IndexOf('.') + 1));
link = String.Format("http://{0}/{1}", host, link.Substring(9));
// returns the file URL in static domain
return String.Format("{0}?v={1}", link, cacheBreaker);
}
// returns file url in normal domain
return String.Format("{0}?v={1}", url.Content(link), cacheBreaker);
}
And to use it (MVC3 Razor):
<link href="#Url.GetContent("~/static/default.css")" rel="stylesheet" type="text/css" />
If you are using another kind of application you can do the same, make a method that to append HtmlLink on the page.
If you don't write cookies from domain, the domain will be cookie-less.
When the domain is set to host only resource content like scripts, images, etc., they are requested by plain HTTP-GET requests from browsers. These contents should be served as-is. This will make your domain cookieless. This cannot be done by web-server configuration. Http is completely state-less and web-servers have no idea about the cookies at all. Cookies are written or sent to clients via server-side scripts. The best you can do is disable asp.net, classic-asp or php script capabilities on the IIS application.
The way we do it is.
We have a sub-domain setup to serve cookie-less resources. So we host all our images and scripts on the sub-domain. and from the primary application we just point the resource by it's url. We make sure sub-domain remains cookie-free by not serving any dynamic script on that domain or by creating any asp.net or php sessions.
http://cf.mydomain.com/resources/images/*.images
http://cf.mydomain.com/resources/scripts/*.scripts
http://cf.mydomain.com/resources/styles/*.styles
from primary domain we just refer a resource as following.
<img src="http://cf.mydomain.com/resources/images/logo.png" />
Serving resources from Cookie-less domains is great technique if you have more than 5 of combined images/styleshees/javascript then its benefit is noticeable and is gain even with that extra DNS lookup. Also its very easy to implement :). There's how you can easily set it in web.config[system.web] and have completely cookieless subdomain (unless its cookie-fested by Google Analytics but thats easily curable as well) :)
<!-- anonymousIdentification configuration:
enabled="[true|false]" Feature is enabled?
cookieName=".ASPXANONYMOUS" Cookie Name
cookieTimeout="100000" Cookie Timeout in minutes
cookiePath="/" Cookie Path
cookieRequireSSL="[true|false]" Set Secure bit in Cookie
cookieSlidingExpiration="[true|false]" Reissue expiring cookies?
cookieProtection="[None|Validation|Encryption|All]" How to protect cookies from being read/tampered
domain="[domain]" Enables output of the "domain" cookie attribute set to the specified value
-->
To give you example
<anonymousIdentification enabled="true" cookieName=".ASPXANONYMOUS" cookieTimeout="100000" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="None" domain="www.domain." />
This will set .ASPXANONYMOUS cookie only on www.domain.anyTLD but not myStatic.domain.anyTLD ... no need to create new pools and stuff :).
If you aren't using that cookie, in any way, you could just disable session state in IIS 6:
http://support.microsoft.com/kb/244465
In IIS, go to the Home Directory tab, then click the "Configuration" button.
Next go to the Options tab and un-check "Enable session state". The cookie will go away, and you can leave your files where they are with no need for an extra domain or sub-doamin.
Plus, by using additional domains, you increase dns lookups, which partially defeats the intent of the overall optimization.

How to have multiple logins with ASP.Net?

I'm working on a website with an internal and an external section.
The users for both sections are different so they require a different login page. I wanted to configure the authentication differently for both folders, but ASP.Net but it's not allowed.
Example (in my main web.config):
<authentication mode="Forms">
<forms loginUrl="~/Pages/Internal/Main.aspx" defaultUrl="~/Pages/Internal/Main.aspx" cookieless="UseDeviceProfile" name=".ApplicationAuthenticatedUser" path="/" protection="All" slidingExpiration="true" timeout="45"/>
</authentication>
And in the external subfolder, I try to overwrite the settings:
<authentication mode="Forms">
<forms loginUrl="~/Pages/External/Default.aspx" defaultUrl="~/Pages/External/Default.aspx" cookieless="UseDeviceProfile" name=".ApplicationAuthenticatedUser" path="/Pages/External" protection="All" slidingExpiration="true" timeout="45"/>
</authentication>
However this gives me an error.
I tried putting both of them in their subfolders but I get the same error, the authentication configuration section must be set at the application level (I'm guessing that means the root web.config).
A possible solution is to centralize the login page and redirect depending on where the request came from, if it came from an external page, send it to the external login page, otherwise to the internal one.
It would work, but if it's possible I'd like the solution where I can configure this in the web.config.
Thanks
I am confused? Why two user data stores? I understand internal versus external, but if this is the same application, you can assign roles to give more permissions to your internal users. In addition, you can allow your internal users to access the site from home without VPN.
Even so, if you must have two stores, your best bet is duping the application. It can be the exact application, but you put it on one internal server and one external. Then you can authenticate the users at different locations. Note, however, that you still need roles, unless you are kludging up the application.
If you need to authenticate against two stores, you can do it with a custom provider. The ASP.NET login model allows for custom providers and it is very easy to build one:
http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx
http://msdn.microsoft.com/en-us/library/aa479048.aspx
Now, if you must redirect to different pages (you are stuck in this model for some reason?), you can possibly do it by IP address. It is likely your internal network uses a 10 dot or 192 dot IP scheme. If so, those addresses get transfered to internal. The rest to external. This will require you setting up something that does the redirect. I know you can do this on the login page, if not with an HTTP Handler.
This seems like an awful lot of work, however. I still do not see the picture of why you have to accomplish the task in this manner.
If you can run as two different IIS applications then you can have different authentication providers (or different instances of the same provider... possibly using the same database with the application attribute on the provider to distinguish).
But different web apps means no shared state (Application and Session) and duplicating the install. For an intranet/internet this would allow the external deployment to not include components that no internet user can access (and thus improve security by reducing surface area).
Otherwise you might need a custom authentication provider that forwards to one of the built in ones depending on who is logging in.
If your your site is a single web application, you could probably use the ASP.NET Role Provider model for that, having two roles, one for internal and one for external pages (you can configure that pr. folder with the <location> configuration element).
For more information, see http://msdn.microsoft.com/en-us/library/9ab2fxh0.aspx
I have a simple way of handling this that might be of use to somebody. I basically want to be able to use the same code for a guest login and a registered user. I also have a mobile version of the website that I want to send to a different login page when the authentication ticket expires.
Probably not the most elegant solution, but simple enough:
Public Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs)
If Page.IsValid Then
Dim userLogin As String = ""
userLogin = System.Guid.NewGuid.ToString
FormsAuthentication.RedirectFromLoginPage(userLogin, False)
' place a url param throughout my app, only four pages so no
' big problem there in this case g stands for guest
Response.Redirect("menu.aspx?m=g", False)
End If
End Sub
Then, in Global.asax:
Protected Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Request.IsAuthenticated And _
(Not Request.RawUrl.ToLower.Contains("guestlogin.aspx")) And _
(Not Request.RawUrl.ToLower.Contains("registeredlogin.aspx")) And _
(Not Request.RawUrl.ToLower.Contains("mobilelogin.aspx")) Then
Response.Redirect("spLogin.aspx?m=" & Request.QueryString("m"))
End If
End Sub
Then, in your login page (the one specified in your Web.config):
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
if request.querystring("m")="g" then
Response.Redirect("guestlogin.aspx?m=g")
elseif request.querystring("m")="r" then
Response.Redirect("registeredlogin.aspx?m=r")
elseif request.querystring("m")="m" then
Response.Redirect("mobilelogin.aspx?m=m")
end if
End If
End Sib

Resources