Хакер - Как приручить «Киви». Автоматизируем прием платежей Qiwi на Python
hacker_frei
https://t.me/hacker_frei
Mazay
Содержание статьи
- Постановка задачи
- Реализация
- Локальная часть
- Серверная часть
- Чекер
- Выводы
Как говорил великий комбинатор, «О карманных деньгах не надо думать — они валяются на дороге, и мы будем их подбирать по мере надобности». В современном мире, где автоматизация легка и повсеместна, кешем обзаводиться можно даже не нагибаясь. Достаточно сделать полезную программу или сервис и подключить платежи. Сегодня мы поговорим именно о платежах и смастерим собственный скрипт для приема оплаты на кошелек Qiwi.
Этот сервис я выбрал как один из самых распространенных, удобных и не требующих сложных действий вроде регистрации ИП или заключения договоров. Зачем нам эта бюрократия? Нам работать надо!
Писать будем на Python, хотя, внимательно изучив примеры, ты сможешь при желании воспроизвести их на другом языке.
ПОСТАНОВКА ЗАДАЧИ
Итак, дано: есть программа, единственная функция которой — выводить на экран текстовое сообщение. Если программа работает в деморежиме, то сообщение будет «Демка», если в полноценном, то «Программа зарегистрирована». Демка бесплатна, полная версия будет стоить рубль (дороже такое вряд ли кто‑то купит).
Требуется: прикрутить к нашей программе возможность платно переключаться из деморежима в полноценный, при этом желательно вообще без нашего участия.
Вот наша программа:
def get_ID():
# Тут надо вставить генерацию уникального ключа,
# но для иллюстрации сойдет и просто константа,
# задаваемая вручную для каждого экземпляра ПО
return 1
def get_key_from_file(file_name):
try:
key_file = open(file_name, "r")
key = key_file.read()
return key
except:
return 0
def check_key():
key = int(get_key_from_file('key.txt'))
# Такой вот простой алгоритм генерации ключа
# В реальной программе следует придумать посложнее
if key == get_ID() * 2:
return True
else:
return False
if check_key():
print('Программа зарегистрирована!')
else:
print('Демка!')
Алгоритм работы такой:
- Программа при запуске создает ID пользователя. Можно, к примеру, генерировать идентификатор на основе серийников установленного железа, а если ты решил делать бота для Telegram, то достаточно взять
user_id. - Программа проверяет файл лицензии, где надеется увидеть сгенерированный на основе своего ID набор данных (назовем его ключом), из которого будет понятно, оплатил ли пользователь покупку.
- Если ключ подходит, то выводим сообщение об этом.
- Если ключ неправильный, программа выводит сообщение «Демка».
Нам нужно реализовать возможность получения ключа в автоматическом режиме, то есть без участия создателя программы. Ключ должен выдаваться каждому свой, в зависимости от ID, и только тем, кто нам заплатил.
Взаимодействовать с пользователем мы будем через Telegram, поскольку это просто, удобно и современно. При желании в качестве фронтенда можно использовать и сайт, а ключ высылать по электронной почте, но это совсем другая история.
Боты вместо программ
Я в этой статье использую очень примитивный вариант защиты. Даже если мы изобретем сложный способ генерации ID, для взломщика все в итоге сводится к тому, чтобы исправить результат сравнения ключа с эталонным. Чтобы усложнить ему жизнь, ты можешь использовать дополнительные защиты и методы обфускации.
Однако гораздо более простой способ защитить программу — это сделать ее сервисом. И если никакой сложный графический интерфейс не нужен, тогда отличный вариант — это бот в Telegram. В таком случае можно не заморачиваться с ключами и достаточно лишь проверять в базе факт оплаты.
Итак, недостатки бота:
- нельзя реализовать сложный интерфейс;
- нельзя работать с локальным оборудованием;
- сложно обрабатывать много файлов;
- необходимо постоянное подключение к интернету.
Достоинства бота:
- не надо беспокоиться о всякого рода зависимостях, совместимостях, версиях операционки и так далее — все будет работать под твоим неусыпным контролем;
- никто не будет иметь доступа к коду, и никто не сможет даже попытаться его взломать.
Предполагается, что пользователь программы будет оплачивать необходимую сумму на кошелек Qiwi, введя в комментариях ID.
Серверная же часть будет состоять из двух модулей: чекера и бота. Чекер станет с небольшим интервалом проверять кошелек и при получении платежей складывать информацию о них в базу, присовокупляя к ним айдишники пользователей и свежесгенерированные ключики. А бот получит от пользователя ID и проверит, есть ли он в базе оплаченных. Если есть, то вышлет в ответ ключик, который пользователю надо будет сохранить в каталог с программой.
Разработчику в таком случае остается только периодически проверять баланс кошелька да листать каталог элитной недвижимости, почесывая при этом пузо и сыто икая.
РЕАЛИЗАЦИЯ
Локальная часть
Итак, для начала идем на сайт Qiwi и создаем там пару ключей для доступа через API.

