Время прочтения: 6 мин.

Зарождение идеи.

Идея идентификации возникла из-за неутоленного любопытства о работе частных денег и экономики в целом, а также из-за вопросов: насколько крипта является заменой фиату, и насколько она анонимна. Также, все мы знаем, что крипту из-за ее «анонимности» используют в различных незаконных операциях, а из-за задачи по направлению комплаенс (соблюдение требований законодательства и внутренних регламентирующих документов), подвернулась возможность разбираться с этим с точки зрения рисков для работодателя (win to win, так сказать).

Сама идея состояла в том, чтобы:

  1. Найти криптокошельки каких-нибудь закоренелых злостных уголовников-террористов.
  2. Собрать их транзакции.
  3. Собрать транзакции их контрагентов по пополнению кошельков.
  4. Посмотреть по сумме и дате-времени, кто со своего банковского счета перевел сумму +- равную зачислению на криптокошелек (к счастью, нам предоставляется и сумма, и комиссия, и время транзакции крипты (blockchain помнит все))

Чуть упрощенная схема. Интересуют тут кошельки с картой (фиат) и поступления на криптокошельки после обменника.

Начало пути.

Для начала выберем человека, чей кошелек станем искать. Отправляемся на сайт Росфинмониторинга и ищем его в «Перечень организаций и физических лиц, в отношении которых имеются сведения об их причастности к экстремистской деятельности или терроризму»

Например, Иванов Иван Иванович.

Дальше ищем кошелек. Пишем в гугле название организации, переходим на сайт и… нас не пускает на сайт. Включаем впн и видим…

Нет, не это, хотя это в том числе

А все же видим кошелек для донатов

Action-сцена.

Ищем сайт, откуда собирать информацию о кошельке и транзакциях по нему. Я нашел tokenview, на нем можно посмотреть транзакции различных валют и информацию о кошельках, но это и была моя первая ошибка — написав код для получения информации по кошельку и движению средств по нему, оказалось, что сайт возвращает только последние 2,5 тысячи транзакций.

Ну хоть осталось получение минимальной информации (на следующей картинке):

Как видим по номеру находится несколько кошельков с различными валютами.

Код получения json с сайта прилагается:

public Wallets(string wallet)
        {
            Wallet = wallet;
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://tokenview.com/api/search/" + wallet);
            request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0";
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8";
            request.KeepAlive = true;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.Load(response.GetResponseStream(), Encoding.UTF8);
            JObject jObject = JObject.Parse(doc.Text);
            CryptoWallets = jObject["data"].ToObject<List<CryptoWallet>>();
        }

Дальше ищем транзакции. Следом за tokenview был найден сайт blockchain, не знаю на счет ошибочности выбора, но данный сервис в отличие от предыдущего готов нам дать уже 50 тысяч последних транзакций (иногда и этого не хватает), но на нем меньше выбор валют в отличие от предыдущего.

Ниже конструктор, который получает информацию о транзакциях.

public Transactions(string network, string wallet, int trCount)
        {
            Network = network;
            Wallet = wallet;
            TransactionsList = new List<Transaction>();
            for (int offset = 0, limit = 50; (TransactionsList.Count == 0 || TransactionsList.Count < trCount) && offset<=50000; offset += limit)
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Format(
                    "https://api.blockchain.info/haskoin-store/{0}/address/{1}/transactions/full?limit={2}&offset={3}",
                    Network.ToLower(), wallet, limit, offset));
                request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0";
                request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8";
                request.KeepAlive = true;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc.Load(response.GetResponseStream(), Encoding.UTF8);
                JObject jObject = JObject.Parse("{\"data\":" + doc.Text + "}");
                TransactionsList = TransactionsList.Concat(jObject["data"].ToObject<List<Transaction>>()).ToList();
            }
        }

И заодно несколько пометок касательно возвращаемого json-а:

  • Транзакции возвращаются в виде блоков, где может быть несколько транзакций, где несколько получателей и/или отправителей
  • Отправителей или получателей может быть крайне много
  • Есть ограничение по длине возвращаемого ответа, все, что больше ограничения, отсекается от ответа
  • Сумма возвращается в сатошах

Можно поставить, чтобы возвращалось больше транзакций в одном запросе (в коде переменная limit), но в свете вышеописанного неизбежны ошибки. Вот часть возвращаемых данных, где показаны отправители, получатели и суммы, где-о сбоку так же есть дата и время.

Если кто-то вдруг хочет посмотреть больше, то вот ссылка на все транзакции связанные с криптокошельком берлинского пациента.

Ну и так же нам для попыток идентификации все-таки нужна стоимость крипты в фиатной валюте на каждый день, а учитывая высокую валатильность крипты (так еще и всякие Илоны Маски вносят свою лепту), нужны сразу минимум две цифры- минимум и максимум цен за день.

Для добычи курса валют нашел сайт coinmarketcap. Думал, что придется сначала искать в долларах, затем тащить курсы с цб, но оказалось, что все может быть гораздо проще и можно смотреть сразу в рублях. Там есть еще валюты, но себе добавил только, то, что было интересно.

Соответственно код для сбора курсов валют:

private void AddFromSite(CoinСurrency coin, CoinСurrency fiat, DateTime startDate, DateTime finishDate)
        {
            double start = (startDate.Date - new DateTime(1970, 1, 1)).TotalSeconds;
            double finish = (finishDate.Date - new DateTime(1970, 1, 1)).TotalSeconds;
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(
                "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/historical?id=" +
                (int)coin +
                "&convertId=" +
                (int)fiat +
                "&timeStart=" +
                start +
                "&timeEnd=" +
                finish
                );
            request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0";
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8";
            request.KeepAlive = true;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.Load(response.GetResponseStream(), Encoding.UTF8);
            JObject jObject = JObject.Parse(doc.Text);
            if (name == null)
            {
                id = jObject["data"]["id"].ToObject<int>();
                name = jObject["data"]["name"].ToObject<string>();
                symbol = jObject["data"]["symbol"].ToObject<string>();
            }
            quotes = quotes.Concat(jObject["data"]["quotes"].ToObject<List<Quote>>()).ToList();

    public enum CoinСurrency
    {
        Bitcoin = 1,
        Russian_Ruble = 2806,
        Euro = 2790,
        United_States_Dollar = 2781
        ,Ethereum=1027
    }

Вот в принципе все, что напридумывал для сбора информации. К сожалению, пока не довел до конца задачу и не нашел всех спонсоров того, чье имя нельзя называть, может, когда-нибудь вернусь к этому и сообщу о результатах.

Заключение. Собрав всю вышеизложенную информацию, можно пытаться идентифицировать, при условии, что есть доступ к транзакциям фиата. Конечно, идентификация тут довольно вероятностная получается, и может несколько потенциальных владельцев быть на один кошелек, в силу того, что есть разброс по времени и суммам, но чем больше операция по обмену на один кошелек, тем больше вероятность идентификации.

(ну напрашивалась картинка из фильма)

Пока всем этим занимался, коллега подкинул статью «Использование общедоступных источников информации для деанонимизации криптовалютных кошельков», как минимум дает больше источников информации, ну и вроде, есть интересные мысли. До применения не добрался, так что прокомментировать не могу.

Для тех, кто хочет познакомится с криптой «Как работают криптовалюты. С картинками»

Ну и традиционно ссылка на GIT, правда код там страшен