Прочитав статью "Китай хочет запретить гражданам использовать Wi-Fi и Bluetooth", задумался о том, как можно различными способами использовать включенные Bluetooth-устройства, не подключаясь к ним (хотя и сама статья посвящена распространению нелегального контента). По сути, любое Bluetooth устройство — это небольшой маячок, который постоянно сообщает о себе миру. И если при поиске знакомых Wi-Fi-сетей устройства уже научились предоставлять случайный поддельный MAC-адрес, то, насколько мне известно, для Bluetooth этого пока нет (поправьте, если ошибаюсь).
Подобное поведение Bluetooth-устройств может быть использовано как в коммерческих целях (например, считать постоянных клиентов в магазине), так и в иных (например, для трекинга и слежения за человеком).
Исключительно в формате эксперимента был написан небольшой алгоритм в Automate, который каждые 15 секунд сканирует Bluetooth-устройства и сохраняет в лог имена, адреса и локацию:
![Flow из Automate Flow из Automate](https://habrastorage.org/getpro/habr/upload_files/988/5f4/3b1/9885f43b14f33495f427e25eda1dfca5.png)
Пустой файл необходимо заранее создать на устройстве (этот алгоритм не проверяет наличие файла и не создает новый — скорость эксперимента была важнее оптимизации).
Получаем файл примерно такого вида:
![Полученный лог с устройствами, адресами и локацией Полученный лог с устройствами, адресами и локацией](https://habrastorage.org/getpro/habr/upload_files/d33/54a/27d/d3354a27d464228c83e943d16996221f.png)
Подготовим файл для дальнейшего анализа, распарсив на столбцы:
import pandas as pd
import csv
# Исходный файл
input_file = "btlog.txt"
# Файл, куда будут записаны данные
output_file = "formatted_file.csv"
with open(input_file, 'r', encoding='utf-8') as inp, open(output_file, 'w', newline='', encoding='utf-8') as out:
writer = csv.writer(out)
writer.writerow(["device name", "device address", "advertiser", "location", "datetime"])
for row in csv.reader(inp, delimiter=';'):
device_names = row[0].split(", ")
device_addresses = row[1].split(", ")
advertisers = row[2].split(", ")
location = f"{row[3]}, {row[4]}"
datetime = row[5]
min_len = min(len(device_names), len(device_addresses), len(advertisers))
for i in range(min_len):
writer.writerow([device_names[i], device_addresses[i], advertisers[i], location, datetime])
Получаем уже более стройную таблицу следующего вида
![Нормализованные данные Нормализованные данные](https://habrastorage.org/getpro/habr/upload_files/74e/18e/1f4/74e18e1f47ee9e09b244db22b32fd136.png)
Теперь нужен инструмент, который позволит выбрать устройство из списка и покажет на карте, где устройство было найдено.
Открываем Google Colab, добавляем CSV-файл в каталог, пишем сам инструмент.
Импорт библиотек:
!pip install pandas folium ipywidgets
import pandas as pd
import folium
from ipywidgets import interact
Подготовка данных из таблицы и форматирование значений:
df = pd.read_csv('formatted_file.csv', sep=',')
df['location'] = df['location'].apply(lambda x: [float(i) for i in x.split(',')])
df['datetime'] = pd.to_datetime(df['datetime'])
df['device address'] = df['device address'].str.strip() # удаление пробелов в начале и конце строки
df['device name'] = df['device name'].str.strip() # удаление пробелов в начале и конце строки
df['frequency'] = df.groupby('device address')['device address'].transform('count')
df = df.sort_values(by='frequency', ascending=False)
# Создание нового столбца 'device_info', объединяющего 'device name' и 'device address' для свитка с выбором устрйоства
df['device_info'] = df['device name'].fillna('unknown') + ' - ' + df['device address']
Делаем выпадающий список с выбором устройства:
@interact
def search_device(device=list(df['device_info'].unique())):
return df[df['device_info'] == device]
Визуализация данных на карте:
def visualize_on_map(device_info):
device_data = df[df['device_info'] == device_info]
m = folium.Map(location=device_data['location'].iloc[0], zoom_start=13)
for _, row in device_data.iterrows():
folium.Marker(
location=row['location'],
popup=folium.Popup('Дата: ' + str(row['datetime']), max_width=300)
).add_to(m)
return m
@interact
def interact_map(device=list(df['device_info'].unique())):
return visualize_on_map(device)
В результате получаем выпадающий список. Выбрав из него соответствующее устройство, видим на карте, где его встречали, а при нажатии на точку видим дату и время:
![Выбран Flipper для примера, так как это мое же устройство Выбран Flipper для примера, так как это мое же устройство](https://habrastorage.org/getpro/habr/upload_files/885/926/966/8859269668275b1bc04c76ee9d6c3e1b.png)
По данным есть некоторые погрешности. Например, едва ли за мной километр ходил человек с 60-дюймовым включенным телевизором, а я этого не заметил. Скорее всего, не успела обновиться локация. Телефоны редко сообщают о себе, а вот часы, наушники и прочие устройства — постоянно.
Все не более чем proof of concept для проведения самого экспримента.
По результатам этого эксперимента становится очевидно, что мы часто беспечно раскрываем информацию о своем местоположении и движениях. Мы невольно регистрируем свое присутствие, оставляя включенным Bluetooth на смартфоне. Этот эксперимент показывает, что по собранным данным можно узнать, где и с какими людьми вы чаще всего пересекаетесь, даже не зная об этом (не замечая их в толпе, в транспорте или в торговом центре), а также — насколько легко определить ваше присутствие в конкретном месте (при наличии там сканнера Bluetooth-устройств и известном MAC-адресе одного из ваших гаджетов).
С точки зрения информационной безопасности это может быть риском. Чтобы уменьшить его, рекомендуется выключать Bluetooth, когда он не используется.
Систему можно развивать, усложнять, делать сеть из Bluetooth-устройств с отслеживанием в конкретных локациях и т.д. Варианты зависят от поставленных целей.