Ключи необходимо сохранить в надежном месте.
Когда мы будем отправлять пользователя на оплату, мы предложим ему перейти по ссылке такого вида:
https://oplata.qiwi.com/create?publicKey=<qiwi_public_key>&billId=<unical_paid_id>&amount=<price>&comment=<ID>&successUrl=<bot_url>
Здесь нужно подставить следующие параметры:
publicKey— публичный ключ для доступа к API Qiwi;billId— уникальный идентификатор счета, который нам необходимо генерировать самостоятельно. Думаю, можно обойтись нашим ID, к которому следует прибавить текущие дату и время, а для красоты — посчитать хеш от этой строки;amount— размер платежа в рублях, в нашем случае будет 1;comment— в комментарии следует положить ID, по которому чекер сможет понять, от кого пришел платеж и для какого ID ему следует создавать ключик;successUrl— адрес, на который отправят пользователя после оплаты. Сюда мы вставим адрес бота, выдающего ключ. Конечно, на всякий случай следует продублировать ссылку на бота в интерфейсе программы и в инструкции, мало ли что.
Добавляем в программу функцию, генерирующую URL:
def get_url():
url = 'https://oplata.qiwi.com/create?publicKey='+config.qiwi_public_key+\
'&billId='+get_unical_billID()+'&amount=1&comment='+str(get_ID())+'&successUrl="https://t.me/super_qiwi_xakep_bot?start="'+str(get_ID())
return""
И изменяем проверку ключа. Добавим в нее открытие нашей ссылки в браузере по умолчанию:
if check_key():
print('Программа зарегистрирована!')
else:
print('Демка!')
subprocess.Popen(('start', get_url()), shell=True)
В итоге пользователь будет отправлен на сайт Qiwi, где ему останется залогиниться и нажать кнопку «Перевести».

