Inloggen op Skyforge website met cURL

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Dit is geen illegale actie, maar een legale poging omdat ik ermee ga inloggen met eigen login.
Aantal mensen kennen Skyforge wel, het is mmo spel dat vrij kort geleden dit jaar begonnen is met open beta. Ik ben leader van een pantheon / guild en het wordt steeds meer werk om alles met de hand in te voeren, want een guild daar kan wel 250 players groot worden.

Helaas heeft Skyforge op dit moment geen API hiervoor, maar ze hebben wel alles webbased informatie staan. Die krijg ik alles te zien nadat ik heb ingelogd.
Nou is de bedoeling om data van mijn pantheon te kunnen lezen, parsen en verwerken in een eigen administratie systeem dat ik straks wil maken.

De eerste uitdaging is goed inloggen met cURL. Uiteraard op de beveiligde pagina van Skyforge. Het is gelukt om login pagina in te lezen, velden invullen en vervolgens uitvoeren. Maar de login proces is geen gewoon systeem.

De form data loopt eerst naar andere pagina, een speciale server pagina, die gegevens controleert en vervolgens terugstuurt met aangegeven pagina, of login gelukt is of niet, of ik ben ingelogd.
Ik stuur dus data naar de speciale pagina.

De code is al opgebouwd om te kijken of hele proces goed loopt. Ik kan op 2 manieren doen, zonder cert controle (negeert dus valid cert) of met cert controle met bewaarde cert blauwdruk. De eerste werkt, de tweede geeft al wat problemen in het begin.

PHP:
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<?php

//username and password of account
$EMAIL = trim($_POST["login"]);
$PASSWORD = trim($_POST["password"]);
$remember = "";
$login_form = "Log In";
$continue = "http://account.my.com/login_continue/?continue=http%3A%2F%2Faccount.my.com";
$failure = "http://account.my.com/login/?continue=http%3A%2F%2Faccount.my.com";
$nosavelogin = "0";

// options
$cookie_file_path = "/tmp/cookies.txt";
$LOGINURL         = "https://account.my.com/login/"; 
$agent            = "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0";

if ($EMAIL<>"")
    {

// begin script
$ch = curl_init(); 

// extra headers
$headers[] = "Accept: */*";
$headers[] = "Connection: Keep-Alive";
$headers[] = "Content-type: application/x-www-form-urlencoded;charset=UTF-8";

// basic curl options for all requests
// curl_setopt($ch, CURLOPT_HTTPHEADER,  $headers);
curl_setopt($ch, CURLOPT_HEADER,  1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
// curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "certificate.my.com.crt");       
curl_setopt($ch, CURLOPT_USERAGENT, $agent); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file_path); 
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file_path); 
// Timeout in seconds
curl_setopt($ch, CURLOPT_TIMEOUT, 20);

// set first URL
curl_setopt($ch, CURLOPT_URL, $LOGINURL);

// execute session to get cookies and required form inputs
$content = curl_exec($ch); 

// grab the hidden inputs from the form required to login
$fields = getFormFields($content);
if ($fields<>"ERROR")
    {
    $result="Fields found";
    $fields['email'] = $EMAIL;
    $fields['password'] = $PASSWORD;
// $fields['continue'] = $continue;
// $fields['failure'] = $failure;
// $fields['nosavelogin'] = $nosavelogin;

    $LOGINURL   = "https://auth-ac.my.com/auth";
    // $LOGINURL = "https://account.my.com/login/"; 

    // set postfields using what we extracted from the form
    $POSTFIELDS = http_build_query($fields); 

    // change URL to login URL
    curl_setopt($ch, CURLOPT_URL, $LOGINURL); 

    // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    // curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 

    // set post options
    curl_setopt($ch, CURLOPT_POST, 1); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $POSTFIELDS); 

    curl_setopt($ch, CURLOPT_HEADER,  1);
    // perform login
    $result = curl_exec($ch);
    }
    else
    {
    $result="Cannot find form fields";
    }
/*  
// derde stap: haaldata op?
    $CHECKURL   = "https://eu.portal.sf.my.com/user/avatar/72061992084468153";
    // change URL to login URL
    curl_setopt($ch, CURLOPT_URL, $CHECKURL); 
    curl_setopt($ch, CURLOPT_POST, 0); 
    curl_setopt($ch, CURLOPT_HEADER,  1);
    // haal data op login
    $checkresult = curl_exec($ch);
*/
// print $result;

curl_close($ch);

    }
    else
    {
    $result="Login afgebroken, lege usernaam gevonden";
    }

function getFormFields($data)
{
    if (preg_match('/(<form id="login_form" method="post" action=".*?<\/form>)/is', $data, $matches)) {
        $inputs = getInputs($matches[1]);
        return $inputs;
    } else {
        return "ERROR";
    }
}

