How do I restrict classic asp page access by domain not IP? - asp-classic

I am looking to write some code that captures the user's domain name and uses it to either allow them access or not allow them access to the page content.

I am talking about the same thing as restricting access to a page via
IP address but using the domain instead. I.E. yoursite.com ... I am
trying to keep yoursite.com from having access to my form. This is an
effort to restrict access from Russia domain that uses one domain but
multiple ever-changing IP addresses.
It depends what you mean by "having access". If you're wanting to prevent a website from using/spamming a form that you host, then there's a few things you can do. Start by implementing CORS restrictions in your web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="Access-Control-Allow-Origin" value="https://yourdomain.com" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Set Access-Control-Allow-Origin to your own domain. This will prevent JavaScript on another website from being able to make POST or GET request to your form.
Set X-Frame-Options to SAMEORIGIN
This will prevent other websites from being able to display your site in an iFrame.
You should also use CSRF tokens. A third party website accessing a form that you host isn't strictly a CSRF issue (actual CSRF exploits tend to use hidden iFrames on the attackers site, which are used to hijack an active session a visitor might have with another website. This is prevented by the other website requiring a token to be included with each form submission). But using CSRF tokens is still good practice and a good deterrent when trying to prevent other websites from having access to a public form that you host.
There are many ways to implement CSRF tokens (and there's lots of tutorials) But this is my preferred method which uses CSRF cookies, as demonstrated in this simple web form:
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<%
response.Charset = "utf-8"
Const CSRF_token_max = 9999999999999
Const CSRF_token_min = 1000000000000
sub create_CSRF_cookie(ignoreFormPost)
' Response.Cookies and Request.Cookies don't behave as you'd expect in Classic ASP.
' Response.Cookies is used to create a new cookie which is return in the HTTP
' response headers, so the client can store it locally.
' Request.Cookies is used to retrieve a cookie from the HTTP request headers, which
' are included in every HTTP request the client makes to the server.
' But here's the catch:
' If you use Response.Cookies to create a new cookie, but during the same page load
' you also use Request.Cookies to retrieve the cookie you have just set, ASP will
' return the value of the cookie waiting to be sent back to the client in the response
' headers, despite the cookie having never left the server.
' This has it's uses, but if we issue a new CSRF cookie before processing a form post,
' Request.Cookies("CSRF") will return the value of the new CSRF cookie rather than the
' value of the cookie contained in the request headers, and thus a CSRF token mismatch
' will occur.
if request.form = "" OR ignoreFormPost then
Dim CSRF_token
Randomize()
CSRF_token = Int((CSRF_token_max-CSRF_token_min+1)*Rnd+CSRF_token_min)
' Save the CSRF token as a cookie.
' HttpOnly must be false, which is it by default in classic asp.
Response.Cookies("CSRF") = CSRF_token
end if
end sub
' Create a new CSRF cookie on each page load
' Set "ignoreFormPost" to false. We don't want to create a new cookie if a form has been posted.
' We will do that once the form has been validated and processed.
call create_CSRF_cookie(false)
'---------------------------------------------------------------
' Process a form POST
'---------------------------------------------------------------
if request.form("formName") = "CSRFform" then
Dim hostName, responseStatus, responseColor, expectedCSRF, postedCSRF, postedText
' Is your domain using http or https?
if Request.ServerVariables("HTTPS") = "on" then _
hostName = "https://" else hostName = "http://"
' Build your hostname, e.g: http://yourdomain.com
hostName = hostName & Request.ServerVariables("HTTP_HOST")
expectedCSRF = request.cookies("CSRF")
postedCSRF = request.Form("CSRF")
postedText = request.Form("text")
' Was the form submitted from your domain?
' Is the CSRF token in the form data the correct length?
' Does the CSRF token in the form data match the CSRF token in the cookie?
if inStr(1,Request.ServerVariables("HTTP_REFERER"),hostName,1) = 1 _
AND len(request.form("CSRF")) = len(CSRF_token_max) _
AND request.Form("CSRF") = request.cookies("CSRF") then
' Everything checks out. Do whatever it is you need to do
responseColor = "#00CD42"
responseStatus = "Form submitted successfully"
else
' verification failed
responseColor = "#E00025"
responseStatus = "Form validation failed"
end if
' Create a new CSRF cookie and tell the sub to ignore the fact that a form was posted.
' We've processed the form now so a new CSRF cookie can be issued.
call create_CSRF_cookie(true)
end if
%><!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<%
' We could populate the hidden CSRF field with the "CSRF_token" variable.
' But instead, we're going to retrieve the token from the CSRF cookie
' as the form is submitted and insert it into the CSRF hidden field.
' Why get the CSRF token from the cookie? Well, let's assume you have
' many forms that require a CSRF token. If the user loads a form and
' we populate the CSRF field with the "CSRF_token" variable, great...
' but what if they open another form before submitting this one. A new
' CSRF cookie will be generated. The form will be validated just fine,
' but if they go back to the previous form and submit it, the CSRF cookie
' will have changed and the form will fail to validate.
' This method allows us to generate a new CSRF cookie each time one is
' required, and forms that have already been generated but forgotten
' about will still be verified once the user gets round to submitting it.
' It's quite a common CSRF technique and one I borrowed/stole from Pythons
' Django framework. Ideally, forms should be posted and handled using ajax,
' this would avoid validation fails when resubmitting a form on a page reload
%>
<form method="post" name="CSRFform" onsubmit="getCSRF()">
<table width="<% if request.form("formName") = "CSRFform" then response.write "5" %>0%" border="1" cellspacing="2" cellpadding="6">
<tbody>
<tr>
<td>
<input type="text" name="text" value="<%=Server.HTMLEncode(request.form("text"))%>" placeholder="Enter some text">
<input type="hidden" id="CSRF" name="CSRF" value="">
<input type="hidden" name="formName" value="CSRFform">
<input type="submit" value="Submit">
</td>
</tr>
<% if request.form("formName") = "CSRFform" then %>
<tr>
<td bgcolor="<%=responseColor%>" style="color:#ffffff; font-size:18px; font-weight:bold;"><%=responseStatus%></td>
</tr>
<tr>
<td>
<%
if postedCSRF = "undefined" then postedCSRF = "NA"
if expectedCSRF = "" then expectedCSRF = "NA"
if postedText = "" then postedText = "NA"
response.write "<p><b>Referer</b>: " & Request.ServerVariables("HTTP_REFERER") & "</p>"
response.write "<p><b>Expected Referer</b>: " & hostName & "/*</p><hr>"
response.write "<p><b>CSRF Token</b>: " & postedCSRF & "</p>"
response.write "<p><b>Expected CSRF Token</b>: " & expectedCSRF & "</p><hr>"
response.write "<p><b>CSRF Length</b>: " & len(replace(postedCSRF,"NA","")) & "</p>"
response.write "<p><b>Expected CSRF Length</b>: " & len(CSRF_token_max) & "</p><hr>"
response.write "<p><b>Posted Text</b>: " & Server.HTMLEncode(postedText) & "</p>"
%>
</td>
</tr>
<% end if %>
</tbody>
</table>
</form>
<script>
// Get the most recent CSRF token from the cookies
function getCSRF() {
document.getElementById("CSRF").value = getCookie("CSRF");
}
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
</script>
<body>
</body>
</html>
You'll notice that as well as validating the CSRF token, I'm also checking the HTTP_REFERER against the servers domain name. Whenever a form is submitted the HTTP_REFERER header contains the URL of the website that submitted the post (this is issued by the browser and cannot be spoofed using a standard HTTP POST request). If the form wasn't submitted from your domain, then the form data won't be processed.
So at this point, it's now impossible for a third party website to use client side code to spam or manipulate a form that you host. This is because we're:
Requiring a valid token to be returned with each post request, and the token can only be issued and accessed on your website.
Checking the HTTP_REFERER header to make sure the post request was made from your website.
Using Access-Control-Allow-Origin to prevent javascript/ajax from posting to your form from a thrid party websites (javascript/ajax could potentially be used to spoof a fake HTTP_REFERER header)
However... if an attacker chooses to access your form using server-side code, then this opens up a whole can or worms. Browsers are required to abide by very strict rules, but when you take browsers out of the equation and use server-side code to access and manipulate a web form on another website, those rules can be bypassed. It would be possible for an attacker to use cURL (or a similar protocol) to request your web form, read the CSRF cookie issued by your server in the response headers, use that CSRF token to validate the form, post the form back to your server along with the CSRF cookie you issued AND spoof the HTTP_REFERER header making it appear as the form was submitted from your website. The attacker would have essentially created a bot, and these are very difficult to detect and prevent against, especially since they can spoof other headers too, such as the HTTP_USER_AGENT.
There are solutions to this though which use algorithms to detect suspicious activity. CloudFlare offers a really good bot management services that is great for detecting and blocking bots as well as general data scraping/mining: https://www.cloudflare.com/lp/bot-management/

Related

ASP.NET MVC Anti Forgery Token Insecure

I can actually see the verification token key generated by MVC3 framework in plain text when making a request to the server without ssl.
This key is stored in a cookie called: _RequestVerificationToken_Lw__
In mixed security environment it is actually possible to see this token in plain text sent to the server on the initial request to the non ssl site. This token is also static for the duration of the user's session. Then what's the use of having this token when it can easily be stolen by an attacker, because the cookie gets thrown around in plain text.
Shouldn't this cookie be marked as secure and never to be sent across in plain text? Or at the very least be regenerated on every request such that the secure information doesn't leak out of the ssl channel?
I'm talking about this block in MVC 3 AntiForgeryWorker class
private string GetAntiForgeryTokenAndSetCookie(HttpContextBase httpContext, string salt, string domain, string path)
{
string forgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(httpContext.Request.ApplicationPath);
AntiForgeryData token = (AntiForgeryData) null;
HttpCookie httpCookie = httpContext.Request.Cookies[forgeryTokenName];
if (httpCookie != null)
{
try
{
token = this.Serializer.Deserialize(httpCookie.Value);
}
catch (HttpAntiForgeryException ex)
{
}
}
if (token == null)
{
token = AntiForgeryData.NewToken();
string str = this.Serializer.Serialize(token);
HttpCookie cookie = new HttpCookie(forgeryTokenName, str)
{
HttpOnly = true,
Domain = domain
};
if (!string.IsNullOrEmpty(path))
cookie.Path = path;
httpContext.Response.Cookies.Set(cookie); //Ma, Why isn't this marked as "SECURE"
}
return this.Serializer.Serialize(new AntiForgeryData(token)
{
Salt = salt,
Username = AntiForgeryData.GetUsername(httpContext.User)
});
}
That's quite the inflammatory question title you have there.
The built-in MVC anti-forgery functionality is as secure as the application is configured to be. All cookies written to Response.Cookies will be automatically marked with the "secure" modifier if <httpCookies requireSSL="true" /> is set in Web.config (see MSDN docs). MVC's anti-forgery cookie also gets this behavior if this switch is set.
Combine this with other functionality like setting the HSTS header in your responses, and you're essentially providing a guarantee that the browser will never send sensitive data over plaintext channels.
Additionally, the anti-forgery system does allow storing custom data in the tokens, and you can receive a callback to verify the custom data when the token is validated. See AntiForgeryConfig.AdditionalDataProvider for more information.
With protection against CSRF attacks, an optimal solution is to always use SSL. Without SSL, yes, the nonce--as it is called--is vulnerable to a MITM attack. When using cookies to store the nonce, the cookie must be marked HTTP-only. This prevents JavaScript from reading the cookie. You should also render the nonce as an <input type="hidden" value="nonce"> tag within all <form>s in addition to a cookie.
Anyone with access to the browser itself would be able to read the nonce, and the only way to prevent a replay attack is to have nonces expire the first time after they are validated for the first time by the server. This approach can cause a terrible user experience when the user uses the back button and resubmits a request with the same nonce, however. Because you're using ASP.NET MVC's built-in anti-CSRF protection mechanism, it may not be easy to change its behavior to only allow a nonce to be used once. (EDIT: Thanks to Levi below for informing me that ASP.NET MVC actually makes this quite simple)
If you want better control over generating and validating the nonces then I suggest rolling your own implementation, as I did with my JuniorRoute framework. In fact, feel free to take a look at JuniorRoute's source code to see how I implemented it. It's too much code for a Stack Overflow post.
My Take
a) The form submission is deemed not forged based on comparison of
__RequestVerificationToken cookie &
__RequestVerificationToken form field.
The 2 values are some kind of symmetrically match and hence not same.
b) Cookie can never be marked default must-use-secure-channel by the framework because some applications do not use https.
c) The __RequestVerificationToken implementation is protection against CSRF & cannot help valid user from snooping into process memory:p.

