NodeMCU/ESP8266安全发布到Azure IoT

NodeMCU/ESP8266安全发布到Azure IoT,azure,ssl,lua,esp8266,nodemcu,Azure,Ssl,Lua,Esp8266,Nodemcu,我正在尝试实现一个基本的传感器到云系统,通过RESTful HTTP/HTTPS POST将数据从ESP8266微控制器发送到Azure IoT云 使用NodeMCU Lua解释器 为了简洁起见,我省略了实际读取传感器并连接到WiFi LAN的代码。这些工作正常 我已经成功地将HTTP帖子发送到UbiDots,但我无法让Azure工作-我认为强制HTTPS是我无法工作的部分 我已经生成了一个SAS令牌,设置了Azure IoT Hub,我非常确定HTTP头是正确的,授权行包含在我从Azure I

我正在尝试实现一个基本的传感器到云系统,通过RESTful HTTP/HTTPS POST将数据从ESP8266微控制器发送到Azure IoT云

使用NodeMCU Lua解释器

为了简洁起见,我省略了实际读取传感器并连接到WiFi LAN的代码。这些工作正常

我已经成功地将HTTP帖子发送到UbiDots,但我无法让Azure工作-我认为强制HTTPS是我无法工作的部分

我已经生成了一个SAS令牌,设置了Azure IoT Hub,我非常确定HTTP头是正确的,授权行包含在我从Azure IoT Hub explorer工具生成的SAS中

==编辑===

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)
我现在通过使用nodemcuhttp(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(false)

然后再次尝试
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
==结束编辑===

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)
我确实知道HTTP库会使代码更整洁,但目前我已经编写了代码,没有使用它,我还没有回去编辑它以使用HTTP库等。我认为它应该仍然可以使用通用套接字库,并且仍然适用于不安全的普通HTTP post,所以,我想让一些东西现在就可以用最小的变化工作

以下是我认为有缺陷的部分

  serv_addr = AZURE_HUB .. ".azure-devices.net"
  tls.cert.verify(true)
  connection:connect(443, serv_addr)
end
这是正确的服务器地址结构、正确的端口和正确的tls使用以及正确的证书验证()吗

如果有人知道NodeMCU在哪里可以找到一个成功与Azure通信的最起码的工作示例,那么它可能真的很好。我还没找到

目前这对我来说有点头疼,但我认为他们正在迫使物联网边缘节点设备向相对安全的端到端系统过渡是件好事

我以前生成过证书:

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

如果将cert.verify切换为false,会发生什么情况?要使验证成功,您的设备需要有签署*.azure-devices.net证书的根CA。通常有一个助手二进制文件将多个根CA闪存到设备闪存上,至少ATWINC1500是这样,不知道ESP。远程设备可能没有通用密码套件。您可以通过ssllabs.com运行遥控器并进行比较。但不确定如何获取设备支持的密码。。一种方法是在www模式下运行一个简单的openssl s_服务器,看看在握手中宣传了什么。我可以在我的PC上运行openssl s_客户端-showcerts-connect myiothub.azure devices.net:8883,对吗?这是获得证书的正确方法吗?是的。应该是第一个,由巴尔的摩Cybertrust根颁发的证书。我已经尝试了这两个证书(CN=巴尔的摩Cybertrust根是列表中的第二个吗?),但两种方式都不起作用。
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