Double quotes and trailing equal sign missing from cookies values in ServletExec - servlets

I have a servlet app which stores cookies as base64-encoded strings. On a server where the app is running on ServletExec, the cookies' values are not wrapped in quotes. Additionally, if the value ends with a '=' character, that character is removed. The missing quotes and trailing '=' prevent the cookies' values from being parsed properly. In 2 other servers where this app is running on ServletExec and Tomcat where this app is working, the cookies are wrapped in double quotes and the trailing '=' sign is not removed.
As seen in a browser's developer tool:
Bad - cookiename:dGVzdHN0cmluZzE
Expected - cookiename:"dGVzdHN0cmluZzE="
Any idea what's stripping out the quotes and the trailing '=' sign? TIA!

By default, the servlet Cookie class follows the Version 0 cookie spec. Here's a cite from the javadoc:
This class supports both the Version 0 (by Netscape) and Version 1 (by RFC 2109) cookie specifications. By default, cookies are created using Version 0 to ensure the best interoperability.
Version 0 cookie values are restrictive in allowed characters. It only allows URL-safe characters. This covers among others the alphanumeric characters (a-z, A-Z and 0-9) and only a few lexical characters, including -, _, ., ~ and %. All other characters are invalid in version 0 cookies, including " and =. If the server doesn't already do it, the browser will swallow the invalid characters.
Your best bet is to URL-encode those characters. This way every character which is not allowed in URLs will be percent-encoded in this form %xx which is valid as cookie value.
So, when creating the cookie do:
Cookie cookie = new Cookie(name, URLEncoder.encode(value, "UTF-8"));
// ...
And when reading the cookie, do:
String value = URLDecoder.decode(cookie.getValue(), "UTF-8");
// ...
An alternative is to switch to Version 1 cookies via Cookie#setVersion(), but this isn't supported in IE<=11.

Related

Is the "?" in URLs completely arbitrary (disregarding reserved/non-escaped character problems, etc.)?

For example, if for whatever stupid reason I configured my server to parse the URL by splitting the queries by the "^" symbol (escaped if necessary) and the "-" symbol instead of the "?" and "&", would I run into any trouble at all apart from a confused user?
Will the browser/HTTP request sent treat it differently in a way that may be detrimental to my up and coming "power minus" business?
? is not arbitrary but defined in the URI RFC section 3.4 Query, I dont' think you can change that.
The Query component internal syntax (how name=value couples are encoded) is not defined by the URI RFC, separators can be defined by other specifications:
& is defined as separator of the application/x-www-form-urlencoded content type by HTML Spec. You may change this aspect supporting for example ; as separator, but you would have in any case to support & for when processing the request produced by an HTML FORM.

User info in URI without password