Classic ASP: ASPSessionID is reused

I know how to handle this in ASP.NET, but is there a way to force the Classic ASP Session ID to be cleared? It is a randomly generated ID like ASPSESSIONIDG32423E that does not seem to be available in RESPONSE.COOKIES collection thus I can not clear it. We have a class ASP site still hanging around and recently it was an audit finding that after the user logs out the same session ID is reused.
MORE CLARIFICATION:
First visit to page, I see this in the proxy editor in Response:
Set-Cookie: ASPSESSIONID=PUYQGHUMEAAJPUYL; path=/Webapp
After a logout, I call Session.RemoveAll and Session.Abandon and then redirect user to login page. At which point I should see a new Set-Cookie with a different value for SessionID. Instead, I do not get a new cookie and the new login session reuses the original session cookie. This is an audit finding that we have to resolve in some way but there does not seem to be a way to control this.
So I did come up with a solution for this as follows. I added two pages called Start.asp and Start2.asp. The original login page was changed to check for a post variable which is now set on Start2.asp, so if login.asp does not see that post variable, it redirects to Start.asp. Start.asp invalidates the ASPSessionID by setting it to 0. The key is using Response.AddHeader "Set-Cookie" in order to do this since Response.Cookies("ASPSESSIONID...") gives an error that you can't access the element:
Code for Start.ASP
<%
If instr(Request.ServerVariables("HTTP_COOKIE"), "ASPSESSIONID") > 0 Then
Dim Allcookies
AllCookies = Split(Request.ServerVariables("HTTP_COOKIE"),";")
For i = 1 to UBound(AllCookies)
If instr(AllCookies(i), "ASPSESSIONID") > 0 Then
Response.AddHeader "Set-Cookie", Left(AllCookies(i),instr(AllCookies(i),"=") -1) & "=0; path=/;secure;httponly"
End if
Next
End if
Response.Redirect("start2.asp")
%>
Next, it calls Start2.asp which looks for all ASPSEssionID cookies and appends Secure; httponly (I had to add these for another finding, ASP metabase setting to add secure only works if the SSL cert. is on the web server. In our case the SSL cert is on a load balancer in front of the web server).
Code for Start2.asp
<%
'CODE for authorization/authentication
'...
Session.Contents.RemoveAll
Session.Abandon
If instr(Request.ServerVariables("HTTP_COOKIE"), "ASPSESSIONID") > 0 Then
Dim Allcookies
AllCookies = Split(Request.ServerVariables("HTTP_COOKIE"),";")
For i = 1 to UBound(AllCookies)
if left(Request.ServerVariables("HTTP_HOST"),2) = "65" and instr(AllCookies(i), "ASPSESSIONID") > 0 Then
Response.AddHeader "Set-Cookie", AllCookies(i) & "; path=/;secure;httponly"
End if
Next
End if
%>
<html>
<body>
<form action="login.asp" method="post">
<input type="hidden" name="start2" id="start2" value="Yes" />
</form>
<script type="text/javascript">
document.forms[0].submit();
</script>
</body>
</html>
Really, though, the new ASPSessionID is not generated until within Start2.asp so that Set-Cookie code for secure and httponly has to also be done in login.asp. So the same code above was copied to the top of login.asp just after this code:
If request.form("Start2") = "" Then
Response.Redirect("start.asp")
End if
IMO - you need to end the session rather than just clear out the session ID. In this case, Session.Abandon is the solution. Ref.: https://devguru.com/content/technologies/asp/session-abandon.html
HTH.
This relates to ASP.NET but describes the behaviour you are seeing in ASP
When you abandon a session, the session ID cookie is not removed from
the browser of the user. Therefore, as soon as the session has been
abandoned, any new requests to the same application will use the same
session ID but will have a new session state instance.
http://support.microsoft.com/?kbid=899918
This behaviour will only occur if using the same browser for the same session, as soon as the browser is closed the session cookie will be lost (providing an explicit expiry date has not been set).
You could try calling Session.Abandon then redirect the user to a page which uses JavaScript to clear all cookies, then redirect to the login page, or whatever page you like.
Clearing all cookies with JavaScript