function getInputs($form)
{
    $inputs = array();

    $elements = preg_match_all('/(<input[^>]+>)/is', $form, $matches);

    if ($elements > 0) {
        for($i = 0; $i < $elements; $i++) {
            $el = preg_replace('/\s{2,}/', ' ', $matches[1][$i]);

            if (preg_match('/name=(?:["\'])?([^"\'\s]*)/i', $el, $name)) {
                $name  = $name[1];
                $value = '';

                if (preg_match('/value=(?:["\'])?([^"\'\s]*)/i', $el, $value)) {
                    $value = $value[1];
                }

                $inputs[$name] = $value;
            }
        }
    }

    return $inputs;
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Skyforge cURL test</title>
</head>

<body>
cURL TEST<br />
<textarea cols="120" rows="40">
--SITE-----------------------
<? echo "\r\n"; ?>
<? echo $content; ?>
<? echo "\r\n"; ?>
--LOGIN----------------------
<? echo "\r\n"; ?>
<? echo $result; ?>
<? echo "\r\n"; ?>
--CHECK----------------------
<? echo "\r\n"; ?>
<? echo $checkresult; ?>
<? echo "\r\n"; ?>
--END------------------------
</textarea>
</body>
</html>


Ik heb tot nu toe geen succesvolle login, want ondanks goede login en wachtwoord krijg ik onjuiste login code terug en wordt ik dus teruggestuurd naar login pagina.

Ik ben geen pro in programmeren, maar ik heb wel graag wat hints van anderen waarom het mislukt en wat er eigenlijk anders moet in de code... Misschien moet cURL iets anders voorbereid worden.
Een voorbeeld van juiste code zou ik graag willen zien.

Als je zelf over Skyforge beschikt (hoewel aanmelden gratis is - het is f2p spel) kun je zelf proberen of het voor je wel lukt om in te loggen en dus data eraf kan halen en verder parsen. In de laatste stap code, dat inmiddels uitgeschakeld is, leidt naar mijn character pagina.

Ik hoef alleen maar succesvol inloggen, dan kan ik verder programmeren en zelf oplossen met de data. Hier zit ik alleen beetje vast ondanks vele pogingen, en met weinig ervaring in cURL kost mij teveel tijd waarom het niet goed gaat. Uren mee prutsen is niet leuk. Bovendien is er bijna geen info over inloggen op Skyforge, het is nog nieuw. Wel van andere mmo spellen, maar dat heeft weinig nut als login systeem anders is.

Dit poging is een alternatief wegens gebrek aan API. De guild wordt steeds groter en er komt meer data bij kijken, dus ik moet wel snel boel automatiseren, anders kom ik niet meer aan het spel toe en kan ik niet meer mijn character levelen. Dat is gewoon jammer en anderen vragen mij ook al waarom ik steeds meer achterop raakt.

Oh ja, de script moet natuurlijk wel login vasthouden anders moet ik steeds weer tussendoor inloggen bij elke data collect pagina.... de cookie zou hiervoor zorgen. Of dat ook zo is, weet ik op dit moment niet.

Alvast hartelijk dank. _/-\o_

Acties:
  • 0 Henk 'm!

  • fiftyhillswest
  • Registratie: Oktober 2009
  • Laatst online: 13-10 12:58
Je kunt eens kijken of cUrl een error geeft, iets wat je nu niet doet.
Dit kan door
PHP:
1
2
3
4
if(curl_errno($ch))
{
    echo 'error:' . curl_error($ch);
}

te doen nadat je je request doet. Dit is trouwens sowieso wel een goed idee ;)

[ Voor 10% gewijzigd door fiftyhillswest op 22-08-2015 13:51 ]


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19:38
Of een library gebruiken die hier speciaal voor gemaakt is. Bijvoorbeeld https://github.com/FriendsOfPHP/Goutte

PHP:
1
2
3
4
5
6
$crawler = $client->request('GET', $loginUrl);
$form = $crawler->selectButton('Sign in')->form();
$crawler = $client->submit($form, array('login' => 'fabpot', 'password' => 'xxxxxx'));
$crawler->filter('.flash-error')->each(function ($node) {
    print $node->text()."\n";
});


Werkt met de Symfony DomCrawler, daarmee kan je makkelijker formulieren invullen/versturen en door het resultaat lopen. Zie http://symfony.com/doc/cu....html#using-the-form-data

Acties:
  • 0 Henk 'm!

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Ik ga hiermee wat tests doen aan de hand van jullie reactie, en kom ik op terug welke error meldingen er zijn na de poging van inloggen.
Speciale library maakt inloggen dus makkelijker? Zal ik even proberen.

Maar je mag natuurlijk zelf een testje doen, registeren is gratis bij My.com. Al hoef je natuurlijk niet mee spelen :-)
Als er paar mensen meekijken hoe inloggen werkt is de oplossing ook sneller gevonden.

Ik heb aantal tips uitgeprobeerd, maar die werkt alleen op pagina's die terugkoppelt naar zichzelf, niet via de speciale server link. Hier verloopt dus wat anders.

Acties:
  • 0 Henk 'm!

  • emnich
  • Registratie: November 2012
  • Niet online

emnich

kom je hier vaker?

MrDummy schreef op zaterdag 22 augustus 2015 @ 21:55:
Ik heb aantal tips uitgeprobeerd, maar die werkt alleen op pagina's die terugkoppelt naar zichzelf, niet via de speciale server link. Hier verloopt dus wat anders.
Je moet even goed met je browser kijken wat er gebeurt. Staat er wellicht iets op die `tussenpagina`. Kan je ook inloggen als je js uit hebt staan (misschien vindt er nog wel iets van een js controle plaats).

