Search code examples
phpjqueryphp-curl

How do I parse this non-formatted list of sha key response?


I'm calling the haveibeenpwned api to search the prefix of a password's sha1 value exists in a database. (form submit bound to an ajax call to a php script). The response is all the compromised passwords in sha1 with the same prefix as my password's along with their incidence count.

The response looks like the following, with no brackets or quotations. You can see an example call here.

0084E2D508D46A4D5FDB509625EE9BE99CE:1
0159EB03D329C98DD0DF294CD5B9CA52854:2
02662E0A92868C8B65DBFC8764C9A54B646:2
03BBAEF4539EA59F8B0784E64323A3B8E9D:2
04B631308CABEB3038D04B0F114D699A022:6
0556B126AA9AF70D83EA0DD7FB6865A6338:1
05B2FBDE67E25293A020855683A12A8AEB6:2
05CCD00B8F9010E60CF6DA4E1E637EF7664:1
069836ADDB456322375224A6D2374D3309D:1
07402605745C387BEF36C2BC54619EC4573:2
07FB36570851A136481E6B8138AC4834484:2
0829F51F120B5F8B99D7AF00602053556BF:2
089BACBDF1C6214D69F1A3BDC20459D57EE:3
08EB1AA8F3C15FC70D6CD4B1F42C9462671:1
09EEFDDA1D7253593138B66DEA14911B7FA:6
0A1359437D05D0A06CA5C840A297A49EE3E:1
0A84D4E8D914D7A782A81838AD57142B352:1
0A9DAA8398558A5448C327E9621446955F1:2
0BA107CFAC7EE7222F7E23E05D2984B38DC:1

I can either search for the my password's incidence in jquery or php. In jquery, I've had no luck trying to convert the response to a string and using response.includes(my_password_sha). Also, setting content-type: json in php doesn't seems to break the server.

      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
         'Content-Type: application/json',
     );

Here's the javascript I've been trying to make work:

            success: function(response) { 
                console.log(response);

                console.log("pw checker responded");                
                var resp_str = response.toString();
                resp_str = resp_str.substring(40)

                var pw_sha = response.toString().substring(0,40);
                pw_sha = pw_sha.substring(7,35);

                if(resp_str.includes(pw_sha))
                { //fails to work
                    console.log("password compromised");
                }


            },

Here's the php:

      $service_url = 'https://api.pwnedpasswords.com/range/42331';
      //$service_url = 'https://haveibeenpwned.com/range/aaf4c';


      $ch = curl_init ($service_url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt ($ch, CURLOPT_HTTPGET, true);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
      $returndata = curl_exec ($ch);
      $status_code = @curl_getinfo($ch, CURLINFO_HTTP_CODE); 
      //print_r($status_code);

      //send back my key and the response
      echo $pw_sha." ";
      echo $returndata;

Solution

  • The response you get from the server is in plain text and returned data is a sequence of lines in the form

    ppp : nnn

    where ppp is the 40 characters long sha1 hashed password and nnn is the incidence count.

    You can easily turn that response into an associative array in PHP, turn the array into JSON and send back JSON encoded data to the frontend JavaScript:

    $response = explode( "\n", $response );
    $out = [];
    foreach( $response as $r )
    {
        $r = explode( ":", $r );
        $out[] = [ 'sha1' => $r[0], 'count' => $r[1] ];
    }
    $out = json_encode( $out );
    echo $out;
    

    The JavaScript AJAX success() callback will receive a decoded object that can be easily inspected:

    success: function(response) {
        var found,
            n,
            i;
    
        found = false;
        n = response.length;
        for( i = 0; i < n; i++ )
        {
            if( pw_sha1_to_check === response[i].sha1 )
            {
                found = true;
                break;
            }
        }
    
        if( found )
        {
            // `pw_sha1_to_check` was found in the list received as response
        }
    

    Ensure when you make the AJAX call with jQuery to specify that a JSON response is expected:

     $.ajax( {
         dataType: 'json',
         // ...