Losing Session between Classic ASP and ASP.NET

The company that I work for is making a transition between classic ASP programs and ASP.NET programs for our intranet software. Eventually, everything will be written in ASP.NET, but because of time constraints, there are still a number of programs that use classic ASP.
To compensate we've written features that allow for redirects and autologins between classic ASP programs and ASP.NET programs. I've been starting to see a problem, though, with holding the session state for our ASP.NET software. If a user uses an ASP.NET program, then does work in a classic ASP program, then goes back to that ASP.NET program, often times, the user's authentication for the ASP.NET program is still in place, yet the user's session is lost, resulting in an error whenever a function is performed within the program.
I'm trying to capture the loss of the session state in global.asax's Session_End event, which would redirect the user to the login page, but that hasn't worked. Has anyone else faced a similar issue with users moving back and forth between classic ASP and ASP.NET and losing sessions? Is that even my real issue here? It's the only thing that I can see as being a problem.
EDIT
This is what we do to redirect users to an ASP.NET page from a classic asp page.
We create an MD5 hash based off of the userID and the date and send it to a redirect.aspx page via the query string. From there, the aspx page creates its own MD5 has based off of the userId and the date, both passed via the query string. If the 2 hashes are identical, the user is authenticated, and the program loads. Here is an example:
Classic ASP:
strDate = Year(Now()) & right("0" & Month(Now()), 2) & right("0" & Day(Now()), 2)
key = MD5(SessionUserID & strDate)
Response.Redirect "/redirect.aspx?key="&key&"&lpid="&ProgramID&"&unum="&SessionUserNum&"&uid="&SessionUserID&"&gid="&SessionGroupID
Redirect.aspx:
string key = Request.QueryString["key"];
//SetDesignModeState Variables:
if (getMd5Hash(Request.QueryString["uid"] + DateTime.Today.ToString("yyyyMMdd")) == key)
{
Session["SessionGroupID"] = Request.QueryString["gid"];
Session["SessionUserNum"] = Request.QueryString["unum"];
Session["SessionUserID"] = Request.QueryString["uid"];
string appID = Request.QueryString["lpid"];
FormsAuthentication.SetAuthCookie(Request.QueryString["uid"], false);
//redirect to ASP.NET page...
I've done a similar thing to you: authenticating users from a legacy ASP application to an ASP.NET site. What would help, is if you could provide a little more detail (sample code, perhaps) of the process you've setup to do this with users coming from the legacy app to the ASPX app.
To give you a brief idea, in my implementation I've done the following:
Create an .ASPX page
The .ASPX page accepts HTTP POST values from a particular legacy ASP app only.
When a POST request is received, I extract the username/password values, then proceed to authenticate in the normal way. If the user is successfully authenticated, we issue a FormsAuthentication cookie to the user.
In reality, my implementation is quite a bit more complicated, using the database as a backing store (as both apps share a common data source) and a particular database field to store a random code which is sent from the classic app to the .NET side to further verify that the request received by the .NET app is valid.
EDIT:
Try manually setting your authentication cookie. Delete the line:
FormsAuthentication.SetAuthCookie(Request.QueryString["uid"], false);
Replace with:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
Request.QueryString["uid"],
DateTime.Now,
DateTime.Now.AddHours(24),
false,
null)
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Current.Response.Cookies.Add(cookie);
See how you get on with that?

How do I configure ASP.Net OutputCache to vary by http vs https?

Here is the scenario, a user opens up non-secure page from our WebApp, let's call it PageA, in their browser and then clicks a link in there that takes them to a secure instance of PageB. Once in PageB the user can subsequently click a link that takes them back to a secure instance of PageA (which they already viewed and is in OutputCache). I observed that even though PageA is being accessed over a different URL after visiting PageB (the secure one) it's actually pulling the prior cached copy rather making a fresh one. I verified this behavior in a debugging session, and was surprised that ASP.Net used the same OutputCache item for a secure copy of the page.
My question is why is it this way? And how do I tell the ASP.Net OutPutCache to treat access from secure URL as a different/unique item than the non-secure equivalent?
[Background]
We recently switched our Web Sites images over to use Scene7/Akamai for all images. As a result of this we added code to use different Scene7 url's when viewing a given page on a secure connection. This OutputCache issue is not allowing for the logic that outputs the secure url's to execute, and is resulting in ugly browser warnings.
This doesn't answer the question as worded but it may eliminate your need to vary by scheme. If you are hard coding the "http://" for the Scene7 urls you can change them to scheme-relative urls.
<img src="http://site.scene7.com/images/someimage.jpg" />
=>
<img src="//site.scene7.com/images/someimage.jpg" />
That will cause the browser to automatically ask for the resource with the same scheme as the referring page. That's assuming you have an SSL certificate for your scene7 domain of course.
I think that you can do a VaryByCustom="scheme" and add this to your Global.asax.cs file (inlcuding a couple other others that I use as well app version & user):
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom.Equals("version", StringComparison.CurrentCultureIgnoreCase))
{
Assembly asm = Assembly.GetExecutingAssembly();
string[] parts = asm.FullName.Split(',');
string version = parts[1].Trim().ToLower();
return version;
}
else if (custom.Equals("user", StringComparison.CurrentCultureIgnoreCase))
{
var user = Membership.Users.CurrentUser;
return null == user ? string.Empty : user.Id.ToString();
}
else if (custom.Equals("scheme", StringComparison.CurrentCultureIgnoreCase))
{
var scheme = context.Request.IsSecureConnection ? "https" : "http";
return scheme;
}
else
return base.GetVaryByCustomString(context, custom);
}
I've never tried it but you might be able to use the Outputcache VaryByHeader property and the "host" header, which specifies the Internet host and port number of the resource being requested.
The question I'd have is why are you redirecting to PageA over secure after from PageB. If its a non-secure page, couldn't you fix the PageB redirect to always redirect to non-secure.