Zodra je goed inzichtelijk heb hoe het inloggen precies werkt kan je makkelijker het namaken.

Acties:
  • 0 Henk 'm!

  • mbarie
  • Registratie: Mei 2011
  • Laatst online: 04-08-2021
Daarnaast zijn er mogelijk CSRF tokens in het spel en dien je eerst je token te achterhalen en de cookies die je aangeboden krijgt bij het opvragen van de login-pagina te implementeren in je login request.

Storyteller @ soundcloud


Acties:
  • 0 Henk 'm!

  • BlueZero
  • Registratie: Mei 2007
  • Laatst online: 10-09 15:45
Zover ik snel kan zien is er inderdaad sprake van een CSFR authenticatie, oftewel je zal alle Cookies die je bij het ophalen van het form krijgt weer mee moeten sturen bij de auth request.

Dit zal je zowiezo moeten doen bij alle requests daarna omdat er een Cookie wordt aangemaakt met daarin een phpsessid waaraan je sessie is gekoppeld.

Log simpelweg eens in in chrome, en zet in de network tab preserve log aan, vervolgens filter je op XHR requests. En let extra goed op de Response Headers, daarin staan Set-Cookie regels die ook in de Request Headers vervolgens weer worden gebruikt. Dit zal je moeten nabootsen in je CURL script.

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
BlueZero:
Dat is goed informatie, en daar kan ik verder gaan experimenteren en zoeken naar juiste code.
Er blijkt voldoende informatie aanwezig te zijn over CSFR authenticatie, dus ik ga even alles doornemen.

Bedankt.

Acties:
  • 0 Henk 'm!

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Ik heb pogingen gedaan met CSFR doorgeven, maar er blijkt geen standaard te zijn.
De ene voorbeeld zegt "X-CSFR-Token", andere zegt "X-CSFR" en weer andere zegt "X-CSFRToken".

CSRF heb ik gevonden, en die probeer ik door te geven in
PHP:
1
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array('X-CSRF-Token: ' . $csrf));


Maar het komt nog niet goed door, en dus besluit ik meer analyseren wat er allemaal gebeurt met headers. Dat kan met Chrome addon "Live HTTP headers" naast ingebouwde ontwikkelaar tool dat hier al is aangewezen.

De eerste page load levert op:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET /login/ HTTP/1.1
Host: account.my.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: csrf_token=xxxxx; p=XXXXX/XXXX; amc_lang=en_US; __cfduid=xxxx; mrcu=xxxxxx; mc=xxxxx; sdc=xxxxxx; s=dpr=1; __utma=144340137.290773732.1441301782.1441467261.1441471519.5; __utmc=144340137; __utmz=144340137.1441301782.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36
X-DevTools-Emulate-Network-Conditions-Client-Id: xxxxx

HTTP/1.1 200 OK
Cache-Control: private, no-cache, no-store
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Mon, 07 Sep 2015 17:40:39 GMT
Server: nginx/1.9.2
Transfer-Encoding: chunked

De cookie bevat aardig wat data... moet ik zeker allemaal opslaan en doorgeven?
Volstaat doorgeven met
PHP:
1
2
curl_setopt($curl_handle, CURLOPT_COOKIEFILE, $cookie_file_path); 
curl_setopt($curl_handle, CURLOPT_COOKIEJAR, $cookie_file_path);

of moet er wat anders hierna doorgegeven worden? De code boven is al gedaan bij de eerste pagina load.

Ik vind ook een andere script voorbeeld: http://www.paulbooker.co.uk/drupal-developer/tags/csrf
Dat komt alleen wel van drupal, maar hier slaat het goed op en geeft ook door als het weer opgeroepen worden.

Er is nog meer bij komen kijken: na inloggen blijkt https://auth-ac.my.com/auth meer links door te sturen. Ik tel 1x 302 POST en daarna 5 keer 302 GET, en vervolgens 9 keer 200 GET.
Ik toon even screenshot uit Live HTTP headers hieronder.
Afbeeldingslocatie: http://mrdummy.net/zooi/tweakers/Live_HTTP_Headers.png
Alleen http://account.my.com/profile/userinfo/ is voor mij nuttig voor verdere verwerking.

Maar ik weet dat mijn poging nog niet goed is na POST, want ik krijg negatieve Location: link terug, wat wijst op mislukte login.

Na POST via auth link is de header:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HTTP/1.1 302 Moved Temporarily
Cache-Control: no-cache,no-store,must-revalidate
Connection: keep-alive
Content-Length: 37
Content-Type: text/html
Date: Mon, 07 Sep 2015 17:50:31 GMT
Expires: Sun, 07 Sep 2014 17:50:31 GMT
Last-Modified: Mon, 07 Sep 2015 20:50:31 GMT
Location: http://account.my.com/login_continue/?continue=http%3A%2F%2Faccount.my.com
Pragma: no-cache
Server: nginx/
Set-Cookie: mrcu=xxxxxxxxx; expires=Thu, 04 Sep 2025 17:50:31 GMT; path=/; domain=.my.com
Set-Cookie: ssdc=xxxxxxxxx; expires=Thu, 08 Oct 2015 17:50:31 GMT; path=/; domain=.auth-ac.my.com; Secure; HttpOnly
Set-Cookie: mc=xxxxxx; expires=Thu, 08 Oct 2015 17:50:31 GMT; path=/; domain=.my.com
Strict-Transport-Security: max-age=16070400; includeSubDomains; preload
X-Content-Type-Options: nosniff

