[Java / .NET] Cookies van Android naar .NET Webservice

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 25-05 11:39
Hoi,

Ik ben bezig met een Android applicatie (in Java) die communiceert mijn een .NET Webservice. Heel simpel gezegd stuurt de Android app een URL naar de webservice, waar de (html source van de) webpagina onder die URL wordt gedownload. De html wordt dan geparsed en alleen de info die de app nodig heeft wordt terug gestuurd.

De webpagina's die de webservice moet downloaden hebben echter authenticatie nodig, als je niet ingelogd bent word je gewoon naar de login pagina gestuurd. De webservice heeft dus inlog gegevens nodig om aan de html te kunnen komen.
Ik kan mijn webservice "laten inloggen" door een http POST te doen (met username/password parameters) naar de login pagina. Als ik daarna dezelfde CookieContainer van de gebruikte HttpWebRequest gebruik voor elke volgende request dan heb ik de juiste cookies om ingelogd te zijn en heb ik toegang tot de pagina's, vanuit mijn webservice.

Elke gebruiker van de Android app heeft in principe zijn eigen inlog gegevens (email + wachtwoord), waarmee ze moeten inloggen, echter wil ik om verschillende redenen niet deze gegevens van de Android app naar mijn webservice gaan sturen. Ik heb het wachtwoord op de webservice (om in te loggen) uiteraard in plain text nodig (ik kan het dus niet gehashed oversturen want daarmee kan ik niet inloggen), maar dat maakt het onderscheppen van hele lijsten met email/wachtwoord combinaties dus vrij eenvoudig lijkt me - niet de bedoeling. Ook al zou ik op een of andere manier veilig het wachtwoord op mijn server krijgen, dan nog moeten gebruikers mij maar vertrouwen dat ik er niks mee doen (ik zou natuurlijk fijn een database kunnen opbouwen met iedereen z'n account gegevens).

Om te voorkomen dat ik gevoelige data ga oversturen (en potentieel opslaan) had ik het volgende bedacht:
1. Het inloggen gebeurt volledig aan de Android kant. Ik gebruik een http POST in de app om zo aan de nodige cookies te komen.
2. Daarna stuur ik de cookies gewoon door naar de webservice.
3. Op de webservice bouw ik een nieuwe CookieContainer van deze cookies, die ik dan zou kunnen gebruiken om in te loggen.

Op deze manier stuur ik alleen de cookie data door en geen wachtwoorden.


De manier waarop ik dit doe is als volgt. Aan de Android kant gebruik ik de volgende code om een username + password te gebruiken om in te loggen en sla ik de cookies op in het User object:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    public static User getLogin(String username, String password)
    {
        User user = new User();
        user.username = username;
                
        DefaultHttpClient httpclient = new DefaultHttpClient();
        try 
        {           
            HttpPost httpost = new HttpPost("https://members.iracing.com/membersite/Login");

            List <NameValuePair> nvps = new ArrayList <NameValuePair>();
            nvps.add(new BasicNameValuePair("username", username));
            nvps.add(new BasicNameValuePair("password", password));

            httpost.setEntity(new UrlEncodedFormEntity(nvps));

            HttpResponse response = httpclient.execute(httpost);
            HttpEntity entity = response.getEntity();

            List<Cookie> cookies = httpclient.getCookieStore().getCookies();
            
            if (cookies.isEmpty()) 
            {
                System.out.println("No cookies");
                return null;
            } 
            else 
            {               
                user.cookies.clear();
                user.cookies.addAll(cookies);
            }

        } 
        catch (Exception ex)
        {
            System.out.println("Exception:   " + ex.toString());
            return null;
        }
        finally 
        {
            httpclient.getConnectionManager().shutdown();
        }       
        
        return user;
    }


Dit User object wordt daarna (in JSON format) naar mijn webservice gestuurd. De cookies worden verstuurd als 3 arrays: de namen, de waardes en de domains. Hiermee bouw ik daarna een nieuwe CookieContainer die ik voor elke request op de webservice wil gebruiken om de gebruiker te authenticeren:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        public CookieContainer GetCookies(string[] cookieNames, string[] cookieValues, string[] cookieDomains)
        {
            var container = new CookieContainer();
            var uri = new Uri("http://members.iracing.com");
            var length = cookieNames.Length;
            if (cookieValues.Length == length && cookieDomains.Length == length)
            {
                for (int i = 0; i < length; i++)
                {
                    var cookie = new Cookie(cookieNames[i], cookieValues[i]);
                    cookie.Domain = domains[i];

                    container.Add(uri, cookie);
                }
            }

            return container;
        }


Nu ik dit ga testen lijkt het echter niet te werken om een hele stomme reden. Stel dat ik de gebruiker een lijst met threads wil tonen een bepaalde URL. De webservice zou dan de html source van die pagina moeten downloaden, echter zie ik dmv debuggen dat hij een heel andere pagina voorgeschoteld krijgt: namelijk een (andere) login pagina met een waarschuwing dat ik Javascript aan moet zetten...

Het lijkt er dus op dat de website denkt dat ik geen Javascript heb draaien. Nou ja, "ik" ben nou eenmaal geen browser maar een simpele HttpWebRequest, dus daar kan ik inkomen. Het vreemde is nu dat dit wel werkt als ik de webservice lokaal aan het debuggen ben!!

Als ik mijn project debug en gewoon via het ingebouwde webservice 'test formulier' de parameters ingeef, dan krijg ik netjes de juiste pagina source te zien. De cookie parameters haal ik dan rechtstreeks uit de Android app (die heb ik op de achtergrond in debug mode draaien en copy/paste daar gewoon de cookie names, values en domains uit). Voor zover ik kan zien ben ik dus exact hetzelfde aan het doen als in een live omgeving met het enige verschil dat de webservice nu lokaal draait en niet op mijn webserver (wel exact dezelfde code), en op die manier werkt het wel, ik word niet doorgelinkt naar een 'please enable javascript' site en ik krijg alles gewoon mooi door. Zodra ik de code op m'n webserver zet en met dezelfde parameters aanroep werkt het niet meer en gaat hij dus zeuren dat ik geen javascript heb.


Wat kan voor dit verschil zorgen? Mis ik bepaalde cookies die gebruikt worden om te bepalen of javascript enabled is of niet? Als ik het forum met Chrome benader terwijl de Developer Tools draaien (waarmee ik de cookies kan inzien) dan zie ik wel vergelijkbare cookies maar niet exact dezelfde.

Heeft iemand enig idee waar dit aan kan liggen en wat ik er aan kan doen om niet doorgestuurd te worden naar de 'enable javascript' pagina?

Bedankt!

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
website of webservice?

als je in c# een website maakt en die gaat gebruiken als webservice zou het idd kunnen dat dat ding allerlei eisen stelt aan je client.
Je moet wel echt een webservice bouwen.

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • DennusB
  • Registratie: Mei 2006
  • Niet online
Waarom geef je niet elke user gewoon een API key? Lijkt me dan toch vrij makkelijk op te lossen zonder dat je gebruikersnamen & wachtwoorden unencrypted heen en weer gaat sturen!

Owner of DBIT Consultancy


Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
DennusB schreef op vrijdag 07 december 2012 @ 16:12:
Waarom geef je niet elke user gewoon een API key? Lijkt me dan toch vrij makkelijk op te lossen zonder dat je gebruikersnamen & wachtwoorden unencrypted heen en weer gaat sturen!
(https is ook een optie)

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • DennusB
  • Registratie: Mei 2006
  • Niet online
Uiteraard :) Maar ik bedoel als je niet wilt kutten met user gegevens verstuur je alleen een API key mee met je request over https. Probleem opgelost.

