• Forum has been upgraded, all links, images, etc are as they were. Please see Official Announcements for more information

Аутентификация с помощью кошелька

Balych

Active member
Возникла мысль, зачем серверу хранить пароли, а пользователю их запоминать, когда у нас есть такая замечательная вещь, как блокчейн.
Идея в том, что пользователь, представляясь своим публичным ключом (т.е. адресом), подтверждает владением им, подписывая предоставленную сервером случайную строку. А сервер может удостоверится, что сессия валидна, проверив подпись.

Ниже пример реализации, демо доступно на https://auth.dashnetwork.info/

Вводим наш DASH-адрес (впрочем, при других настройках, это может быть и адрес любого коина, поддерживающего подпись сообщений):

LosHnfK.png


Сервер генерирует строку (над ее случайностью, конечно, надо поработать...) и предлагает ее подписать:

yeXwKvw.png


Тут бы, конечно, пригодилась реализация типа BIP-0021, только для работы с сообщениями, но ничего такого мной не обнаружилось :(

В общем, подписываем сообщение с помощью dash-cli или в Dash Core:

5U9xkK0.png


И радуемся успешному входу:

aMi6D4f.png


Исходники:

PHP:
<?php
session_start();
require_once('easydash.php');

if ($_POST['login']) {
    $_SESSION['login'] = filter_input(INPUT_POST, 'login', FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^[X][a-km-zA-HJ-NP-Z1-9]{25,34}$/')));
    if ($_SESSION['login'] == true) {
        $_SESSION['message'] = sha1(crypt(time().inet_pton($_SERVER['REMOTE_ADDR']).$_SESSION['login']));
        echo '
            Sign this message:<br /><br />
            <input type="text" id="message" value="'.$_SESSION['message'].'" readonly /><br /><br />
            <input type="text" name="signature" id="signature" placeholder="Input signature"  ><br /><br />
            <input type="submit" value="Login" />';
    }
}

if ($_POST['signature']) {
    $_SESSION['signature'] = filter_input(INPUT_POST, 'signature', FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/[a-zA-Z0-9=\/+]{88}/')));
    $dash = new \elbereth\EasyDash('rpc_username','rpc_password');
    $_SESSION['auth'] = $dash->verifymessage($_SESSION['login'],$_SESSION['signature'],$_SESSION['message']);
}

if ($_POST['logout']) {
    $_SESSION = array();
    session_destroy();
}

function is_auth() {
    if ($_SESSION['auth'] == true) {
        echo '
            Hello, '.$_SESSION['login'].'!<br /><br /><input type="hidden" name="logout" value="1"><input type="submit" value="Logout" />';
    } else if (!$_POST['login'] || ($_SESSION['login']==false && $_POST['login'])){
        echo '
            Hello, guest!<br /><br />
                <input type="text" name="login" id="login" placeholder="Input your DASH address" /><br /><br />
                <input type="submit" value="Login" />';
        $_SESSION = array();
        session_destroy();
    }
}

is_auth();
?>

HTML:
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Dash Network Info</title>
<style type="text/css">
body {
    margin: 0;
    padding: 0;
}
html, body, #wrapper { height: 100%; }
#wrapper {
    width: 100%;
    display:table;
}
#main_cell, #link_cell {
    display: table-cell;
    vertical-align: middle;
    text-align: center;
}
#main_cell { height: 95%; }
#link_cell { height: 5%; }
body * {
    font-family: Verdana;
    font-size: 3vmin;
    font-size: 3vm;
}
input {
    min-width: 70vmin;
    min-width: 70vm;
    text-align: center;
}
#login, #signature, #message {
    outline: none;
    border: 0;
    border-bottom: #ccc 1px solid;
}
.row { display: table-row; }
a { text-decoration:none; }
a:link, a:visited { color: #1c75bc; }
a:hover, a:active { color: #ec2227; }
</style>
<script src="jquery.min.js"></script>
<script>
$(function() {
    auth();
    $("#auth_form").submit(function() {
        auth();
        return false;
    })
})
function auth() {
    $.ajax({
        url: "auth.php",
        type: "post",
        dataType: "html",
        data: $("#auth_form").serialize(),
        success: function(data) {
            $('#auth_div').html(data);
        },
        error: function() {
            $('#auth_div').html('Authentication not available');
        }
    })
}
</script>
</head>
<body>
<div id="wrapper">
    <div class="row">
        <div id="main_cell">
            <form action="" method="POST" id="auth_form">
                <div id="auth_div">
                  
                </div>
            </form>
        </div>
    </div>
    <div class="row">
        <div id="link_cell">
            <a id="link" href="https://www.dash.org">www.dash.org</a>
        </div>
    </div>
</div>
</body>
</html>

Для проверки подписи используется сторонний скрипт easydash.php, хотя можно было бы обойтись обработкой dash-cli. Так же требуется JQuery.

И еще я не уверен на счет правильности регулярных выражений для проверки введенного DASH-адреса и подписи..

На готовое решение не претендует, но быть может кому-то пригодится, в т.ч. чтобы развить мысль дальше. Например, как элемент двухфакторной аутентификации, не требующей доверия третьей стороне, в отличие от СМС или Гугла.
 
Last edited:
Круто! :cool: Переводи пост на английский и запость куда-нибудь в основном форуме тоже плз (в общее или в обсуждение технологий).
 
Добавлена возможность аутентификации с помощью BTC-адреса. Проверка на стороне сервера происходит с помощью кошелька Electrum, вместо Bitcoin Core для экономии места на диске.

PHP:
<?php
session_start();
require_once('easydash.php');

if ($_POST['login']) {
    $_SESSION['login'] = filter_input(INPUT_POST, 'login', FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^[X][a-km-zA-HJ-NP-Z1-9]{25,34}$/')));
    $_SESSION['coin'] = 'dash';
    if ($_SESSION['login'] == false) {
        $_SESSION['login'] = filter_input(INPUT_POST, 'login', FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/')));
        $_SESSION['coin'] = 'btc';
    }
    if ($_SESSION['login'] == true) {
        $_SESSION['message'] = sha1(crypt(time().inet_pton($_SERVER['REMOTE_ADDR']).$_SESSION['login']));
        echo '
            Sign this message:<br /><br />
            <input type="text" id="message" value="'.$_SESSION['message'].'" readonly /><br /><br />
            <input type="text" name="signature" id="signature" placeholder="Input signature"  ><br /><br />
            <input type="submit" value="Login" />';
    }
}

if ($_POST['signature']) {
    $_SESSION['signature'] = filter_input(INPUT_POST, 'signature', FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => '/[a-zA-Z0-9=\/+]{88}/')));
    switch ($_SESSION['coin']) {
        case 'btc':
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_URL, 'http://127.0.0.1:7777');
            $data = '{"id":"curltext","method":"verifymessage","params":["'.$_SESSION['login'].'","'.$_SESSION['signature'].'","'.$_SESSION['message'].'"]}';
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            $result = json_decode(curl_exec($curl), true);
            $_SESSION['auth'] = $result['result'];
            break;
        case 'dash':
            $dash = new \elbereth\EasyDash('rpc_user','rpc_password');
            $_SESSION['auth'] = $dash->verifymessage($_SESSION['login'],$_SESSION['signature'],$_SESSION['message']);
            break;
    }
}

if ($_POST['logout']) {
    $_SESSION = array();
    session_destroy();
}

function is_auth() {
    if ($_SESSION['auth'] == true) {
        echo '
            Hello, '.$_SESSION['login'].'!<br /><br /><input type="hidden" name="logout" value="1"><input type="submit" value="Logout" />';
    } else if (!$_POST['login'] || ($_SESSION['login']==false && $_POST['login'])){
        echo '
            Hello, guest!<br /><br />
                <input type="text" name="login" id="login" placeholder="Input your BTC or DASH address" /><br /><br />
                <input type="submit" value="Login" />';
        $_SESSION = array();
        session_destroy();
    }
}

is_auth();
?>
 
Так на сервере нужно весь блокчайн иметь ? Затратно.
С кошельками Electrum - не нужно, да и Dash-блокчейн не такой объемный, как некоторые...
 
да и биткойн блокчейн не такой затратный при цене $100 за 3Тб, тот кто сервера поставил для авторизации, для того пара дисков не проблема.
 
Back
Top