Ook hier weer cookie data en de juiste Location: link dat aangeeft als login valid is.

Ik weet niet wat er mogelijk ontbreekt, want op dit moment hebben CSRF examples niet veel duidelijkheid en er is geen goed informatie over My.com login systeem. Ik kan wel wat stimuleren aan de hand van de headers, maar ik wil graag even goedzetten. Het is enige knelpunt voor mij.

Je mag zeggen wat je zelf denkt over login systeem. Kan ik hier via PHP doorheen of is er meer stimulatie nodig met meer header regels erbij?

Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19:38
Barryvdh schreef op zaterdag 22 augustus 2015 @ 15:10:
Of een library gebruiken die hier speciaal voor gemaakt is. Bijvoorbeeld https://github.com/FriendsOfPHP/Goutte

PHP:
1
2
3
4
5
6
$crawler = $client->request('GET', $loginUrl);
$form = $crawler->selectButton('Sign in')->form();
$crawler = $client->submit($form, array('login' => 'fabpot', 'password' => 'xxxxxx'));
$crawler->filter('.flash-error')->each(function ($node) {
    print $node->text()."\n";
});


Werkt met de Symfony DomCrawler, daarmee kan je makkelijker formulieren invullen/versturen en door het resultaat lopen. Zie http://symfony.com/doc/cu....html#using-the-form-data
Heb je naar bovenstaande gekeken?

Ik heb even de moeite genomen om een test account aan te maken, en op zich kwam de code aardig in de buurt ;) Onderstaande logt in, kijkt of er errors zijn en maakt dan een 2de request naar een volgende pagina, met dezelfde sessie, om de gebruikersnaam te updaten.

PHP:
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
$credentials = [
    'email' =>  '',
    'password' => '',
];

$client = new Goutte\Client();
$crawler = $client->request('GET', 'http://account.my.com/login/');
$form = $crawler->selectButton('LOG IN')->form();
$crawler = $client->submit($form, $credentials);

$errors = $crawler->filter('.formMsg');
if ($errors->count()) {
    $errors->each(function ($node) {
        print $node->text()."<br/>";
    });
} else {
    // Make a second request using current session
    $crawler = $client->request('GET', 'http://account.my.com/profile/userinfo/');
    $form = $crawler->selectButton('Save')->form();
    $crawler = $client->submit($form, ['nickname' => 'Test1']);

    $crawler->filter('h1')->each(function($node){
        print $node->text().'<br/>';
    });
}


Inloggen met verkeerde gegevens geeft bij mij de error message weer, inloggen met goede gegevens geeft 'Personal information' (wat je ook ziet als je inlogt)

Zoals gezegd zorgt Goutte zelf voor de inputs op formulieren en cookies ed.

Daarnaast, CSRF kan op verschillende manier toegepast worden. Meestal is het echter gewoon hidden input veld. Als je dus de form velden uitleest en die waarde meestuurt, gaat het gewoon goed. Zo ook hier:
<input type="hidden" name="csrf_token" value="JH5ffXfyhK1akblvXemB">

[ Voor 19% gewijzigd door Barryvdh op 07-09-2015 21:02 . Reden: Uitgebreider voorbeeld ]


Acties:
  • 0 Henk 'm!

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Als ik ga zoeken op "php curl csrf" via google, ben ik in onduidelijke tuin gekomen en scripts maken niet veel duidelijk. Het gaat alle kanten op.

Maar ik heb niet in gaten dat er ook woord "web scraper" bestaat. Zou ik daar op googlen, krijg ik veel meer code voorbeelden en de library van Goutte is ook te zien in de gevonden resultaten.

Dus ik was met verkeerde woorden aan het zoeken... *slaps head* en zijn de oplossingen niet duidelijk of niet geweldig.

Fijn dat je positief resultaat kan melden, dus ik ga ermee experimenteren en kijken of ik genoeg data eruit kan halen. Bedankt!

De data is erg belangrijk want mijn pantheon wordt groter en er is veel meer controle nodig op alle spelers. De website zelf heeft nog geen API hiervoor, waardoor ik zelf moet coden en gegevens verwerken.

Aantal mmo's hebben zelf al API hiervoor, zoals WoW, zodat mensen eenvoudig data kunnen ophalen voor hun guild website.

Update na experiment:
Met direct uitvoeren van voorbeeld code krijg ik een op standaard xampp server:
Fatal error: Class 'Goutte\Client' not found in C:\webserver\xampp\htdocs\skyforge\login2.php on line 30
Regel 30 is van
PHP:
1
$client = new Client();

En op colo webserver gewoon witte pagina.
Eerder is use Goutte\Client; wel uitgevoerd zonder foutmelding.

Ook blijkt het Guzzle 6.0 nodig te hebben.
Goutte depends on PHP 5.5+ and Guzzle 6+.

Bij installatie instructie staat er ook:
Add ``fabpot/goutte`` as a require dependency in your ``composer.json`` file:

composer require fabpot/goutte