Owner of DBIT Consultancy


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 25-05 11:39
BasieP schreef op vrijdag 07 december 2012 @ 16:09:
website of webservice?

als je in c# een website maakt en die gaat gebruiken als webservice zou het idd kunnen dat dat ding allerlei eisen stelt aan je client.
Je moet wel echt een webservice bouwen.
Wat bedoel je met "je client"? Volgens mij is het gewoon een webservice.. Hoe zie ik precies het verschil?

De communicatie met de webservice (vanuit Android naar webservice) verloopt trouwens prima. Echter op de webservice zelf gaat het mis. Daar gebruik ik een HttpWebRequest om een webpagina (forum pagina) op te halen, en dat gaat mis omdat hij doorgestuurd wordt naar een "please enable javascript" pagina (en dus niet de pagina die ik moet hebben...) Ik heb niks van doen met Javascript, ik moet gewoon de pure html hebben, maar hij laat me gewoon niet toe zonder javascript (en met een HttpWebRequest snap ik best dat er geen javascript functionaliteit is).
DennusB schreef op vrijdag 07 december 2012 @ 16:12:
Waarom geef je niet elke user gewoon een API key? Lijkt me dan toch vrij makkelijk op te lossen zonder dat je gebruikersnamen & wachtwoorden unencrypted heen en weer gaat sturen!
Wat bedoel je precies met API key? Klinkt als een unieke key per gebruiker die voor authenticatie wordt gebruikt. Dat gaat natuurlijk niet werken, daarmee kan ik gebruikers wel op mijn webservice authenticeren, maar ik moet ze op een (third party) website kunnen authenticeren waar ik geen controle over heb. Zolang die website enkel inloggen met username/password toelaat ben ik daar ook tot gelimiteerd...