I know that URI supports the following syntax:
http://[user]:[password]#[domain.tld]
When there is no password or if the password is empty, is there a colon?
In other words, should I accept this:
http://[user]:#[domain.tld]
Or this:
http://[user]#[domain.tld]
Or are they both valid?
The current URI standard (STD 66) is RFC 3986, and the relevant section is 3.2.1. User Information.
There it’s defined that the userinfo subcomponent (which gets followed by #) can contain any combination of
the character :,
percent-encoded characters, and
characters from the sets unreserved and sub-delims.
So this means that both of your examples are valid.
However, note that the format user:password is deprecated. Anyway, they give recommendations how applications should handle such URIs, i.e., everything after the first : character should not be displayed by applications, unless
the data after the colon is the empty string (indicating no password).
So according to this recommendation, the userinfo subcomponent user: indicates that there is the username "user" and no password.
This is more like convenience and both are valid. I would go with http://[user]#[domain.tld] (and prompt for a password.) because it's simple and not ambiguous. It does not give any chance for user to think if he has to add anything after :

Why is ASP.NET 4 / IIS7 html-encoding my query string?

We've switched one of our test environments to using .NET 4 on IIS7. Production is using .NET 2.
Certain urls, such as
http://www.example.com/page.aspx?param1=<foo>&param2=<foo>
Aren't getting caught by our stringindex code that looks for < or > in Request.Url.ToString(). Why? Because they're showing up as <foo> when we check. This worked in .NET 2.
What is going on?
NOTE: there are no mistakes in the formatting. I really mean HTML encode.
All data in query string needs to be URL Encoded to be able to parse correctly, so if you want to grab what you entered you need to URL Decode the query string.
HttpServerUtility.UrlDecode(Request.QueryString);
http://msdn.microsoft.com/en-us/library/6196h3wt.aspx :
URL encoding ensures that all browsers will correctly transmit text in URL strings. Characters such as a question mark (?), ampersand (&), slash mark (/), and spaces might be truncated or corrupted by some browsers. As a result, these characters must be encoded in tags or in query strings where the strings can be re-sent by a browser in a request string.

ampersand in URL of RSS Feed

As part of our app, user can save some data as XML on server which becomes RSS feed for them.
Now some of the file user created have & in file name as BB&T_RSS.xml.
So when user point this to http://example.com/BB&T.xml, they won't get this.
How to stop this? I tried BB%26T.xml, BB&T.xml without any success with IE, Chrome
use an
%26
for an
&
http://example.com/BB%26T.xml,
http://www.w3schools.com/tags/ref_urlencode.asp
then use
HttpServerUtility.UrlDecode Method
to get the file from the url again
URL encoding ensures that all browsers will correctly transmit text in URL strings. Characters such as a question mark (?), ampersand (&), slash mark (/), and spaces might be truncated or corrupted by some browsers. As a result, these characters must be encoded in tags or in query strings where the strings can be re-sent by a browser in a request string.
Many URL schemes reserve certain characters for a special meaning:
their appearance in the scheme-specific part of the URL has a
designated semantics. If the character corresponding to an octet is
reserved in a scheme, the octet must be encoded. The characters ";",
"/", "?", ":", "#", "=" and "&" are the characters which may be
reserved for special meaning within a scheme. No other characters may
be reserved within a scheme. (src)

Why do cookie values with whitespace arrive at the client side with quotes?

I'm a .NET developer starting to dabble in Java.
In .NET, I can set the value of a cookie to a string with white space in it:
new HttpCookie("myCookieName", "my value") - and when I read that value on the client side (JavaScript), I get the value I expected (my value).
If I do the same thing in a Java servlet - new Cookie("myCookieName", "my value"), I get the value including the double quotes ("my value").
Why the difference? Am I missing something? How do people handle this in the Java world? Do you encode the value and then you decode on the client side?
When you set a cookie value with one of the following values as mentioned in Cookie#setValue(),
With Version 0 cookies, values should not contain white space, brackets, parentheses, equals signs, commas, double quotes, slashes, question marks, at signs, colons, and semicolons. Empty values may not behave the same way on all browsers.
then the average container will implicitly set the cookie to version 1 (RFC 2109 spec) instead of the default version 0 (Netscape spec). The behaviour is not specified by the Servlet API, the container is free to implement it (it may for example throw some IllegalArgumentException). As far as I know, Tomcat, JBoss AS and Glassfish behave all the same with regard to implicitly changing the cookie version. For at least Tomcat and JBoss AS this is the consequence of fixes for this security issue.
A version 1 cookie look like this:
name="value with spaces";Max-Age=3600;Path=/;Version=1
while a version 0 compatible cookie look like this:
name=value%20with%20spaces;Expires=Mon, 29-Aug-2011 14:30:00 GMT;Path=/
(note that an URL-encoded value is valid for version 0)
Important note is that Microsoft Internet Explorer doesn't support version 1 cookies. Even not the current IE 11 release. It'll interpret the quotes being part of the whole cookie value and will treat and return that accordingly. It does not support the Max-Age attribute and it'll ignore it altogether which causes that the cookie's lifetime defaults to the browser session. You was apparently using IE to test the cookie handling of your webapp.
To support MSIE as well, you really need to URL-encode and URL-decode the cookie value yourself if it contains possibly characters which are invalid for version 0.
Cookie cookie = new Cookie(name, URLEncoder.encode(value, "UTF-8"));
// ...
and
String value = URLDecoder.decode(cookie.getValue(), "UTF-8"));
// ...
In order to support version 1 cookies for the worldwide audience, you'll really wait for Microsoft to fix the lack of MSIE support and that the browser with the fix has become mainstream. In other words, it'll take ages (update: as of now, 5+ years later, it doesn't seem to ever going to happen). In the meanwhile you'd best stick to version 0 compatible cookies.
As far as I know, spaces must be encoded in cookies. Different browsers react differently to un-encoded cookies. You should URL-encode your cookie before setting it.
String cookieval = "my value";
String cookieenc = URLEncoder.encode(cookieval, "UTF-8");
res.addCookie(new Cookie("myCookieName", cookieenc));
ASP.NET does the encoding automatically, in Java you have to do it yourself. I suspect the quotes you see are added by the user agent.
It probably has to do with the way Java encodes the cookie. I suggest you try calling setVersion(1) on the new cookie and see if that works for you.
Try using setVersion(0).
HttpCookie cookie = new HttpCookie("name", "multi word value");
System.out.println(cookie.toString());
prints:
name="several word value"
But after setting
cookie.setVersion(0);
System.out.println(cookie.toString());
prints:
name=several word value
Encoding is a good idea too, but the quotes around the value look to be an independent issue.

Resources