Het lijkt op dat ik niet gelijk kan uitvoeren, maar moet ik nog wat toevoegen. Helaas ben ik niet goed bekend mee. :|

Een korte uitleg in eigen woorden zou wat duidelijker maken en waar ik code moet gebruiken tegenover "standaard xampp webserver" en colo webserver. Anders val ik weer terug op cURL commando's welke wel werken.

Ik heb directory Goutte gekopieerd naar de directory van de webpagina en voer uit. Maar dat is niet genoeg, er is meer voor nodig.

[ Voor 37% gewijzigd door MrDummy op 08-09-2015 20:40 ]


Acties:
  • 0 Henk 'm!

  • BlueZero
  • Registratie: Mei 2007
  • Laatst online: 10-09 15:45
Ik zou als je niet genoeg kennis heb van CURL om dit uit te voeren het niet op de manier doen waarom je nu vraagt, enkel en alleen al omdat als ze ooit een cookie-naam/lengte veranderen dat dan niets meer werkt en het lastig debuggen is.

Barryvdh heeft gelijk en het beste is om simpel Goutte te gebruiken echter daarvoor heb je een basiskennis nodig van composer en ik begrijp dat je dat niet hebt.

Het makkelijkste is om Symfony te installeren op Xampp http://seiler.it/installi...k-into-xampp-for-windows/

En vervolgens via de composer Goutte te installeren dat doe je door in de console: composer require fabpot/goutte te runnen.

Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19:38
BlueZero schreef op woensdag 09 september 2015 @ 12:44:
Ik zou als je niet genoeg kennis heb van CURL om dit uit te voeren het niet op de manier doen waarom je nu vraagt, enkel en alleen al omdat als ze ooit een cookie-naam/lengte veranderen dat dan niets meer werkt en het lastig debuggen is.

Barryvdh heeft gelijk en het beste is om simpel Goutte te gebruiken echter daarvoor heb je een basiskennis nodig van composer en ik begrijp dat je dat niet hebt.

Het makkelijkste is om Symfony te installeren op Xampp http://seiler.it/installi...k-into-xampp-for-windows/

En vervolgens via de composer Goutte te installeren dat doe je door in de console: composer require fabpot/goutte te runnen.
Je hebt niet perse Symfony nodig, maar wel Composer: https://getcomposer.org/doc/00-intro.md

Composer installeren op je server, dan dus in de commandline 'composer require fabpot/goutte' uitvoeren. Dan in je script de vendor/autoload.php requiren.
PHP:
1
require __DIR__ . '/vendor/autoload.php';

Acties:
  • 0 Henk 'm!

  • BlueZero
  • Registratie: Mei 2007
  • Laatst online: 10-09 15:45
Barryvdh schreef op woensdag 09 september 2015 @ 12:59:
[...]

Je hebt niet perse Symfony nodig, maar wel Composer: https://getcomposer.org/doc/00-intro.md

Composer installeren op je server, dan dus in de commandline 'composer require fabpot/goutte' uitvoeren. Dan in je script de vendor/autoload.php requiren.
PHP:
1
require __DIR__ . '/vendor/autoload.php';
Correct, maar als iemand zo een soort systeem wil maken dan juich ik de overstap van harte toe.

Misschien is Symfony ook niet zo handig om mee te beginnen maar is Laravel wel een goede keus gezien het feit dat dit al gebaseerd is op Symfony.

Acties:
  • 0 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Ik denk niet dat je hier een library voor nodig hebt.
Het lijkt me gewoon een simpele POST and that's it.
-edit-
0: Zet CURLOPT_HEADER op 0 (of comment regel 30 en 75). Nu gooi je je header data bij de body data en dat is vragen om moeilijkheden. Volgens mij worden dan ook de cookies niet verwerkt.

1: Is je cookiefile wel gevuld? Inderdaad is COOKIEJAR om te schrijven en COOKIEFILE om te lezen, zodat je niet steeds hoeft in te loggen. Die csrf token zit daar ook in als het goed is, dus hoef je verder niets mee te doen.
2: zet CURLOPT_VERBOSE eens op 1, dan zie je beter wat er precies fout gaat.
3: Je Chorme post geeft aan dat de server met gzip de boel terugstuurt. Het kan zijn, dat cURL daar niet mee is gecompileerd (maar dat zou je dan bij 2 moeten zien) Probeer dan eens een lege string met CURLOPT_ENCODING zodat de server weet wat die versie wel snapt

Als er geen cookiefile aangemaakt wordt (1) zul je nooit kunnen inloggen, en verder kun je dus met de verbose (2) veel beter zien wat er nu precies fout gaat.

[ Voor 9% gewijzigd door Vaan Banaan op 09-09-2015 15:50 . Reden: CURLOPT_HEADER ]

500 "The server made a boo boo"


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19:38
Vaan Banaan schreef op woensdag 09 september 2015 @ 14:43:
Ik denk niet dat je hier een library voor nodig hebt.
Het lijkt me gewoon een simpele POST and that's it.
Als je met CSRF te maken hebt, zijn het al 2 posts (1 GET om formulier + inputs op te halen, 1 POST om te versturen). Daarnaast kan je het vast wel puur met cURL, maar een library als Goutte maakt het ook makkelijker om iets zinnigs met de output te doen of volgende requests te maken)