Ik moet de gebruiker kunnen inloggen vanuit mijn webservice. Aangezien ik geen controle heb over de website waarbij ik heb wil inloggen heb ik volgens mij maar twee opties:

1. Het wachtwoord plaintext naar de service sturen (of encrypted, https, whatever, zolang het maar plaintext te gebruiken is) en daarmee inloggen,

2. Inloggen voordat de communicatie met webserver plaatsvind en de cookies doorsturen.

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 01:23

Janoz

Moderator Devschuur®

!litemod

Ik begrijp dat je geen controle hebt over de website. Iets als een api key of andere inlog methoden waarbij je webserver niet het wachtwoord nodig heeft zijn in dat geval niet mogelijk. Je zou inderdaad kunnen kijken of je de sessie kunt hijacken (dat is in feite wat je doet wanneer je de cookie van de android telefoon overneemt), maar naast dat dit heel erg lastig is, bestaat ook nog eens de kans dat de site daar tegen beveiligd wordt (of gaat worden).

De enige optie die overblijft is inderdaad het wachtwoord 'plaintext' oversturen. Echter, zolang je dat met https doet is dat niet zomaar te sniffen. Gebruik je het vervolgens enkel om in te loggen (en sla je het dus niet op bij je webservice) dan is de kans alweer een stukje kleiner dat iemand al die credentials weet te achterhalen.

Het enige probleem wat blijft is dat je gebruikers je maar op je blauwe ogen moeten geloven dat je fatsoenlijk met hun gegevens om gaat. En zolang de website niet aangepast wordt zal dat het maximaal haalbare zijn.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 25-05 11:39
Ik was al bang dat het overnemen van cookies op deze manier misschien niet helemaal zou 'kloppen' (echter lijkt het vooralsnog te werken, maar dan alleen vanaf een lokale debug server). Helaas, dan lijkt er dus inderdaad geen manier te zijn om het werkend te krijgen zonder het wachtwoord nodig te hebben. Dan blijf ik maar bij mijn huidige manier. Overigens sla ik het wachtwoord nergens fysiek op (niet in een database of in een ander bestand ofzo), maar het staat uiteraard wel in het geheugen. Zou dat nog een potentieel gevaar kunnen leveren, stel dat de server gehacked wordt? Stel dat ik een lijstje met User objects heb die allemaal gewoon een Password property hebben, is dat lijstje uit het geheugen uit te lezen door een hacker ook al staat het nergens opgeslagen, en kan ik er nog veiliger mee omgaan op een of andere manier (zo snel mogelijk dat geheugen weer vrijgeven ofzo?).


Kan iemand nog een manier bedenken waarop ik het (ook voor een leek) een beetje geloofwaardig kan maken dat ik niks uithaal met de wachtwoorden? Ik neem aan dat 99% er niks om geeft maar wellicht zijn er wat mensen die besluiten de app niet te gebruiken uit voorzorg. Ik zou natuurlijk de hele zooi open source kunnen maken en op een of andere manier aan kunnen tonen dat ik inderdaad de code draai die ze zelf kunnen inzien (ik heb hier geen ervaring mee maar ik neem aan dat dit wel kan?), maar de kans dat iemand de moeite gaat nemen om dat na te kijken is zo goed als 0 dus die moeite ga ik ook niet doen.

Mijn iRacing profiel


Acties:
  • 0 Henk 'm!

  • creator1988
  • Registratie: Januari 2007
  • Laatst online: 02-07 20:41
NickThissen schreef op vrijdag 07 december 2012 @ 23:29:
Ik was al bang dat het overnemen van cookies op deze manier misschien niet helemaal zou 'kloppen' (echter lijkt het vooralsnog te werken, maar dan alleen vanaf een lokale debug server). Helaas, dan lijkt er dus inderdaad geen manier te zijn om het werkend te krijgen zonder het wachtwoord nodig te hebben. Dan blijf ik maar bij mijn huidige manier. Overigens sla ik het wachtwoord nergens fysiek op (niet in een database of in een ander bestand ofzo), maar het staat uiteraard wel in het geheugen. Zou dat nog een potentieel gevaar kunnen leveren, stel dat de server gehacked wordt? Stel dat ik een lijstje met User objects heb die allemaal gewoon een Password property hebben, is dat lijstje uit het geheugen uit te lezen door een hacker ook al staat het nergens opgeslagen, en kan ik er nog veiliger mee omgaan op een of andere manier (zo snel mogelijk dat geheugen weer vrijgeven ofzo?).
SecureString class gebruiken of een char[] die je daarna cleared i.p.v. normale string.

De 3rd party zou een auth API moeten aanbieden als OAuth, dan heb je dit gedoe niet.
Pagina: 1