EM-129: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
 
(не показана 1 промежуточная версия этого же участника)
Строка 3: Строка 3:
 
[[Категория:EM-129]]
 
[[Категория:EM-129]]
 
[[Категория:Networking]]
 
[[Категория:Networking]]
  +
[[Категория:Zabbix]]
  +
   
 
=EM-129=
 
=EM-129=
Строка 62: Строка 64:
 
* TOKEN_URL - адрес куда послылать запрос на SID
 
* TOKEN_URL - адрес куда послылать запрос на SID
 
* ALL_DATA_URI - суффикс запроса данных
 
* ALL_DATA_URI - суффикс запроса данных
  +
<BR>
 
  +
<BR>
 
Секретная строка формируется следующим образом:
 
Секретная строка формируется следующим образом:
   
Строка 69: Строка 72:
 
- Пользовательский пароль закодированный в base64
 
- Пользовательский пароль закодированный в base64
 
- "соль"
 
- "соль"
  +
<BR>
 
 
По шагам
 
По шагам
* A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')" - послать запрос на соль и взять поле с именем "SALT" из полученного json
+
* '''A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')'''" - послать запрос на соль и взять поле с именем "SALT" из полученного json
* S=$(printf ${EM_129_PASSWORD} | base64) - закодировать пароль
+
* '''S=$(printf ${EM_129_PASSWORD} | base64)''' - закодировать пароль
* SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}" - склеять строки
+
* '''SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}"''' - склеять строки
* LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')" - взять sha1 от склейки строк
+
* '''LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')"''' - взять sha1 от склейки строк
* SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')" - отправить запрос на SID и взять из ответа значение поля SID
+
* '''SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')"''' - отправить запрос на SID и взять из ответа значение поля SID
  +
<BR>
 
 
Получение данных дальше
 
Получение данных дальше
* ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}" - сформировать адрес куда слать запрос с учетом SID
+
* '''ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}"''' - сформировать адрес куда слать запрос с учетом SID
* D=$(curl ${ALL_DATA_URL} | jq -r .) получить данные
+
* '''D=$(curl ${ALL_DATA_URL} | jq -r .)''' получить данные
  +
<BR>
 
  +
<BR>
 
Данные получаются в виде json (для некоторых полей нужен множитель 0.1 или 0.01 - сопоставить с интерфейсом устройства не сложно)
 
Данные получаются в виде json (для некоторых полей нужен множитель 0.1 или 0.01 - сопоставить с интерфейсом устройства не сложно)
  +
<BR>
 
<PRE>
 
<PRE>
 
