php login curl code not working as expected

前端 未结 2 1039
暖寄归人
暖寄归人 2021-02-18 19:23

I am trying to use the curl function in php to login to a specific page. Please check the code below. I connect with my email and password at banggood.com and then i would like

相关标签:
2条回答
  • 2021-02-18 19:39

    You're doing several things wrong:

    1. You're trying to login before you have a cookie session, but the site requires you to have a cookie session before sending the login request.

    2. There's an CSRF token tied to your cookie session, here called at, that you need to parse out from the login page html and provide with your login request, which your code doesn't fetch.

    3. Most importantly, there is a captcha image tied to your cookie session that you need to fetch and solve, and who's text you need to append to your login request, which your code is completely ignoring.

    4. Your login request needs the header x-requested-with: XMLHttpRequest - but your code isn't adding that header.

    5. Your login request needs the fields com=account and t=submitLogin fields in the POST data, but your code isn't adding either of them (you try to add them to your URL, but they're not supposed to be in the url, they're supposed to be in the POST data, aka your $postValues array, not the url)

    Here's what you need to do:

    • First do a normal GET request to the login page. This will give you a session cookie id, the CSRF token, and the url to your captcha image.
    • Store the cookie id and make sure to provide it with all further requests, then parse out the csrf token (it's in the html looking like <input type="hidden" name="at" value="5aabxxx5dcac0" />), and the url for the captcha image (its different for each cookie session, so don't hardcode it).
    • Then fetch the captcha image, solve it, and add them all to your login request's POST data, along with the username, password, captcha answer, com and t, and add the http header x-requested-with: XMLHttpRequest to the login request too, send it to https://www.banggood.com/login.html, then you should be logged in!

    Here's an example implementation using hhb_curl for the web requests (it's a curl_ wrapper taking care of cookies, turning silent curl_ errors into RuntimeExceptions, etc), DOMDocument for parsing out the CSRF token, and deathbycaptcha.com's api for breaking the captcha.

    Ps: the example code won't work until you provide a real credited deathbycaptcha.com api username/password on line 6 and 7, also the captcha looks so simple that I think breaking it could be automated if you're sufficiently motivated, I'm not. - edit, seems they improved their captcha since i wrote that, it looks very difficult now. Also, the banggood account is just a temporary testing account, no harm comes of it being compromised, which obviously happens when I post the username/password here)

    <?php
    
    declare(strict_types = 1);
    require_once ('hhb_.inc.php');
    $banggood_username = 'igcpilojhkfhtdz@my10minutemail.com';
    $banggood_password = 'igcpilojhkfhtdz@my10minutemail.com';
    $deathbycaptcha_username = '?';
    $deathbycaptcha_password = '?';
    
    $hc = new hhb_curl ( '', true );
    $html = $hc->exec ( 'https://www.banggood.com/login.html' )->getStdOut ();
    $domd = @DOMDocument::loadHTML ( $html );
    $xp = new DOMXPath ( $domd );
    $csrf_token = $xp->query ( '//input[@name="at"]' )->item ( 0 )->getAttribute ( "value" );
    $captcha_image_url = 'https://www.banggood.com/' . $domd->getElementById ( "get_login_image" )->getAttribute ( "src" );
    $captcha_image = $hc->exec ( $captcha_image_url )->getStdOut ();
    
    $captcha_answer = deathbycaptcha ( $captcha_image, $deathbycaptcha_username, $deathbycaptcha_password );
    
    $html = $hc->setopt_array ( array (
            CURLOPT_POST => 1,
            CURLOPT_POSTFIELDS => http_build_query ( array (
                    'com' => 'account',
                    't' => 'submitlogin',
                    'email' => $banggood_username,
                    'pwd' => $banggood_password,
                    'at' => $csrf_token,
                    'login_image_code' => $captcha_answer 
            ) ),
            CURLOPT_HTTPHEADER => array (
                    'x-requested-with: XMLHttpRequest' 
            ) 
    ) )->exec ()->getStdOut ();
    var_dump ( // $hc->getStdErr (),
    $html );
    
    function deathbycaptcha(string $imageBinary, string $apiUsername, string $apiPassword): string {
        $hc = new hhb_curl ( '', true );
        $response = $hc->setopt_array ( array (
                CURLOPT_URL => 'http://api.dbcapi.me/api/captcha',
                CURLOPT_POST => 1,
                CURLOPT_HTTPHEADER => array (
                        'Accept: application/json' 
                ),
                CURLOPT_POSTFIELDS => array (
                        'username' => $apiUsername,
                        'password' => $apiPassword,
                        'captchafile' => 'base64:' . base64_encode ( $imageBinary )  // use base64 because CURLFile requires a file, and i cba with tmpfile() .. but it would save bandwidth.
                ),
                CURLOPT_FOLLOWLOCATION => 0 
        ) )->exec ()->getStdOut ();
        $response_code = $hc->getinfo ( CURLINFO_HTTP_CODE );
        if ($response_code !== 303) {
            // some error
            $err = "DeathByCaptcha api retuned \"$response_code\", expected 303, ";
            switch ($response_code) {
                case 403 :
                    $err .= " the api username/password was rejected";
                    break;
                case 400 :
                    $err .= " we sent an invalid request to the api (maybe the API specs has been updated?)";
                    break;
                case 500 :
                    $err .= " the api had an internal server error";
                    break;
                case 503 :
                    $err .= " api is temorarily unreachable, try again later";
                    break;
                default :
                    {
                        $err .= " unknown error";
                        break;
                    }
            }
            $err .= ' - ' . $response;
            throw new \RuntimeException ( $err );
        }
        $response = json_decode ( $response, true );
        if (! empty ( $response ['text'] ) && $response ['text'] !== '?') {
            return $response ['text']; // sometimes the answer might be available right away.
        }
        $id = $response ['captcha'];
        $url = 'http://api.dbcapi.me/api/captcha/' . urlencode ( $id );
        while ( true ) {
            sleep ( 10 ); // check every 10 seconds
            $response = $hc->setopt ( CURLOPT_HTTPHEADER, array (
                    'Accept: application/json' 
            ) )->exec ( $url )->getStdOut ();
            $response = json_decode ( $response, true );
            if (! empty ( $response ['text'] ) && $response ['text'] !== '?') {
                return $response ['text'];
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-18 19:46

    Set CURLOPT_FOLLOWLOCATION to 1 or true, you may also need CURLOPT_AUTOREFERER instead of the static REFERER.

    Do you get some cookies into your COOKIEJAR (cookie.txt) ? Remember that the file must already exists and PHP needs write permissions.

    If you have PHP executing on localhost then a Network sniffer tool could help debug the problem, try with Wireshark or some equivalent software. Because maybe the request still miss some important HTTP Headers like Host

    0 讨论(0)
提交回复
热议问题