Recently I was challenged to make a script that would authenticate through a bot-proof login from and redirect to a logged in page.
Main concept
The form is not online anymore… Through a web sniffer I’ve found out the form is sent as POST xhr/ajax request with on-fly generated security parameter – hash. See a figure below:
My script authentication concept is put down in the following steps:
- Load a form into a browser (PHP cURL with CURLOPT_RETURNTRANSFER => true).
- Fill the form out with login/password (on page JavaScript).
- Generate security hash based on the form serialized inputs. Append a hash input field (on page JavaScript).
- Run on page JavaScript to automatically submit the extended form. We submit the form to the same script as a POST request.
- Having been rerun, the script gathers the POST payload and submits it as POST XHR to the target server for authentication.
- Then with PHP cURL, we request logged.php file to get the result (test or fail).
Let’s expose each of the steps with some code. Or you might want to jump to the whole code.
Load form into browser
$header=get_web_page('https://auth.gripon.ru/');
print_r($header['content']);
function get_web_page($url){
$options = array( CURLOPT_RETURNTRANSFER => true, // return page
CURLOPT_HEADER => true, //return headers in addition to content );
$ch = curl_init( $url );
curl_setopt_array( $ch, $options ); // to save cookie in "cookie jar", namely cookie.txt file $tmpfname = dirname(__FILE__).'/cookie.txt';
curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname);
$rough_content = curl_exec( $ch );
$header = curl_getinfo( $ch ); curl_close( $ch );
$header_content = substr($rough_content, 0, $header['header_size']);
$body_content = trim(str_replace($header_content, '', $rough_content));
$header['content'] = $body_content;
return $header;
}
Fill the form out
We inject JavaScript code to be run with GET parameters (login/password).
echo '<script>$("#login-username").val("' . $_GET['login'] . '"); $("#login-password").val("' . $_GET['password'] . '"); </script>';
Generate security md5 hash
The form’s Javascript file (md5.js) produces hash value out of serialized form upon Login button click:
var ser = $( "#loginform" ).serialize(); var hash=md5(ser);
To load md5.js in our script we included it in the page’s head section. Now we create hash value and append a new hash input field:
<html>
<head>
<script src='https://auth.gripon.ru/md5.js'></script>
</head>
<body>
<?php echo '<script> var form = $( "#loginform" ).serialize();
var hash = md5(form);
$("#loginform").append(\'<input id="hash" type="text" name="hash" value="\' + hash + \'" >\' ); </script>';
?>
Now the form is extended with a hash input.
Auto-submit the extended form
To send the form to our own auth script we change form’s target `action` attribute to `#`. Then we may trigger from submission.
echo '<script>$("#loginform").attr( "action", "#" );
loginform.submit();
console.log("Login form is sent."); </script>';
Submit as POST XHR to the target server and fetch auth result
We simply submit to auth.gripon.ru for authentication. To make it XHR as in the original form we add this:
curl_setopt($ch, CURLOPT_HTTPHEADER, array(...));
if ( isset($_POST['hash']) )
{
// xhr POST request to post.php
post_xhr('https://auth.gripon.ru/post.php', $_POST);
// get logged.php response
$header = get_web_page('https://auth.gripon.ru/logged.php');
print_r($header['content']);
exit;
}
function post_xhr( $url, $post=NULL){
$options = array(
CURLOPT_POSTFIELDS => $post ? http_build_query($post) : '',
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true, // return web page
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
$tmpfname = dirname(__FILE__).'/cookie.txt';
curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname);
// to make request xhr
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Host" => "auth.gripon.ru",
"User-Agent" => "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Accept" => "application/json, text/javascript, */*; q=0.01",
"Accept-Language" => "en-us,en;q=0.5",
"Accept-Encoding" => "gzip, deflate",
"Accept-Charset" => "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive" => "115",
"Connection" => "keep-alive",
"X-Requested-With" => "XMLHttpRequest",
"Referer" => "https://auth.gripon.ru"
));
curl_exec( $ch );
curl_close( $ch );
}
The whole code
<?php
if ( isset($_POST['hash']) )
{
// xhr POST request to post.php
post_xhr('https://auth.gripon.ru/post.php', $_POST);
// get result from logged.php
$header = get_web_page('https://auth.gripon.ru/logged.php');
print_r($header['content']);
exit;
}
else if (!isset($_GET) OR !isset($_GET['login']) OR !isset($_GET['password']) )
{
echo 'Missing GET parameters.';
exit;
}
?>
<!DOCTYPE html>
<html>
<body>
<?php
// the original auth form load
$header=get_web_page('https://auth.gripon.ru/');
// output form in browser
print_r($header['content']);
function get_web_page($url){
$options = array(
CURLOPT_RETURNTRANSFER => true, // return page
CURLOPT_HEADER => true, //return headers in addition to content
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
// to save cookie in "cookie jar", namely cookie.txt file
$tmpfname = dirname(__FILE__).'/cookie.txt';
curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname);
$rough_content = curl_exec( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );
$header_content = substr($rough_content, 0, $header['header_size']);
$body_content = trim(str_replace($header_content, '', $rough_content));
$header['content'] = $body_content;
return $header;
}
function post_xhr( $url, $post=NULL){
$options = array(
CURLOPT_POSTFIELDS => $post ? http_build_query($post) : '',
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true, // return web page
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
$tmpfname = dirname(__FILE__).'/cookie.txt';
curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname);
// to make request xhr
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Host" => "auth.gripon.ru",
"User-Agent" => "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Accept" => "application/json, text/javascript, */*; q=0.01",
"Accept-Language" => "en-us,en;q=0.5",
"Accept-Encoding" => "gzip, deflate",
"Accept-Charset" => "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Keep-Alive" => "115",
"Connection" => "keep-alive",
"X-Requested-With" => "XMLHttpRequest",
"Referer" => "https://auth.gripon.ru"
));
curl_exec( $ch );
curl_close( $ch );
}
?>
</body>
<script src='https://auth.gripon.ru/md5.js'></script>
<script>
// fill out from with input values
$("#login-username").val("<?php echo $_GET['login']; ?>");
$("#login-password").val("<?php echo$_GET['password']; ?>");
var form = $( "#loginform" ).serialize();
// create hash value - md5.js
var hash = md5(form);
// append a hash input field
$("#loginform").append('<input id="hash" type="text" name="hash" value="' + hash + '" >');
// change form's target, `action` attribute
$("#loginform").attr( "action", "#" );
// extended (with hash) form submition
loginform.submit();
</script>
</html>
Disclaimer
I admit, it might not be the most optimal way to authenticate through this bot-proof form, yet I think some may get some ideas of how to handle tough logging-in cases in the web scraping. Welcome to suggest some better solutions.
11 replies on “Auth in bot-proof login form with PHP Curl and JavaScript”
Hello
Or you input the login and password
cordially
Rien, what do you mean?
Hello
I like to put a login ( test) and password ( test1 ) to see the work , for I am beginner information
thanks in advance
Do it in that live form and see its work. Good playground to start with.
De plus chaque fois que je lance ta commande j’ai “Missing GET parameters.” ce qui est normale car je n’ai pas mis de login ni de pass
Amicalement
Also every time I run the command I “Missing GET parameters.” This is normal because I did not put login and pass
friendly
a last hand please
Try to work with this form from different browsers. What technique do you use for the automatic filling out the form?
thank you for your reply but I work weird.
but I take a sui works program , I modify it to see how it works, the I ‘m stuck , I can not seem to get past the password or login,
thank you in advance for your help
Thank you for your help
For my Part I waiting for me to put in your file
$username = ‘myuser’;
$password = ‘mypass’;
cordialy
GET parameters are taken from the url parameters. Read the theory here. So as you run the php script, you embed username & password into the url like this: …/script.php?login=myuser&password=mypass