{
 
{

Текущая версия на 15:59, 24 августа 2022


EM-129

В связи с нестабильностью питания решил наконец поставить хоть какое-то защитное реле что б не спалить технику
(в последний раз броски напряжения не пережил свитч Catalyst 3550 и я остался без PoE для все своих железок чем был сильно расстроен)


По EM-129 есть практически исчерпывающий обзор от Андрея, которому нет причин не доверять:

Однако в обзоре не упоминается ничего про программную часть устройства

Зачем?

Я принципиально не хочу отправлять свои данные в любой клауд, если это не мой клауд и привязывать устройство к чему-ьто в интернете мне кажется очень странной идеей

Пару слов об устройстве

Я не могу сказать ничего хорошего про реализацию безопастности EM-129

  • Поддержка HTTPS отсутвует
  • Кабельного подключения нет

Этих 2 факторов вполне достаточно что бы при желании можно было взломать сеть и отснифить пароль - в качестве "защиты" могу скаазть только что надо подойти достаточно близко что бы сниффить траффик.


Сигнал достаточно слабый хотя расстяние от места установки до точки доступа - примерно 5 метров и одна бетонная стена

/interface/wireless/registration-table/print
Columns: INTERFACE, MAC-ADDRESS, AP, SIGNAL-STRENGTH, TX-RATE, UPTIME
2  wlan-2.4Ghz-ssid-infra-1  CC:50:E3:FA:83:55  no  -81dBm@1Mbps     18Mbps                  1d1h13m32s


Получение данных

О программной реализации интерфейса тоже можо сказать мало хорошего
Из плюсов могу отметить только то что инерфейс работает относительно быстро и не слишком уродлив, впрочем что и не удивительно - под капотом там JavaScript который только отсылает на устройство запросы данных, вся обработка и отрисовка происходит на стороне браузера


Из минусов - авторизация сделана максимально плохо

  • Используется только пароль, без логина
  • При авторизации создается Session ID (далее SID) который может быть только один и который по сути представляет собой префикс в URL для получения данных
  • Прямое следствие этого - на устройство можно зайходить и смотреть только одному пользователю одновременно. При подключении второго SID меняется и первого "отлогинивает"
  • BasicAuth был бы лучше в разы


Для того что бы понять как происходит авторизация пришлось немного покопаться в коде JS (что замечу говорит о "удачности" решения)

Авторизация происходит следующим образом

  • Пользователь вводит пароль
  • Браузер отправляет на устройство запрос что бы получить "соль" (случайное число) и тип устройства (похоже что аналогичный код используется не только в EM-129 но и других реле)
  • На оснвани полученой соли, имени устройства и пользовательского пароля формируется "секретная строка" и отправляется на сервер (основое время было потрачено на то что б найти как формируется эта секретная строка, и я не пишу на JavaScript. Думаю у web-разработчика это заняло бы единицы минут а не пол часа как у меня)
  • Если строка верна то сервер возвращает SID
  • ВСЕ!

Код скрипта

27 строк на bash

  • IP - адрес реле
  • SALT_URL - адрес куда посылать запрос на "соль"
  • TOKEN_URL - адрес куда послылать запрос на SID
  • ALL_DATA_URI - суффикс запроса данных



Секретная строка формируется следующим образом:

  • sha1 от строки состоящей из 3 частей
- имя устройства
- Пользовательский пароль закодированный в base64
- "соль"


По шагам

  • A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')" - послать запрос на соль и взять поле с именем "SALT" из полученного json
  • S=$(printf ${EM_129_PASSWORD} | base64) - закодировать пароль
  • SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}" - склеять строки
  • LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')" - взять sha1 от склейки строк
  • SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')" - отправить запрос на SID и взять из ответа значение поля SID


Получение данных дальше

  • ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}" - сформировать адрес куда слать запрос с учетом SID
  • D=$(curl ${ALL_DATA_URL} | jq -r .) получить данные



Данные получаются в виде json (для некоторых полей нужен множитель 0.1 или 0.01 - сопоставить с интерфейсом устройства не сложно)

{
  "volt_msr": 2302,
  "freq_msr": 5000,
  "cur_msr": 321,
  "pows_msr": 740,
  "enrga_msr": 32,.
  "enrga_d_msr": 0,
  "enrga_w_msr": 0,
  "enrga_m_msr": 0,
  "enrgs_msr": 39,
  "sys_flag": 1409482896,
  "faul_flag": 0,
  "ar_time": 0,
  "cost_energy": 1700,
  "cost_unit": 16,
  "STATUS": "OK"
}

Код скрипта

#!/bin/bash

set -eu${DEBUG:+x}

IP="192.168.31.250"
SALT_URL="http://${IP}/api/login?salt"
TOKEN_URL="http://${IP}/api/login?login="
ALL_DATA_URI="api/all/get?volt_msr&freq_msr&cur_msr&pows_msr&enrga_msr&enrga_d_msr&enrga_w_msr&enrga_m_msr&enrgs_msr&sys_flag&faul_flag&ar_time&cost_energy&cost_unit"

A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')"
E__EM_129_DEVNAME="EM-129"
EM_129_PASSWORD="12345678"

S=$(printf ${EM_129_PASSWORD} | base64)
SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}"
LOGIN="$(printf "${SUM}" |  sha1sum | awk '{ print $1}')"
SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')"


ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}"
D=$(curl ${ALL_DATA_URL} | jq -r .)
if [ "${D}X" != "X" ];
then
    echo "${D}"
else
    echo "{}"
    exit 1
fi
exit 0

Интеграция с мониторингом

Имя возможность получать данные с устройства не составит труда сделать интеграцию за заббиксом или прометеем
В моем случае все максимально просто и практически полностью соответвует статье https://serveradmin.ru/parsing-i-peredacha-json-dannyih-v-zabbix/

  • Добавить скрипт в агента (не забыть дать возможность агенту ходить на устройство если они в разных VLAN и между ними есть фильтрация)
cat /etc/zabbix/zabbix_agentd.d/UserParameter-ElectricCounter.conf
UserParameter=electricCounter,/etc/zabbix/scripts/counter.sh

Далее сделать зависимые Items как описано выше по сслыке. Готовый темплейт для особо ленивых ниже =)

Zabbix template