11

I have an app that sends a username and password to an API via HTTPS. The API returns HTTPOnly cookies.

This means that the cookies are "invisible" to the code, but still exist and will be sent to the server in subsequent requests.

The Set-Cookie header is stripped from the HttpWebResponse.Headers and the cookie does not appear in the HttpWebResponse.Cookies or the HttpWebRequest.CookieContainer. However, if a subsequent request is made using that same HttpWebRequest.CookieContainer they are sent to the server, but they are inaccessible to the code.

As far as I can tell, this makes them impossible to serialize or preserve in any way. It seems the only way to make this work will be to cache the actual username and password and login again every time.

Is there something I am missing?

carbin
  • 2,907
  • 2
  • 28
  • 36
  • Could you serialize the entire `CookieContainer` (http://answers.flyppdevportal.com/categories/metro/csharpvb.aspx?ID=d214c388-41de-44b7-8260-9e21f3fcb859) and reuse the entire container when required? – keyboardP Apr 06 '13 at 13:46
  • You cannot manipulate httponly cookie. They are modified only when you send http requests. It is essential for secure communication between server and client. So this behaviour you are facing is normal. – user568109 Apr 06 '13 at 14:25
  • @keyboardP If you serialize the CookieContainer, when it is unserialized the cookies are no longer sent. – carbin Apr 06 '13 at 15:29
  • I'm currently looking into the same problem. Just to be sure that I understand you correctly: You did assign your HttpWebRequest a new Cookie Container and got an empty CookieContainer in your HttpWebResponse. However, you use this container and pass it to all your subsequent Requests and the received httponly cookies are used? From my readings I would support user568109 thesis that it is impossible to temper with the httponly cookie object inside the cookie container. That's why its propably always empty :( – Markus Rudel Apr 08 '13 at 08:09
  • NewsBlur API by any chance? That's where I have run into this, and my only solution was to login every time the app starts. I am hoping that a move to oauth will be made soon... – calum Apr 09 '13 at 08:17
  • @MarkusRudel Yes, that's what happens. It seems WP hits this because it uses the Silverlight runtime and Silverlight is (rightly) prevented from accessing HTTPOnly cookies, but fully fledged phone applications really should be able to serialize cookies. I can only assume every other WP app hits this problem and handles it by logging in each time. – carbin Apr 09 '13 at 17:52

2 Answers2

3

You'll have to use reflection to take a look at the Cookies stored in the cookie container.

Use something like this to have a look at what you have, then you can either try to subclass to gain access to the data you want or go through the process of storing the cookie in memory, deleting it from the container, then adding it as a normal cookie

    public List<Cookie> GetAllCookies(CookieContainer cc)
    {
        List<Cookie> lstCookies = new List<Cookie>();

        Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cc, new object[] { });

        foreach (var pathList in table.Values)
        {
            SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
            foreach (CookieCollection colCookies in lstCookieCol.Values)
                foreach (Cookie c in colCookies) lstCookies.Add(c);
        }

        return lstCookies;
    }
    public string ShowAllCookies(CookieContainer cc)
    {
        StringBuilder sb = new StringBuilder();
        List<Cookie> lstCookies = GetAllCookies(cc);
        sb.AppendLine("=========================================================== ");
        sb.AppendLine(lstCookies.Count + " cookies found.");
        sb.AppendLine("=========================================================== ");
        int cpt = 1;
        foreach (Cookie c in lstCookies)
            sb.AppendLine("#" + cpt++ + "> Name: " + c.Name + "\tValue: " + c.Value + "\tDomain: " + c.Domain + "\tPath: " + c.Path + "\tExp: " + c.Expires.ToString());

        return sb.ToString();
    }
Steve Kallestad
  • 3,484
  • 2
  • 23
  • 31
  • Do you not get a MethodAccessException when using reflection to access non-public types on Windows Phone? Every time I have tried to do this it has failed. – calum Apr 13 '13 at 10:01
  • good catch. internal and protected should be OK, but private definitely isn't. Looking at the source for CookieContainer, this should work. If not, it will be a matter of building a custom cookie container class based on the source and leveraging that instead. – Steve Kallestad Apr 13 '13 at 10:17
  • I can't even compile this code on WP8 (Hashtable, SortedList are missing). – altso Aug 13 '13 at 13:40
  • @altso - You should be able to adapt the code pretty easily to use list and dictionary collections instead. It was just an example. The concept remains the same. – Steve Kallestad Aug 26 '13 at 22:40
  • @zaitsman I can't recall any details, but I was not able to make this code working. – altso Mar 26 '14 at 13:47
1

You can also try using TCP Sockets to get the cookies directly. Here's my answer for a similar question: https://stackoverflow.com/a/21737087/262036

Once you get the response you parse the string in search for the cookie and grab the value. After that you can create a new cookie in the CookieContainer that is not HttpOnly and use it in next requests.

Community
  • 1
  • 1
Ajadex
  • 2,319
  • 1
  • 20
  • 23