Acties:
  • 0 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Ja, daar heb je gelijk in, het is inderdaad eerst een GET om het inlogformulier op te halen en dan een simpele POST
Het script van MrDummy doet dat ook.
Met de getFormFields functie haalt hij alle velden op (ook de hidden) en vult email en password met zijn gegevens. Daar doet hij ook uitgebreide controle op.

Het enige wat ik denk dat fout gaat, is dat de cookies die met de GET terugkomen niet door cURL gelezen worden (en de csrf van deze site is ook een cookie) Alleen omdat hij CURLOPT_HEADER aan heeft staan.
Vervolgens heb je met de POST dan geen cookies (cURL stuurt alle cookies van een domein altijd automatisch mee als je CURLOPT_COOKIEFILE hebt gedefineerd)

cURL is echt heel goed en ik zou er geen library tegenaan gooien, als het met nog geen 100 regels ook perfect kan werken.

500 "The server made a boo boo"


Acties:
  • 0 Henk 'm!

  • Barryvdh
  • Registratie: Juni 2003
  • Laatst online: 19:38
Vaan Banaan schreef op woensdag 09 september 2015 @ 15:37:
cURL is echt heel goed en ik zou er geen library tegenaan gooien, als het met nog geen 100 regels ook perfect kan werken.
cURL is vast heel goed, daarom gebruiken Goutte en andere crawlers ook cURL voor hun requests. Het is alleen niet erg makkelijk en overzichtelijk. Natuurlijk kan je met preg_match proberen je inputs eruit te halen, zelf je cookies etc bijhouden en de tekst handmatig parsen dalijk. Maar daar wordt het niet echt overzichtelijker van.
Bovendien is dit pas de eerste stap, want daarna moet hij ook nog van andere pagina's dingen gaan ophalen.

Acties:
  • 0 Henk 'm!

  • BlueZero
  • Registratie: Mei 2007
  • Laatst online: 10-09 15:45
Barryvdh schreef op woensdag 09 september 2015 @ 16:03:
[...]


cURL is vast heel goed, daarom gebruiken Goutte en andere crawlers ook cURL voor hun requests. Het is alleen niet erg makkelijk en overzichtelijk. Natuurlijk kan je met preg_match proberen je inputs eruit te halen, zelf je cookies etc bijhouden en de tekst handmatig parsen dalijk. Maar daar wordt het niet echt overzichtelijker van.
Bovendien is dit pas de eerste stap, want daarna moet hij ook nog van andere pagina's dingen gaan ophalen.
Mocht OP toch CURL willen gebruiken gebruik dan PHP HTML DOM

code:
1
2
3
4
5
6
 // Create a DOM object
$dom = new simple_html_dom();
// Load HTML from a string
$dom->load(curl_exec($ch))

print_r( $dom );


En zoek vervolgens je input velden met:

code:
1
$inputs = $html->find('input');


Zie hier de complete lijst met mogelijkheden

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Er is nog een vraag.

Is het wel mogelijk om cURL lijn open te houden (dus steeds herhalen met lezen en posten) voordat het afgesloten kan worden met curl_close($curl_handle);?

In sommige scripts de ik bekijk merk ik op dat het elke keer weer gestart wordt en dan weer gesloten voor elke verwerking.
Zo wordt voor opvragen data een nieuwe handle geopend en hier worden dan cookie data meegestuurd met curl_setopt($curl_handle, CURLOPT_COOKIEFILE, $cookie_file_path);.

Welke methode is te doen? Mag ik wel in een keer diverse handelingen doen of is het beter te controleren door in losse stappen te doen? Wat is dus makkelijker?

Voor CSRF key heb ik deze code:
PHP:
1
2
3
4
5
6
7
8
9
// execute session to get cookies and required form inputs
$buffer = curl_exec($curl_handle);

// get and store CSRF data
preg_match('/^Set-Cookie:\s*([^;]*)/mi', $buffer, $value);
parse_str($value[1], $cookies);
$csrf = $cookies[csrf_token];
file_put_contents($token_file_path, $csrf);
$result_csrf="CSRF code: ".$csrf;

Acties:
  • 0 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Cookies regelt cURL voor je, daar hoef je zelf niks mee te doen.
Is het wel mogelijk om cURL lijn open te houden (dus steeds herhalen met lezen en posten) voordat het afgesloten kan worden met curl_close($curl_handle);?
Ja, dat wordt zelfs aangeraden. Init aan het begin van je script, close aan het einde van je script.
Welke methode is te doen? Mag ik wel in een keer diverse handelingen doen of is het beter te controleren door in losse stappen te doen? Wat is dus makkelijker?
Laat dat hele CSRF voor wat het is, daar hoef je niks mee te doen. Die zit bij my.com in een cookie en regelt cURL automatisch voor je
Na CURLOPT_COOKIEFILE zorgt cURL namelijk voor de afhandeling van cookies. Dus die worden dan automagisch voor je aangemaakt, ververst, verwijderd, enzovoort. Dat gebeurt volledig automatisch bij elke GET, POST, PUT, DELETE, whatever.
CURLOPT_COOKIEJAR zorgt dat ze NA de curlclose naar een bestand geschreven worden voor later.

