Тема: HTTP Авторизация и безопасность
Здравствуйте уважаемые форумчане и разрабы.
На досуге, изучая API, написал такой вот php скрипт авторизации и получения токена:
<?php
@unlink('cookie.txt');
echo '<body><center>
<h2>Скрипт авторизации в СМТ Wialon</h2>
<br><br>
<form method="POST" action="" id="auth-form" onsubmit="checkLogin(event)">
<input type="text" class="" name="login" id="login" placeholder="Пользователь" value="" autocapitalize="off" autocorrect="off" dir="auto">
<input type="password" class="" name="passw" placeholder="Пароль" autocapitalize="off" autocorrect="off" dir="auto">
<input type="submit" value="Получить"></form><br><br>';
if(!$_POST['submit']){
$login = htmlentities(htmlspecialchars($_POST['login']), ENT_QUOTES, 'UTF-8');
$passw = htmlentities(htmlspecialchars($_POST['passw']), ENT_QUOTES, 'UTF-8');
if (empty($login) OR empty($passw)) {
echo 'Незаполнены поля логин или пароль!';
exit;
} else {
$target_link = 'http://hosting.wialon.com/login.html';
$headers = array(
'cache-control: max-age=0',
'upgrade-insecure-requests: 1',
'user-agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36',
'sec-fetch-user: ?1',
'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'x-compress: null',
'sec-fetch-site: none',
'sec-fetch-mode: navigate',
'accept-encoding: deflate, br',
'accept-language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $target_link);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_VERBOSE, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSLVERSION, 3);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$content = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpcode != 200 ) {
echo 'Статус ответа: '.$httpcode.'<br>';
unset ($target_link, $content);
} else {
preg_match_all('#name="(.*?)" value="(.*?)"#Ui',$content, $matches);
echo 'Статус ответа: '.$httpcode.'<br>Получена сигнатура ('.$matches[1][9].'): '.$matches[2][9];
unset ($target_link, $content);
$target_link = 'https://hosting.wialon.com/oauth.html';
$postFields = array();
$postFields[$matches[1][0]] = $matches[2][0];
$postFields[$matches[1][1]] = $matches[2][1];
$postFields[$matches[1][2]] = $matches[2][2];
$postFields[$matches[1][3]] = $matches[2][3];
$postFields[$matches[1][4]] = $matches[2][4];
$postFields[$matches[1][5]] = $matches[2][5];
$postFields[$matches[1][6]] = $matches[2][6];
$postFields[$matches[1][7]] = $matches[2][7];
$postFields[$matches[1][8]] = $matches[2][8];
$postFields[$matches[1][9]] = $matches[2][9];
$postFields[$matches[1][10]] = $matches[2][10];
$postFields['login'] = $login;
$postFields['passw'] = $passw;
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $target_link);
curl_setopt($curl, CURLOPT_COOKIEFILE, __DIR__ . '/cookie.txt');
curl_setopt($curl, CURLOPT_COOKIEJAR, __DIR__ . '/cookie.txt');
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postFields));
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
$content = curl_exec($curl);
curl_close($curl);
preg_match('#<h1 class="title">(.*?)</h1>#Ui',$content, $out1);
preg_match('#token=(.*?)&#Ui',$content, $out2);
preg_match('#svc_error=(.*?)#Ui',$content, $out3);
$res = str_replace(array("\r\n", "\r", "\n"), '', strip_tags($out1[1]));
$token = str_replace(array("\r\n", "\r", "\n"), '', strip_tags($out2[1]));
$error = str_replace(array("\r\n", "\r", "\n"), '', strip_tags($out3[1]));
if ($error == 0) {
echo '<br>Результат: '.$res.'<br>Token: '.$token.')';
} else {
$errors = array(
1 => 'Invalid session',
2 => 'Invalid service',
3 => 'Invalid result',
4 => 'Invalid input',
5 => 'Error performing request',
6 => 'Неизвестная ошибка',
7 => 'Доступ запрещён',
8 => 'Неверное имя или пароль.',
9 => 'Authorization server is unavailable, please try again later',
1001 => 'No message for selected interval',
1002 => 'Item with such unique property already exists',
1003 => 'Only one request of given time is allowed at the moment',
1006 => 'Превышен лимит попыток входа. Повторите попытку позже.'
);
echo '<br>Результат - неудача. <br>Логин: "<b>'.$login.'</b>" или пароль: "<b>'.$passw.'</b>".<br>Ошибка: <b> '.$errors[$error].'</b> ('.$error.')';
unset ($target_link, $postFields, $errortext);
}
}
}
}
?>
Может кому пригодится.
демо версия: Проверить работу скрипта
В процессе выяснил что при множественных запросах (циклических) с положительным результатом существует ограничение по количеству авторизаций, а вот при отрицательном результате (неправильные пары логин/пароль) ограничения нет
Что в свою очередь потенциально позволяет осуществить брут (подбор) пароля.
Циферный пароль из 6 символов подберётся за 10 - 11 дней.
Вывод:
Пользователям и Администраторам - На ответственных УЗ использовать сложные пароли не менее 8 символов.
Разрабам - может стоит как-то ограничить количество неправильно введённых учетных данных?