Хакер - Как приручить «Киви». Автоматизируем прием платежей Qiwi на Python

Хакер - Как приручить «Киви». Автоматизируем прием платежей 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




Report Page