СЕРВЕРНАЯ ЧАСТЬ
На сервере нам понадобятся две программы. Первая — чекер, он будет регулярно проверять, поступили ли в кошелек свежие платежи, и сохранять их в базу данных. Вторая — бот, который должен взаимодействовать с пользователем и при наличии платежа в базе выдавать пользователю ключ взамен на ID.
Чекер
Для проверки списка последних платежей нам необходимо выпустить токен для API.
Этот токен нужно передавать в заголовке каждого запроса. Запускать чекер удобнее всего через cron. Итак, поехали:
#!/usr/bin/python3
import json
import sqlite3
import requests
import config
def keygen(ID):
return ID * 2
sqlite_connection = sqlite3.Connection
try:
# Подключаемся к базе
sqlite_connection = sqlite3.connect(config.db_name)
cursor = sqlite_connection.cursor()
# Создаем таблицу, если она отсутствует
sqlite_create_table_query = '''CREATE TABLE if not exists qiwi (
txnId INTEGER PRIMARY KEY,
account TEXT ,
summa text,
date datetime,
program_id text,
key text);'''
cursor.execute(sqlite_create_table_query)
sqlite_connection.commit()
s = requests.Session()
# Создаем заголовок с токеном
s.headers['authorization'] = 'Bearer ' + config.qiwi_api_access_token
parameters = {'rows': '50'}
# Запрашиваем список последних 50 платежей (если запускать чекер каждые 10 секунд, этого будет вполне достаточно на первых порах)
h = s.get('https://edge.qiwi.com/payment-history/v1/persons/' + config.qiwi_login + '/payments', params=parameters)
res = json.loads(h.text)
sqlite_insert_query = "INSERT INTO qiwi (date,txnId, account, summa, program_id, key) VALUES (?,?,?,?,?,?) "
# Пробегаемся по полученному списку
for data in res['data']:
if data['type'] == 'IN':
# Генерируем ключ, взяв ID пользователя из комментария к платежу
key = keygen(data['comment'])
data_tuple = (data['date'], data['txnId'], str(data['account']), str(data['sum']['amount']),
data['comment'], key)
try:
# И добавляем результат в базу. Если платеж уже добавлен, то ничего страшного не произойдет, словим exeption и продолжим работать дальше
cursor.execute(sqlite_insert_query, data_tuple)
except:
print("Ошибка добавления ")
sqlite_connection.commit()
cursor.close()
except sqlite3.Error as error:
print("Ошибка при подключении к sqlite" + str(error))
finally:
if sqlite_connection:
sqlite_connection.close()
Конечно, в реальный чекер следует добавить как минимум логирование ошибок и дополнительные проверки, но для понимания сути процесса это сейчас не важно.
Осталось сделать бота. Инструкций, как создать бота через BotFather, в интернете неисчислимое множество, поэтому перейду сразу к делу.
#!/usr/bin/python3
import telebot
import config
import sqlite3
# Создаем экземпляр бота
bot = telebot.TeleBot(config.tg_bot_token)
# Функция, обрабатывающая команду /start
@bot.message_handler(commands=["start"])
def start(message):
# При успешной оплате мы пересылаем пользователя на нашего бота, сразу передав в качестве параметра команды start ключ пользователя. Мы можем сразу обработать эту ситуацию и вернуть ключ. Если же пользователь сам пришел к боту, то надо пояснить ему, что нужно сделать
if message.text == '/start':
bot.send_message(message.chat.id,
'Привет! Пришли мне ID своей программы, и, если она оплачена, я пришлю тебе в ответ ключик.')
else:
if len(message.text) > 1 + len('/start'):
handle_text(message)
@bot.message_handler(content_types=["text"])
def handle_text(message):
sqlite_connection = sqlite3.Connection
try:
sqlite_connection = sqlite3.connect(config.db_name)
# Если это первый запуск, то отрезаем все лишнее, если не первый, то считаем, что нам передали ключ и ищем его в базе. По-хорошему, конечно, тут не помешает сделать какие-то дополнительные проверки, так что воспринимай это как макет программы
if str(message.text).startswith('/start'):
text = str(message.text)[len('/start') + 1:len(message.text)]
else:
text = message.text
sqlite_select_query = "SELECT * from qiwi where program_id ='" + text + "';"
cursor = sqlite_connection.cursor()
cursor.execute(sqlite_select_query)
rows = cursor.fetchall()
cursor.close()
key = ""
for row in rows:
key = row[5]
# Берем последний ключ из базы и отправляем его пользователю
if len(key) > 0:
bot.send_message(message.chat.id, 'Твой ключ: ' + key + '\nСохрани его в файл key.txt и положи рядом с программой.')
else:
bot.send_message(message.chat.id,
'Твоего ID нет в списке оплаченных. Возможно, платеж еще не обработан. Обычно это занимает не более минуты, попробуй еще раз через 5 минут, если не поможет — обращайся к разработчику, будем разбираться.')
except sqlite3.Error as error:
print(error)
finally:
if sqlite_connection:
sqlite_connection.close()
# Запускаем бота
bot.polling(none_stop=True, interval=0)
ВЫВОДЫ
Напоследок расскажу тебе о разновидности мошенничества, с которой я столкнулся при тестировании. В интернете продаются готовые аккаунты Qiwi, в том числе и прошедшие идентификацию и привязку к паспортным данным. Такие аккаунты часто покупают, чтобы не светить свои реальные данные.
Бывают случаи, когда мошенники продают аккаунты Qiwi по заведомо низким ценам, например по 5–10 рублей вместо 30 или 60. А после покупки легко может оказаться, что к такому аккаунту уже выпущен токен, с помощью которого можно проверять баланс, а самое главное — переводить деньги. У мошенников есть чекер, который постоянно проверяет проданный тебе кошелек и при появлении денег на балансе мгновенно переводит всю сумму или ее часть на свой кошелек. Будь осторожен и не гонись за бесплатным сыром!
Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei