NodeMCU / ESP8266 защищенный пост в Azure IoT - PullRequest
0 голосов
/ 29 апреля 2018

Я пытаюсь внедрить базовую систему «датчик-облако», отправляющую данные из микроконтроллера ESP8266 в облако IoT Azure по протоколам RESTful HTTP / HTTPS.

Используется интерпретатор NodeMCU Lua.

Для краткости я опустил здесь код, который фактически считывает датчики и подключается к WiFi-сети. Они работают правильно.

Я успешно работал с HTTP POST для UbiDots, но я не могу заставить Azure работать - я думаю, что принудительный HTTPS - это та часть, с которой я не могу работать.

Я сгенерировал токен SAS, настроил IoT-концентратор Azure, и я почти уверен, что HTTP-заголовок правильный, а строка авторизации включена в SAS, который я сгенерировал из средства обозревателя IOT-концентраторов Azure.

=== РЕДАКТИРОВАТЬ ===

My NodeMCU build is as follows:
NodeMCU custom build by frightanic.com
                branch: dev
                commit: 5e1ca234cce36f251edd78dc3d5a5ce4d4c76a59
                SSL: true
                modules: adc,crypto,ds18b20,file,gpio,http,hx711,net,node,ow,sntp,tmr,uart,wifi,tls
 build created on 2018-04-26 07:02
 powered by Lua 5.1.4 on SDK 2.2.1(cfd48f3)

Теперь я сделал все намного лучше с помощью рефакторинга, использующего библиотеку NodeMCU HTTP (S). Соответствующий код следующим образом:

function postHTTPWebService(name1, val1, name2, val2, name3, val3, name4, val4)

  tls.cert.verify([[
  -----BEGIN CERTIFICATE-----
-- certificate mostly redacted
  MIIFtDCCBJygAwIBAgIQCLh6UBu+nNotFk0+OVG/VTANBgkqhkiG9w0BAQsFADBa
  86Qho5jQenT2jOjD0iuqK84RWRlE51wHCULr1/0VTblvbEQ1Joe6oztosIHnIMl/
  EwLzzKufHJVQy65kgLuHCl3OpmuyfeM9NuIpUbcl/NAJ47CtxGIuPn6FJrL2r/dt
  N2UI+5Gz6BZ2YSpl9ViUs0UB78BPA3u4
  -----END CERTIFICATE-----
  ]])

  tls.cert.verify(true)

  azure_url =
    "https://" .. AZURE_HUB .. ".azure-devices.net/devices/" ..
    AZURE_DEVICE .. "/messages/events?api-version=" .. AZURE_API

  azure_payload = json(name1, val1, name2, val2, name3, val3, name4, val4)

  azure_headers =
    "Authorization: " .. SAS_TOKEN .. "\r\n" ..
    "Content-Type: application/json\r\n" ..
    "Content-Length: " .. string.len(azure_payload) .. "\r\n" ..
    "Host: " .. AZURE_HUB .. ".azure-devices.net\r\n\n"

  http.post(azure_url, azure_headers, azure_payload,
    function(return_status, return_payload)
    if (return_status < 0) then -- big fail, no HTTP return at all
      print("HTTP request failed")
    elseif (return_status == 200) then
      print(return_payload)
      print("Got HTTP 200 return - entering deep sleep")
      node.dsleep(DEEPSLEEP_TIME)
    else
      -- There are many HTTP codes which are valid but still unsuccessful
      print("Got valid return status - not 200")
      print(return_status, return_payload)
    end
  end)
end

Когда я использую tls.cert.verify(true), я получаю следующий вывод:

E:M 1472
E:M 1520
E:M 1520
HTTP client: Disconnected with error: 88
HTTP client: Connection timeout
HTTP request failed

Теперь давайте попробуем tls.cert.verify(false)

E:M 40
E:M 1520
E:M 1520
E:M 120
HTTP client: Disconnected with error: -123
HTTP client: Connection timeout
HTTP request failed

И попробуйте tls.cert.verify(false) еще раз:

E:M 264
E:M 1520
E:M 1520
HTTP client: Disconnected with error: -16
HTTP client: Connection timeout
HTTP request failed

=== КОНЕЦ РЕДАКТИРОВАНИЯ ===

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

Следующая неисправная часть, я думаю

  serv_addr = AZURE_HUB .. ".azure-devices.net"
  tls.cert.verify(true)
  connection:connect(443, serv_addr)
end

Это правильная структура адреса сервера, правильный порт и правильное использование tls, а также правильный cert.verify ()?

Минимальный рабочий пример успешного взаимодействия с Azure может быть очень хорошим, если кто-нибудь знает, где его найти для NodeMCU. Я еще не нашел.

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

Я ранее сгенерировал сертификат:

tls.cert.verify([[
-----BEGIN CERTIFICATE-----
foo blah blah blah here is the certificate generated
-----END CERTIFICATE-----
]])

tls.cert.verify(true)

Так что теперь, когда мой код вызывает tls.cert.verify (true), этот сертификат уже должен храниться во флэш-памяти.

AZURE_DEVICE = "MyAzureDeviceName"
AZURE_HUB = "myazureiothub"
AZURE_API = "2016-02-03"

SAS_TOKEN = "123AFthisisafaketokenC4%3D"
DEEPSLEEP_TIME = 60000000 -- 1 minute in microseconds

local module = {}

function format_json(variable1, value1, variable2, value2, variable3, value3, variable4, value4)
  payload =
            '{\"' .. variable1..'\": {"value": ' .. value1..'},\"'
            .. variable2 .. '\": {"value": ' .. value2 .. '},\"'
            .. variable3 .. '\": {"value": ' .. value3 .. '},\"'
            .. variable4 .. '\": {"value": ' .. value4 .. '}}'
  return payload
end

function postHTTPWebService(name1, value1, name2, value2, name3, value3, name4, value4)

  connection =  tls.createConnection(net.TCP, 0)
  connection:on("receive", function(connection, payload)
    if (string.find(payload, "200 OK") ~= nil) then
      print("HTTP 200 received - OK");
      connection:close();
      collectgarbage();
      node.dsleep(DEEPSLEEP_TIME)
    else
      print("HTTP Return Error")
      print(payload) -- print the HTTP status returned. 
    end
  end)

  connection:on("connection", function(connection, payload)
    data = format_json(name1, value1, name2, value2, name3, value3, name4, value4)
    local post = "POST /devices/" .. AZURE_HUB .. "/messages/events?api-version=" .. AZURE_API .. " HTTP/1.1\r\n" ..
    "Host: " .. AZURE_HUB .. ".azure-devices.net\r\n" ..
    "Authorization: SharedAccessSignature " .. SAS_TOKEN .. "\r\n" ..
    "Content-Type: application/json\r\n" ..
    "Content-Length: " .. string.len(data) .. "\r\n" ..
    "\r\n" .. data .. "\n"
    print(post) -- print the full HTTP payload for debugging
    connection:send(post)
    print("HTTP POST sent.")
    end)

  connection:on("disconnection", function(connection, payload)
    connection:close();
    collectgarbage();
  end)

  serv_addr = AZURE_HUB .. ".azure-devices.net"
  tls.cert.verify(true)
  connection:connect(443, serv_addr)
end

function readSensors()
  value1 = 1 -- Dummy sensor data for testing
  value2 = 2
  value3 = 3
  value4 = 4
  postHTTPWebService("sensor1", value1, "sensor2", value2, "sensor3", value3, "sensor4", value4)
end

local function main_function()

  -- Wait a second, then run the sensor function
  tmr.alarm(3, 1000, tmr.ALARM_SINGLE, function() readSensors() end)
end

function module.start()
  main_function()
end
return module
...