Zet CURLOPT_HEADER uit op regel 30 en 75 en je script zou een stuk beter moeten werken.
Zie ook mijn eerdere post
Je hoeft verder niets met de cookies te doen, want dat regelt cURL voor je.

500 "The server made a boo boo"


  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Helemaal goed, morgen maar even coden en kijken of het beter gaat.

De andere tips zal ik ook proberen, want de DOM methode heb ik al eens eerder gezien op internet als scraping oplossing. Maar cURL is natuurlijk prima.

De andere methode met library van Goutte en composer is stapje hoger voor mij (niet in mijn kennisgebied dus), dus doe ik later om poging te doen en te leren, omdat deze met standaard niet erin zit en daardoor niet direct werkt.

Wordt vervolgd....

Acties:
  • 0 Henk 'm!

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Hmm, het gaat niet helemaal goed, want er wordt aparte connectie gemaakt per url.

De error log van VERBOSE luidt:
code:
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
* About to connect() to account.my.com port 443 (#0)
*   Trying 185.30.176.71... * connected
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSL connection using ECDHE-RSA-AES256-SHA
* Server certificate:
*    subject: C=VG; ST=Tortola; L=Road Town; O=BENSTAR LIMITED; OU=IT; CN=*.my.com
*    start date: 2015-08-26 00:00:00 GMT
*    expire date: 2016-10-14 23:59:59 GMT
*    subjectAltName: account.my.com matched
*    issuer: C=US; O=GeoTrust Inc.; CN=GeoTrust SSL CA - G3
*    SSL certificate verify ok.
> GET /login/ HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Host: account.my.com
Accept: */*
Accept-Encoding: deflate, gzip

< HTTP/1.1 200 OK
< Server: nginx/1.9.2
< Date: Sun, 13 Sep 2015 17:19:00 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
* Added cookie csrf_token="xxxxxxx" for domain account.my.com, path /, expire 1444756740
< Set-Cookie: csrf_token=xxxxxx; path=/; expires=Tue, 13-Oct-2015 17:19:00 GMT
< Cache-Control: private, no-cache, no-store
< Content-Encoding: gzip
< 
* Connection #0 to host account.my.com left intact
* About to connect() to auth-ac.my.com port 443 (#1)
*   Trying 185.30.179.7... * connected
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSL connection using ECDHE-RSA-RC4-SHA
* Server certificate:
*    subject: C=VG; ST=Tortola; L=Road Town; O=BENSTAR LIMITED; OU=IT; CN=*.my.com
*    start date: 2014-10-15 00:00:00 GMT
*    expire date: 2015-10-15 23:59:59 GMT
*    subjectAltName: auth-ac.my.com matched
*    issuer: C=US; O=GeoTrust Inc.; CN=GeoTrust SSL CA - G2
*    SSL certificate verify ok.
> POST /auth HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Host: auth-ac.my.com
Accept: */*
Accept-Encoding: deflate, gzip
Content-Length: 258
Content-Type: application/x-www-form-urlencoded

* upload completely sent off: 258out of 258 bytes
< HTTP/1.1 302 Moved Temporarily
< Server: nginx/
< Date: Sun, 13 Sep 2015 17:19:00 GMT
< Content-Type: text/html
< Content-Length: 37
< Connection: keep-alive
< Location: http://account.my.com/login/?continue=http%3A%2F%2Faccount.my.com&error_code=1
< Cache-Control: no-cache,no-store,must-revalidate
< Pragma: no-cache
< Expires: Sat, 13 Sep 2014 17:19:00 GMT
< Last-Modified: Sun, 13 Sep 2015 20:19:00 GMT
< X-Content-Type-Options: nosniff
< Strict-Transport-Security: max-age=16070400; includeSubDomains; preload
< 
* Connection #1 to host auth-ac.my.com left intact
* About to connect() to eu.portal.sf.my.com port 443 (#2)
*   Trying 185.30.178.63... * connected
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSL connection using ECDHE-RSA-AES256-SHA
* Server certificate:
*    subject: C=VG; ST=Tortola; L=Road Town; O=BENSTAR LIMITED; OU=IT; CN=*.portal.sf.my.com
*    start date: 2015-03-10 00:00:00 GMT
*    expire date: 2018-03-09 23:59:59 GMT
*    subjectAltName: eu.portal.sf.my.com matched
*    issuer: C=US; O=GeoTrust Inc.; CN=GeoTrust SSL CA - G3
*    SSL certificate verify ok.
> POST /user/avatar/72061992084468153 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Host: eu.portal.sf.my.com
Accept: */*
Accept-Encoding: deflate, gzip
Content-Length: 258
Content-Type: application/x-www-form-urlencoded

* upload completely sent off: 258out of 258 bytes
< HTTP/1.1 302 Found
< Server: nginx
< Date: Sun, 13 Sep 2015 17:19:00 GMT
< Content-Length: 0
< Connection: keep-alive
< Keep-Alive: timeout=60
* Added cookie route="c92e0a538e60f7115d7438eea18fd5c3" for domain eu.portal.sf.my.com, path /, expire 0
< Set-Cookie: route=c92e0a538e60f7115d7438eea18fd5c3; Path=/
* Added cookie portal_backend="backend53" for domain eu.portal.sf.my.com, path /, expire 1442168340
< Set-Cookie: portal_backend=backend53; Expires=Sun, 13-Sep-2015 18:19:00 GMT; Path=/; Secure
< Location: https://eu.portal.sf.my.com/error/HiddenFromAnonymous/user/avatar/72061992084468153
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< 
* Connection #2 to host eu.portal.sf.my.com left intact
* Closing connection #0
* Closing connection #1
* Closing connection #2


Ik heb 3x CURLOPT_URL in 1 keer uitgevoerd achter elkaar.
Dit maakt echter niet 1 connectie van, maar maakt steeds nieuwe connectie aan.
Hierdoor gaan aantal zaken niet goed, het resultaat van posten is niet goedgekeurd en ben ik weer terug bij het begin.

De cookie en CSRF zijn wel goed, die worden inderdaad doorgegeven.

Maar op dit moment volgt cURL niet goed de doorverwijzingen en dat gaat mis. Want dat moet wel gebeuren, anders is inloggen "afgekeurd".
Gelukkig heb ik een interessante scraping library gevonden tijdens zoeken naar web scraping via Google:
https://barebonescms.com/...mate_web_scraper_toolkit/
Deze maakt gebruik van aanwezige PHP codes en dus direct te gebruiken.

En inderdaad, de UWS Toolkit code werkt. Het volgt nu wel correct doorverwijzing na posten van form velden, en ik krijg eindelijk de goede pagina ervoor.

En het is ook gelukt om andere pagina's in te laden en benodigde data ophalen. Dus ik ga verder experimenteren met de UWS Toolkit.

Acties:
  • 0 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Mooi dat het gelukt is met de library.
Dit is duidelijk je eerste hobby-project en je kan niet goed bevatten wat je precies aan het doen bent.
Ik moet daarom Barryvdh gelijk geven: voor jou is cURL nog niet geschikt. Een library die dit onder de motorkap voor je regelt, gaat waarschijnlijk sneller resultaten opleveren.

Toelichting op je laatste bevindingen:
Hmm, het gaat niet helemaal goed, want er wordt aparte connectie gemaakt per url.
Dat er meerdere connecties gemaakt worden is niet erg. Dat moet ook wel, want het is niet gezegd dat de verschillende sub-domeinen op 1 en dezelfde server (en IP-adres) draaien.
Dit zit echter WEL allemaal in 1 curl-handle, waardoor de cookies ook allemaal goed verstuurd worden.
En hij laat ze open, zodat, ALS je toevallig nog een keer iets op hetzelfde sub-domein opvraagd, je die desbetreffende connectie kan hergebruiken
Hierdoor gaan aantal zaken niet goed, het resultaat van posten is niet goedgekeurd en ben ik weer terug bij het begin.
code:
14
15
16
> GET /login/ HTTP/1.1
User-Agent: ...
Host: account.my.com
code:
45
46
47
> POST /auth HTTP/1.1
User-Agent: ...
Host: auth-ac.my.com
Je doet een GET op de inlog-pagina en dan een POST met die data naar een heel andere pagina. Dat gaat nooit werken.
Als je dus een GET doet naar https://account.my.com/login/ om de fields op te halen, moet je die data ook met een POST weer naar https://account.my.com/login/ sturen. Dan pas ben je ingelogd. (En wordt je met een 302 of wat dan ook ergens anders heen gestuurd)

Daarna zou je met een GET naar https://auth-ac.my.com/auth (geen idee wat je daar wilt ophalen)
En eventueel ook met een GET naar https://eu.portal.sf.my.com/user/avatar/72061992084468153
Hiervoor moet je 1 keer CURLOPT_HTTPGET op 1 zetten. Nu zet je CURLOPT_POST op 0, maar daarmee wordt het niet per definitie een echte GET.
En regel 89 zou ook weer weg mogen.

500 "The server made a boo boo"


Acties:
  • 0 Henk 'm!

  • MrDummy
  • Registratie: April 2000
  • Laatst online: 25-07 12:00

MrDummy

Nog steeds gek op anime...

Topicstarter
Ik heb in verleden al eerder scrape gedaan op andere site, maar daar is wat simpeler gedaan zonder login nodig. Dat werkt wel meteen zonder veel omwegen met aantal cURL regels.

Hier bevind ik in een andere situatie met vereiste login.
In de login pagina kan ik zien dat form link naar auth gaat, zodat ik denk dat het ook kan door direct naar auth te sturen met POST. Dat moet toch anders volgens je door dezelfde link te nemen waar ik eerder form velden ophaal.

Maar inderdaad, het is niet makkelijk werken direct met cURL. De library is inderdaad makkelijker voor mij.

Acties:
  • 0 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Dat zal wel de redirect na login zijn, wat een heel gebruikelijke login flow is (op welke site dan ook). Dit is een Post/Redirect/Get pattern

Inderdaad doe je een GET naar de login pagina, haalt de fields op en doe je een POST naar diezelfde pagina.
De redirect en hele zut daarna doet cURL voor je, aangezien je CURLOPT_FOLLOWLOCATION op true hebt staan

[ Voor 7% gewijzigd door Vaan Banaan op 14-09-2015 14:31 ]

500 "The server made a boo boo"

Pagina: 1