ASP.NET Help! FireFox is eating my cookies! - asp.net

IE works fine, but FireFox does not.
I am setting a cookie on my default.aspx page:
HttpCookie hc = new HttpCookie("guid", guid.ToString());
hc.Expires = DateTime.Parse("12/12/2010");
Response.Cookies.Add(hc);
My upload control (I'm using SWFUpload) submits to upload.aspx.
On upload.aspx I call:
if (Request.Cookies["guid"] != null)
{
// Do something.
}
...my cookie only contains my ASP.NET session variable. Any ideas?

I have had the same issue when trying to upload files in Firefox through my Flex application. If you're also using Flash, you may want to do what I did; if you're using the HTML controls, this may or may not apply.
What I did to work around the Firefox issue is issue a one-time use token on the server, then post that token when doing the upload (for example, it could be a hidden field in the form). If the token is recognized upon upload, the upload is processed, then the token is expired. So it's basically what you're doing, only without using a cookie.

This is what I used to add/get cookie values. Works for me in both IE and FF
addCookie:
HttpCookie c = new HttpCookie("myCookie");
c.Expires = new DateTime(2050, 1, 1);
c.Values.Add("key", "value");
getCookie:
string value = Request.Cookies["myCookie"]["key"];

Behind the scenes, you are probably setting the same cookie twice. Firefox and IE probably differ on which one they choose to keep. ASP.NET likes to set a "guid" cookie automatically in a lot of web applications. By choosing that name, you are bound to create tension between the automatic logic and your own. The best way to see what is happening is to load the Live HTTP Headers add-on to Firefox. It will allow you to see exactly what cookie commands are being sent over to the end-user. You can also force a similar problem to see it recreated:
HttpCookie hc = new HttpCookie("testcookie", "xyz");
hc.Expires = DateTime.Parse("12/12/2010");
Response.Cookies.Add(hc);
hc = new HttpCookie("testcookie", "abc");
Response.Cookies.Add(hc);
This results in an HTTP header with two Set-Cookie calls:
Set-Cookie: testcookie=xyz; expires=Sun, 12-Dec-2010 07:00:00 GMT; path=/
Set-Cookie: testcookie=abc; expires=Sun, 12-Dec-2010 07:00:00 GMT; path=/
From there, it is up to the browser to decide whether first or last is the final value. If two browsers do it differently, you end up with the situation you describe. Install the Live HTTP Headers add-on and look for something similar. At the very least, you should probably consider "guid" to be a cookie name that you should use in an ASP.NET forms app.
If you absolutely need to have multiple places set the same cookie, try to find it first (create a new one if it doesn't exist). This will ensure you are overriding the value of the existing cookie rather than creating another cookie with the same name.
HttpCookie hc = Response.Cookies["testcookie"];
if (null == hc) {
hc = new HttpCookie("testcookie");
Response.Cookies.Add(hc);
}
hc.Value = "xyz";

First off, there's a type-safe constructor for DateTime, which is new DateTime(2010, 12, 12).
Second, you're using different names for your cookie: guid vs applicationGuid. Use either, not both.

Related

Using Datazen in an iframe with external authentication

I was able to successfully use external authentication with datazen via HTTPWEBREQUEST from code-behind with VB.NET, but I am unclear how to use this with an iframe or even a div. I'm thinking maybe the authorization cookies/token isn't following the iframe around? The datazen starts to load correctly, but then it redirects back to the login page as if it's not being authenticated. Not sure how to do that part, this stuff is pretty new to me and any help would be greatly appreciated!!
Web page errors include:
-OPTIONS url send # jquery.min.js:19b.extend.ajax # jquery.min.js:19Viewer.Controls.List.ajax # Scripts?page=list:35Viewer.Controls.List.load # Scripts?page=list:35h.callback # Scripts?page=list:35
VM11664 about:srcdoc:1
XMLHttpRequest cannot load http://datazenserver.com/viewer/jsondata. Response for preflight has invalid HTTP status code 405Scripts?page=list:35
load(): Failed to load JSON data. V…r.C…s.List {version: "2.0", description: "KPI & dashboard list loader & controller", url: "/viewer/jsondata", index: "/viewer/", json: null…}(anonymous function) # Scripts?page=list:35c # jquery.min.js:4p.fireWith # jquery.min.js:4k # jquery.min.js:19r # jquery.min.js:19
Scripts?page=list:35
GET http://datazenserver.com/viewer/login 403 (Forbidden)(anonymous function) # Scripts?page=list:35c # jquery.min.js:4p.fireWith # jquery.min.js:4k # jquery.min.js:19r # jquery.min.js:19
' ''//////////////////////////////////
Dim myHttpWebRequest As HttpWebRequest = CType(WebRequest.Create("http://datazenserver.com/"), HttpWebRequest)
myHttpWebRequest.CookieContainer = New System.Net.CookieContainer()
Dim authInfo As String = Session("Email")
myHttpWebRequest.AllowAutoRedirect = False
myHttpWebRequest.Headers.Add("headerkey", authInfo)
myHttpWebRequest.Headers.Add("Access-Control-Allow-Origin", "*")
myHttpWebRequest.Headers.Add("Access-Control-Allow-Headers", "Accept, Content-Type, Origin")
myHttpWebRequest.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
Dim myHttpWebResponse As HttpWebResponse = CType(myHttpWebRequest.GetResponse(), HttpWebResponse)
Response.AppendHeader("Access-Control-Allow-Origin", "*")
' Create a new 'HttpWebRequest' Object to the mentioned URL.
' Assign the response object of 'HttpWebRequest' to a 'HttpWebResponse' variable.
Dim streamResponse As Stream = myHttpWebResponse.GetResponseStream()
Dim streamRead As New StreamReader(streamResponse)
frame1.Page.Response.AppendHeader("Access-Control-Allow-Origin", "*")
frame1.Page.Response.AppendHeader("headerkey", authInfo)
frame1.Attributes("srcdoc") = "<head><base href='http://datazenserver.com/viewer/' target='_blank'/></head>" & streamRead.ReadToEnd()
You might have to do more of this client-side, and I don't know whether you'll be able to because of security concerns.
External authentication in Datazen looks something like this:
User-Agent | Proxy | Server
-------------------|----------------------|------------------------------------
1. /viewer/home --> 2. Append header --> 3. Check cookie (not present)
<-- 5. Forward <-- 4. Redirect to /viewer/login
6. /viewer/login --> 7. Append header --> 8. Append cookie
<-- 10. Forward <-- 9. Redirect to /viewer/home
11. /viewer/home --> 12. Append header --> 13. Check cookie (valid)
<-- 15. Forward <-- 14. Give content
16. .................. Whatever the user wanted ..........................
So even though you're working off a proxy with a header, you're still getting a cookie back that it uses.
Now, that's just context.
My guess, from your description of the symptoms, is that myHttpWebResponse should have a cookie set (DATAZEN_AUTH_TOKEN, I believe), but it's essentially getting thrown out--you aren't using it anywhere.
You would need to tell your browser client to append that cookie to any subsequent (iframe-based) requests to the domain of your Datazen server, but I don't believe that's possible due to security restrictions. I don't know a whole lot about CORS, though, so there might be a way to permit it.
I don't know whether there's any good way to do what you're looking to do here. At best, I can maybe think of a start to a hack that would work, but I can't even find a good way to make that work, and you really wouldn't want to go there.
Essentially, if you're looking to embed Datazen in an iframe, I would shy away from external authentication. I'd shy away from it regardless, but especially there.
But, if you're absolutely sure you need it over something like ADFS, you'll need some way to get that cookie into your iframe requests.
The only way I can think to make this work would be to put everything on the same domain:
www.example.com
datazen.example.com (which is probably your proxy)
You could then set a cookie from your response that stores some encrypted (and likely expiring) form of Session("Email"), and passes it back down in your html.
That makes your iframe relatively simple, because you can just tell it to load the viewer home. Something to the effect of:
<iframe src="//datazen.example.com/viewer/home"></iframe>
In your proxy, you'll detect the cookie set by your web server, decrypt the email token, ensure it isn't expired, then set a header on the subsequent request onto the Datazen server.
This could be simplified at a couple places, but this should hold as true as possible to your original implementation, as long as you can mess with DNS settings.
I suppose another version of this could involve passing a parameter to your proxy, and sharing some common encryption key. That would get you past having to be on the same domain.
So if you had something like:
var emailEncrypted = encrypt(Session("Email") + ":somesalt:" + DateTime.UtcNow.ToString("O"));
Then used whatever templating language you want to set your iframe up with:
<iframe src="//{{ customDomain }}/viewer/home?emailkey={{ emailEncrypted }}"></iframe>
Then your proxy detected that emailkey parameter, decrypted it, and checked for expiration, that could work.
Now you'd have a choice to make on how to handle this, because Datazen will give you a 302 to /viewer/login to get a cookie, and you need to make sure to pass the correct emailkey on through that.
What I would do, you could accept that emailkey parameter in your proxy, set a completely new cookie yourself, then watch for that cookie on subsequent requests.
Although at that point, it would probably be reasonable to switch your external authentication mode to just use cookies. That's probably a better version of this anyway, assuming this is the only place you use Datazen, and you'd be safe to change something so fundamental. That would substantially reduce your business logic.
But, you wouldn't have to. If you didn't want to change that, you could just check for the cookie, and turn it into a header.
You should do (1), but just for good measure, one thing I'm not sure on, is whether you can pass users directly to /viewer/login to get a cookie from Datazen. Normally you wouldn't, but it seems like you should be able to.
Assuming it works as expected, you could just swap that URL out for that. As far as I know (although I'd have to double-check this), the header is actually only necessary once, to set up the cookie. So if you did that, you should get the cookie, then not need the URL parameter anymore, so the forced navigation would be no concern.
You'll, of course, want to make sure you've got a good form of encryption there, and the expiration pattern is important. But you should be able to secure that if you do it right.
I ended up just grabbing the username and password fields and entering them in with javascript. But this piece helped me a ton. You have to make sure you set the
document.domain ='basedomain.com';
in javascript on both sites in order to access the iframe contents else you'll run into the cross-domain issues.

How to create cookie without quotes around value?

I need to create cookie with e-mail address as value - but when I try to - then I have result:
"someone#example.com"
but I would like to have:
someone#example.com
The cookie should be created without double quoted marks - because other application uses it in such format. How to force java to not to add double quoted? Java adds them because there is special char "at".
I create the cookie that way:
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
Cookie cookie = new Cookie("login", "someone#example.com");
cookie.setMaxAge(2592000);
cookie.setDomain("domain.com");
cookie.setVersion(1);
response.addCookie(cookie);
Thanks for any help.
It's indeed caused by the # sign. This is not allowed in version 0 cookies. The container will implicitly force it to become a version 1 cookie (which breaks in MSIE browsers). You'd like to URL-encode the cookie value on cookie's creation
Cookie cookie = new Cookie("login", URLEncoder.encode("someone#example.com", "UTF-8"));
cookie.setMaxAge(2592000);
cookie.setDomain("domain.com");
response.addCookie(cookie);
and URL-decode it on cookie reading
String value = URLDecoder.decode(cookie.getValue(), "UTF-8");
Note that you should for sure not explicitly set the cookie version to 1.
See also:
Why do cookie values with whitespace arrive at the client side with quotes?
Unrelated to the concrete problem, cookies are visible and manipulatable by the enduser or man-in-the-middle. Carrying the email address around in a cookie is a bad smell. What if the enduser changes it to a different address? Whatever functional requirement (remembering the login?) you thought to solve with carrying the email address around in a cookie should most likely be solved differently.
See also:
How do I keep a user logged into my site for months?

Is the name of a cookie case sensitive?

A HTTP Cookie consists of a name-value pair and can be set by the server using this response:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: name=value
Set-Cookie: name2=value2; Expires=Wed, 09 Jun 2021 10:18:14 GMT
Future requests from the client will then look like this:
GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: name=value; name2=value2
Is the name of the cookie case sensitive?
For example, if my server sends a response as such:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: Aaaa=Bbbb
Set-Cookie: aAaa=bBbb
Set-Cookie: aaAa=bbBb
Set-Cookie: aaaA=bbbB
Is it reasonable to expect a client (Chrome, FireFox, Safari, IExplorer, Opera, etc) to send future requests with the header Cookie: Aaaa=Bbbb; aAaa=bBbb; aaAa=bbBb; aaaA=bbbB;?
Note: Question is neither JSP-specific, PHP-specific, nor ASP-specific.
Cookie names are case-sensitive. The RFC does not state that explicitly, but each case-insensitive comparison is stated so explicitly, and there is no such explicit statement regarding the name of the cookie. Chrome and Firefox both treat cookies as case-sensitive and preserve all case variants as distinct cookies.
Test case (PHP):
print_r($_COOKIE);
setcookie('foo', '123');
setcookie('Foo', '456');
Load script twice, observe $_COOKIE dump on second run.
At the bottom is a script that demonstrates Cookie case sensitivity on browsers and .Net framework. Every time it is run, it will insert a cookie named xxxxxxxxxx, with random upper/lower cases. Press F5 to refresh a few times to insert a few cookies.
I have teste it on Chrome and Firefox, and both demonstrate similar behavior, something like below:
Request.Cookies["xxxxxxxxxx"].Name returns: xxxxXxXXXX
All XXXXXXXXXX Cookies:
xxxxXxXXXX
xXxxXxXXXx
XxxxxXxXXx
XXXxXxXXxX
It shows:
Cookies are case sensitive on Chrome and Firefox
.Net Framework can handle case sensitive cookies (that's why it could loop through all those cookies)
Request.Cookies["xxxxxxxxxx"] is case insensitive (that's why it returns the first cookie that case-insensitively matches the name)
As mentioned in other answers, the new RFC indicates that cookies are case sensitive, and both Chrome and Firefox seem to handle it that way. .Net Framework can handle case-sensitive cookies, but it really wants to treat cookies case-insensitively, and many of its functions do treat cookies that way (Cookies[], Cookies.Set() etc.). This inconsistency can cause many hard to track bugs.
TestCookie.aspx:
<%# Page language="c#" AutoEventWireup="false" validateRequest=false %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title id="title">Test Cookie Sensitivity</title>
</head>
<body>
<p>Request.Cookies["xxxxxxxxxx"].Name returns:
<%
HttpCookie cookie2 = Request.Cookies["xxxxxxxxxx"];
if (cookie2 == null) Response.Write("No cookie found");
else Response.Write(cookie2.Name);
%>
</p>
<h3>All XXXXXXXXXX Cookies:</h3>
<ul>
<%
foreach (string key in Request.Cookies.Keys)
if (key.ToLower() == "xxxxxxxxxx") Response.Write("<li>" + key + "</li>");
Random rand = new Random();
StringBuilder name = new StringBuilder();
for (int i = 0; i < 10; i++) {
if (rand.Next(2) == 0) name.Append('x');
else name.Append('X');
}
HttpCookie cookie = new HttpCookie(name.ToString());
cookie.HttpOnly = true;
cookie.Expires = DateTime.Now.AddMonths(1);
Response.Cookies.Add(cookie);
%>
</ul>
</body>
</html>
It seems cookies are actually case sensitive. Theres some confusion with this. It is interesting that the MSDN says otherwise:
Cookie names are NOT case-sensitive
Source: http://msdn.microsoft.com/en-us/library/ms970178.aspx the bottom of the article says it's ©2002 so it might be outdated.
Also, the question has been asked in the asp.net forums, too: http://forums.asp.net/t/1170326.aspx?Are+cookie+names+case+sensitive+ and it seems the answer is case-sensitive.
What's going on? MSDN says no, other technologies say yes. To be sure, I tested this using ASP classic.
Code
hashUCASE = Request.Cookies("data")("Hash")
hashLCASE = Request.Cookies("data")("hash")
Response.Write "<p> hashUCASE = " & hashUCASE
Response.Write "<br> hashLCASE = " & hashLCASE
cookieNameUCASE = Request.Cookies("Data")
cookieNameLCASE = Request.Cookies("data")
Response.Write "<p> cookieNameUCASE = " & cookieNameUCASE
Response.Write "<br> cookieNameLCASE = " & cookieNameLCASE
Response.End
Results
hashUCASE: EE3305C0DAADAAAA221BD5ACF6996AAA
hashLCASE: EE3305C0DAADAAAA221BD5ACF6996AAA
cookieNameUCASE: name=1&Hash=EE3305C0DAADAAAA221BD5ACF6996AAA
cookieNameLCASE: name=1&Hash=EE3305C0DAADAAAA221BD5ACF6996AAA
As you can see in the results, the value "Hash" was created with uppercase and even when you make the request with lower case, it returns the same value, which makes it not case-sensitive. Under this MS technology, it is not.
Conclusion
So, using Request.Cookies() in ASP classic, it's not case-sensitive, like Microsoft says. But wait, isn't it case sensitive again? This may mean that whether sensitive or not depends on the server side technology that makes the request to the browser, which could be normalizing the cookie name to make the requests and thus making it not case sensitive. But that's something else we'll have to test to verify.
My advice is to make tests with whatever technology you are using and establish a standard in your code base, make an agreement with your team. i.e. if you're going to use a cookie, decide if it will always be written in lowercase or uppercase anytime you are going to use it in your code. That way there won't be any case sensitivity problems because in your code it will be always declared with the same case.
tl;dr
As long as you keep a convention with the cookie names you won't have problems with case sensitivity.
According to RFC 2109 - HTTP State Management Mechanism cookie names aka attribute names are case insensitive:
4.1 Syntax: General
The two state management headers, Set-Cookie and Cookie, have common
syntactic properties involving attribute-value pairs. The following
grammar uses the notation, and tokens DIGIT (decimal digits) and
token (informally, a sequence of non-special, non-white space
characters) from the HTTP/1.1 specification [RFC 2068] to describe
their syntax.
av-pairs = av-pair *(";" av-pair)
av-pair = attr ["=" value] ; optional value
attr = token
value = word
word = token | quoted-string
Attributes (names) (attr) are case-insensitive. White space is
permitted between tokens. Note that while the above syntax
description shows value as optional, most attrs require them.
According to MSDN, cookies name are NOT case sensitive. However, I'm not sure if that's just ASPX/IIS specific implementation. I believe it depends on the web server and the language as well.
If you send a cookie named "UserID", the browser will make sure they send it back as "UserID", not "userid".

Storing multiple values in cookies

I have very large website which uses a lot of cookies. There are approx. 14 different cookies are there. I have different cookies for each item. When a user surfs the site they will have 14 cookies in their browser. I do not want this.
I want a single cookie for my site that will have 14 items and I can add,edit and delete them. I tried many ways but I am not able to do this.
I need to put some run time cookies as well save the user name in cookie. After the user logs in I want to save their personal site address in it. Eventually I want both the user name and personal site address both. I want to save user name before and then when user goes to his personal site then i will store personal site name run time.
Does any one have an idea how I could do this?
Matthew beat me to it, but yes, see the ASP.NET Cookies Overview...
To write and read a single cookie with multiple key/values, it would look something like this:
HttpCookie cookie = new HttpCookie("mybigcookie");
cookie.Values.Add("name", name);
cookie.Values.Add("address", address);
//get the values out
string name = Request.Cookies["mybigcookie"]["name"];
string address = Request.Cookies["mybigcookie"]["address"];
There is a section in the ASP.NET Cookies Overview that discusses how to implement multiple name-value pairs (called subkeys) in a single cookie. I think this is what you mean.
The example from that page, in C#:
Response.Cookies["userInfo"]["userName"] = "patrick"; //userInfo is the cookie, userName is the subkey
Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString(); //now lastVisit is the subkey
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);
HttpCookie aCookie = new HttpCookie("userInfo");
aCookie.Values["userName"] = "patrick";
aCookie.Values["lastVisit"] = DateTime.Now.ToString();
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
EDIT: From the Cookies Overview (emphasis added):
Modifying and Deleting Cookies:
You
cannot directly modify a cookie.
Instead, changing a cookie consists of
creating a new cookie with new values
and then sending the cookie to the
browser to overwrite the old version
on the client.
Modifying and Deleting Cookies: You cannot directly modify a cookie. Instead, changing a cookie consists of creating a new cookie with new values and then sending the cookie to the browser to overwrite the old version on the client.

Setting cookie by calling webpage by Microsoft.XMLHTTP

The situation:
I have 2 webpages with 2 domains (backoffice.myurl.com & www.myurl.com).
The backoffice is written in classic asp, the frontend in asp.net 3.5 (vb.net)
When I hit a button in the backoffice, I want to set a cookie on the frontend.
I do this by calling a page on the frontend via Microsoft.XMLHTTP
Dim GetConnection
Set GetConnection = CreateObject("Microsoft.XMLHTTP")
GetConnection.Open "POST", webserviceLocation, False
GetConnection.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
GetConnection.Send("data=" &value)
In the aspx code I read the posted value and put it in a cookie:
If Not Request.Cookies("mytest3") Is Nothing Then
Response.Cookies("mytest3").Expires = Now.AddYears(-23)
End If
Response.Cookies.Set(New HttpCookie("mytest3", Request.Form.Item("data")))
Response.Cookies("mytest3").Expires = DateTime.Now.AddYears(30)
On another page on the frontend I want to read that cookie:
Request.Cookies("mytest3").Value
but the Request.Cookies("mytest3") is 'nothing' there.
Apparently the cookie is not set. What am I doing wrong or how can I solve this?
The pages are called (my debugger hits the breakpoints)
Is this even possible at all?
When creating the cookie you need to explicitly set the domain:
' I do not remember if the value should be set to myurl.com or .myurl.com
' Please test
Response.Cookies("mytest3").Domain = "myurl.com"
This way the browser will send the cookie along each request to *.myurl.com
Darin has answered your question but you have another problem with this line:-
Response.Cookies("mytest3").Expires = Now.AddYears(-23)
The response Cookie collection is a differentc collection to that of the Request collection. The response cookies is always empty until code specifically adds a cookie to it. Hence the above line will fail.

Resources