How to get referrer URL in ASP.NET when there are multiple redirects?

I'm developing a web application that uses an in-house SSO server for authentication. I have a link on my home page to a page called Logout.aspx. Logout.aspx clears the Forms Authentication cookie, all session data, then performs a redirect to the LoginUrl specified in the forms authentication configuration which is currently set to a page called Login.aspx.
However when Login.aspx loads, an attempt is made to implicitly reauthenticate the user against the SSO server using the SSO authentication ticket which was previously issued. If this ticket still exists, the previous user will be logged back in and sent back to the home page. I want to determine, when the Login page loads, whether the request has come via the Logout page. The UrlReferrer property of the request still references Home.aspx, presumably because this was the last url the client requested.
Currently I have a workaround in place whereby I append a querystring variable to the request from the logout page that instructs the Login page not to perform an implicit login and instead prompt the user for credentials. How can I determine programmatically whether the request came via a redirect from the Logout page?
Edit 29/04/2009:
Following the conversation with jellomonkey, I should point out that the interaction between the SSO server and the local forms authentication of the consuming website isn't directly relevant to the problem at hand. Expressed succinctly, my problem is:
User clicks HTML hyperlink from Home.aspx which takes them to Logout.aspx
Page_Load event handler of Logout.aspx clears Forms Authentication ticket and Session data and redirects the user to Login.aspx
Page_Load event of Login.aspx checks the UrlReferrer property of the Request object to determine whether the request came via the Logout page. However, in requests which have come via a redirect from Logout.aspx, the UrlReferrer property of the Request object is Home.aspx.
Why is this? Why is the UrlReferrer Home.aspx and not Logout.aspx?
The scenario you are describing should be working correctly unless the logout page is not actually deleting the forms authentication cookie. There are several ways to end the forms authentication session:
//I have seen instances where this does not work.
FormsAuthentication.SignOut()
//I have not seen this code fail before.
Dim cookie As HttpCookie = FormsAuthentication.GetAuthCookie( _
HttpContext.Current.User.Identity.Name, False)
cookie.Expires = Date.Now.AddDays(-1)
Response.Clear()
Response.AppendCookie(cookie)
Response.Redirect(FormsAuthentication.LoginUrl)
Also if you are using a role manager which stores in a cookie remember to call Roles.DeleteCookie().
Edit: In response to the updated question.
The Response.Redirect method does not return a header with a new URL referrer because the spec says that only client initiated requests should contain a referrer header. Here is the Response.Redirect code which you can see does not change the referrer header:
Public Sub Redirect(ByVal url As String, ByVal endResponse As Boolean)
If (url Is Nothing) Then
Throw New ArgumentNullException("url")
End If
If (url.IndexOf(ChrW(10)) >= 0) Then
Throw New ArgumentException(SR.GetString("Cannot_redirect_to_newline"))
End If
If Me._headersWritten Then
Throw New HttpException(SR.GetString("Cannot_redirect_after_headers_sent"))
End If
Dim handler As Page = TryCast(Me._context.Handler,Page)
If ((Not handler Is Nothing) AndAlso handler.IsCallback) Then
Throw New ApplicationException(SR.GetString("Redirect_not_allowed_in_callback"))
End If
url = Me.ApplyRedirectQueryStringIfRequired(url)
url = Me.ApplyAppPathModifier(url)
url = Me.ConvertToFullyQualifiedRedirectUrlIfRequired(url)
url = Me.UrlEncodeRedirect(url)
Me.Clear
If (((Not handler Is Nothing) AndAlso handler.IsPostBack) AndAlso (handler.SmartNavigation AndAlso (Me.Request.Item("__smartNavPostBack") = "true"))) Then
Me.Write("<BODY><ASP_SMARTNAV_RDIR url=""")
Me.Write(HttpUtility.HtmlEncode(url))
Me.Write("""></ASP_SMARTNAV_RDIR>")
Me.Write("</BODY>")
Else
Me.StatusCode = &H12E
Me.RedirectLocation = url
If ((url.StartsWith("http:", StringComparison.OrdinalIgnoreCase) OrElse url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) OrElse ((url.StartsWith("ftp:", StringComparison.OrdinalIgnoreCase) OrElse url.StartsWith("file:", StringComparison.OrdinalIgnoreCase)) OrElse url.StartsWith("news:", StringComparison.OrdinalIgnoreCase))) Then
url = HttpUtility.HtmlAttributeEncode(url)
Else
url = HttpUtility.HtmlAttributeEncode(HttpUtility.UrlEncode(url))
End If
Me.Write("<html><head><title>Object moved</title></head><body>" & ChrW(13) & ChrW(10))
Me.Write(("<h2>Object moved to here.</h2>" & ChrW(13) & ChrW(10)))
Me.Write("</body></html>" & ChrW(13) & ChrW(10))
End If
Me._isRequestBeingRedirected = True
If endResponse Then
Me.End
End If
End Sub
You can use reflector to follow the other methods but I don't see one which changes any header.
Response.Redirect("login.aspx?from=logout")
Steve Yates
ITS, Inc.
Why doesn't Tarzan have a beard?
~ Taglines by Taglinator: www.srtware.com ~

Resources