(一)HTTP 根本认证(Basic Authentication)原理过程,以及esp32 idf服务器 ...

打印 上一主题 下一主题

主题 1930|帖子 1930|积分 5790

媒介:通过同时讲诉服务器和客户端的处置惩罚情况,来理通思维,便于明白整个Basic Authentication认证过程.


一.先遍及一下根本知识:

Base64 是一种将二进制数据转换为 ASCII 字符串的编码方式,利用 64 个可打印字符(A-Z, a-z, 0-9, +, /)表示二进制内容,并在末尾用 = 填充。其核心目的是解决二进制数据在纯文本协议(如 HTTP)中传输时的兼容性问题。
HTTP 根本认证(Basic Authentication) 作用:将用户名和密码拼接为 username:password 格式后 Base64 编码,置于 Authorization: Basic <凭据> 头中传输。例如:
  1. GET /protected-resource HTTP/1.1
  2. Authorization: Basic dXNlcjpwYXNzd2Q=
复制代码
Base64优势


  • 文本协议兼容性
    确保二进制数据(如加密哈希、文件内容)在 HTTP 头或 URL 中不因非 ASCII 字符被截断或转义。
  • 浅显性与通用性

    • 全部编程语言均支持 Base64 编解码库(如 Python 的 base64、C 的 mbedtls_base64)。
    • 无需复杂配置,得当快速实现轻量级数据封装。

Base64局限性


  • 数据膨胀
    Base64 编码后数据体积增加约 33%(每 3 字节二进制数据扩展为 4 字符),可能影响传输服从。
  • 无加密保护
    Base64 仅编码而非加密,攻击者可轻易解码还原原始数据(发起配合 HTTPS 补充安全性)。

二.HTTP根本认证的原理


  • 认证流程

    • 步调1:客户端初次请求
      客户端发送不带认证信息的HTTP请求到服务器受保护资源:GET /protected-resource HTTP/1.1
    • 步调2:服务器返回质询(Challenge)
      服务器返回401 Unauthorized状态码,并在相应头中添加:WWW-Authenticate: Basic realm="SecureArea"
      其中realm定义受保护资源的安全域,浏览器会弹出用户名/密码输入框。
    • 步调3:客户端发送凭据
      用户输入凭据后,客户端将username:password拼接后进行Base64编码,生成Authorization头:Authorization: Basic dXNlcjpwYXNzd29yZA==
    • 步调4:服务器验证
      服务器解码Base64字符串,分离用户名和密码进行校验,通过则返回资源,失败则重复步调2。

  • 安全性问题

    • Base64仅为编码而非加密,凭据易被解码为明文,需配合HTTPS保证传输安全。
    • 无法防御重放攻击,攻击者可截获凭据后重复利用。

  • Base64编码依赖
    利用mbedtls/base64.h库进行编码,需在menuconfig中启用MBEDTLS_BASE64_C组件。
  • esp32 idf实现细节:
客户端发送请求访问受限区域,服务器返回401未授权,要求认证。客户端将用户名和密码拼接成“username:password”格式,进行Base64编码,然后放在Authorization头的Basic字段中发送。服务器解码验证,通过则返回资源。
对于服务器部分,需要ESP-IDF的httpd组件,创建HTTP服务器。处置惩罚函数中,查抄请求头中的Authorization字段,如果没有,发送401,并设置WWW-Authenticate头。如果有,解码Base64,验证用户名密码。
对于客户端部分,利用esp_http_client组件。当发起请求时,如果服务器返回401,需要处置惩罚重试,或者直接预先添加Authorization头。主动处置惩罚401可能需要客户端自己处置惩罚,或者直接在第一次请求时添加Authorization头,制止401相应。
详细步调:
服务器实现步调:
1. 配置并启动HTTP服务器。
2. 注册处置惩罚程序,例如处置惩罚GET请求到某个URI。
3. 在处置惩罚函数中,查抄请求头的Authorization字段。
4. 如果没有该字段,设置相应状态为401,添加WWW-Authenticate头,返回。
5. 如果有,提取Basic后面的凭据,进行Base64解码。
6. 拆分用户名和密码,与预设的进行比较。
7. 如果匹配,返回请求的资源;否则返回403禁止访问。
客户端实现步调:
1. 配置WiFi毗连,毗连到AP。
2. 利用esp_http_client发起HTTP GET请求。
3. 构造Authorization头,将用户名密码拼接后Base64编码。
4. 将头添加到请求中,发送请求。
5. 处置惩罚相应。
如今,代码方面需要注意的点:
服务器端:
- 利用httpd_config_t配置服务器参数。
- 创建URI处置惩罚函数,查抄请求头。
- 处置惩罚Base64解码,用户密码校验。
- 需要包罗须要的头文件,比如httpd.h,以及base64编解码函数。
客户端端:
- 利用esp_http_client_config_t配置客户端参数。
- 生成Authorization头,其中Base64编码需要注意是否正确处置惩罚。
- 可能需要手动添加头字段。
Base64编码在ESP32中可以用mbedtls库中的函数,或者利用内置的base64编码函数。例如,esp-idf有提供base64_encode函数吗,或者需要自己实现,或者利用mbedtls的base64函数。
例如,利用mbedtls_base64_encode函数来编码用户名和密码的字符串。
注意,在拼接用户名密码时,中间用冒号毗连,例如"admin:password",然后Base64编码。
在服务器端,收到Authorization头后,取出Base64字符串,解码得到"username:password",然后分割比较。
三.服务器代码

ESP32 IDF 实现服务器端代码 实现一个带有 Basic 认证的 HTTP 服务器。
  1. #include <string.h>
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "esp_system.h"
  5. #include "esp_wifi.h"
  6. #include "esp_event.h"
  7. #include "esp_log.h"
  8. #include "nvs_flash.h"
  9. #include "esp_http_server.h"
  10. #include "mbedtls/base64.h"
  11. static const char *TAG = "http_server";
  12. #define WIFI_SSID      "YOUR_SSID"
  13. #define WIFI_PASS      "YOUR_PASSWORD"
  14. static httpd_handle_t server = NULL;
  15. // Basic 认证处理函数
  16. static esp_err_t basic_auth_handler(httpd_req_t *req) {
  17.     const char *auth_header = httpd_req_get_hdr_value_str(req, "Authorization");
  18.     if (!auth_header) {
  19.         httpd_resp_set_status(req, "401 Unauthorized");
  20.         httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm="Restricted Area"");
  21.         httpd_resp_send(req, "Authentication Required", HTTPD_RESP_USE_STRLEN);
  22.         return ESP_OK;
  23.     }
  24.     if (strncmp(auth_header, "Basic ", 6) != 0) {
  25.         httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid auth header");
  26.         return ESP_FAIL;
  27.     }
  28.     const char *encoded_creds = auth_header + 6;
  29.     uint8_t decoded_creds[128];
  30.     size_t out_len;
  31.     int ret = mbedtls_base64_decode(decoded_creds, sizeof(decoded_creds), &out_len,
  32.                                    (const unsigned char *)encoded_creds, strlen(encoded_creds));
  33.     if (ret != 0) {
  34.         httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Base64 decode failed");
  35.         return ESP_FAIL;
  36.     }
  37.     decoded_creds[out_len] = '\0';
  38.     char *username = strtok((char *)decoded_creds, ":");
  39.     char *password = strtok(NULL, ":");
  40.     if (!username || !password) {
  41.         httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid credentials");
  42.         return ESP_FAIL;
  43.     }
  44.     // 验证用户名密码(示例为 admin/password123)
  45.     if (strcmp(username, "admin") || strcmp(password, "password123")) {
  46.         httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Invalid credentials");
  47.         return ESP_FAIL;
  48.     }
  49.     httpd_resp_send(req, "Authenticated Successfully!", HTTPD_RESP_USE_STRLEN);
  50.     return ESP_OK;
  51. }
  52. // URI 路由配置
  53. static httpd_uri_t uri_handler = {
  54.     .uri = "/",
  55.     .method = HTTP_GET,
  56.     .handler = basic_auth_handler,
  57.     .user_ctx = NULL
  58. };
  59. // 启动 HTTP 服务器
  60. static void start_webserver() {
  61.     httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  62.     config.lru_purge_enable = true;
  63.     if (httpd_start(&server, &config) == ESP_OK) {
  64.         httpd_register_uri_handler(server, &uri_handler);
  65.         ESP_LOGI(TAG, "HTTP server started");
  66.     } else {
  67.         ESP_LOGE(TAG, "Failed to start server");
  68.     }
  69. }
  70. // WiFi 事件处理
  71. static void wifi_event_handler(void *arg, esp_event_base_t event_base,
  72.                                int32_t event_id, void *event_data) {
  73.     if (event_id == WIFI_EVENT_STA_START) {
  74.         esp_wifi_connect();
  75.     } else if (event_id == IP_EVENT_STA_GOT_IP) {
  76.         start_webserver();
  77.     }
  78. }
  79. // 初始化 WiFi
  80. static void wifi_init_sta() {
  81.     esp_netif_init();
  82.     esp_event_loop_create_default();
  83.     esp_netif_create_default_wifi_sta();
  84.     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  85.     esp_wifi_init(&cfg);
  86.     esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL);
  87.     esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL);
  88.     wifi_config_t wifi_config = {
  89.         .sta = {
  90.             .ssid = WIFI_SSID,
  91.             .password = WIFI_PASS,
  92.             .threshold.authmode = WIFI_AUTH_WPA2_PSK
  93.         }
  94.     };
  95.     esp_wifi_set_mode(WIFI_MODE_STA);
  96.     esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
  97.     esp_wifi_start();
  98. }
  99. void app_main() {
  100.     nvs_flash_init();
  101.     wifi_init_sta();
  102. }
复制代码
四.客户端代码
实现一个通过 Basic 认证访问服务器的客户端。
  1. #include <string.h>
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "esp_system.h"
  5. #include "esp_wifi.h"
  6. #include "esp_event.h"
  7. #include "esp_log.h"
  8. #include "nvs_flash.h"
  9. #include "esp_http_client.h"
  10. #include "mbedtls/base64.h"
  11. static const char *TAG = "http_client";
  12. #define WIFI_SSID      "YOUR_SSID"
  13. #define WIFI_PASS      "YOUR_PASSWORD"
  14. #define SERVER_URL     "http://SERVER_IP/"
  15. // HTTP 客户端任务
  16. static void http_client_task(void *pvParameters) {
  17.     const char *username = "admin";
  18.     const char *password = "password123";
  19.     char credentials[64];
  20.     snprintf(credentials, sizeof(credentials), "%s:%s", username, password);
  21.     unsigned char encoded_creds[128];
  22.     size_t encoded_len;
  23.     int ret = mbedtls_base64_encode(encoded_creds, sizeof(encoded_creds), &encoded_len,
  24.                                    (const unsigned char *)credentials, strlen(credentials));
  25.     if (ret != 0) {
  26.         ESP_LOGE(TAG, "Base64 encode failed: %d", ret);
  27.         vTaskDelete(NULL);
  28.         return;
  29.     }
  30.     encoded_creds[encoded_len] = '\0';
  31.     char auth_header[128];
  32.     snprintf(auth_header, sizeof(auth_header), "Basic %s", encoded_creds);
  33.     esp_http_client_config_t config = {
  34.         .url = SERVER_URL,
  35.         .method = HTTP_METHOD_GET,
  36.     };
  37.     esp_http_client_handle_t client = esp_http_client_init(&config);
  38.     esp_http_client_set_header(client, "Authorization", auth_header);
  39.     esp_err_t err = esp_http_client_perform(client);
  40.     if (err == ESP_OK) {
  41.         ESP_LOGI(TAG, "Status = %d, Content Length = %d",
  42.                  esp_http_client_get_status_code(client),
  43.                  esp_http_client_get_content_length(client));
  44.     } else {
  45.         ESP_LOGE(TAG, "Request failed: %s", esp_err_to_name(err));
  46.     }
  47.     esp_http_client_cleanup(client);
  48.     vTaskDelete(NULL);
  49. }
  50. // WiFi 事件处理
  51. static void wifi_event_handler(void *arg, esp_event_base_t event_base,
  52.                                int32_t event_id, void *event_data) {
  53.     if (event_id == WIFI_EVENT_STA_START) {
  54.         esp_wifi_connect();
  55.     } else if (event_id == IP_EVENT_STA_GOT_IP) {
  56.         xTaskCreate(http_client_task, "http_client_task", 4096, NULL, 5, NULL);
  57.     }
  58. }
  59. // 初始化 WiFi
  60. static void wifi_init_sta() {
  61.     esp_netif_init();
  62.     esp_event_loop_create_default();
  63.     esp_netif_create_default_wifi_sta();
  64.     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  65.     esp_wifi_init(&cfg);
  66.     esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL);
  67.     esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL);
  68.     wifi_config_t wifi_config = {
  69.         .sta = {
  70.             .ssid = WIFI_SSID,
  71.             .password = WIFI_PASS,
  72.             .threshold.authmode = WIFI_AUTH_WPA2_PSK
  73.         }
  74.     };
  75.     esp_wifi_set_mode(WIFI_MODE_STA);
  76.     esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
  77.     esp_wifi_start();
  78. }
  79. void app_main() {
  80.     nvs_flash_init();
  81.     wifi_init_sta();
  82. }
复制代码
说明


  • 配置 WiFi 信息
    更换代码中的 YOUR_SSID、YOUR_PASSWORD 和 SERVER_IP。
  • 部署服务器和客户端

    • 服务器代码:运行在提供资源的 ESP32 上。
    • 客户端代码:运行在需要访问资源的 ESP32 上。

  • 验证流程

    • 客户端初次请求会收到 401,随后携带认证头重新请求。
    • 服务器验证通事后返回资源,否则返回 403。

通过上述代码,ESP32 可实现完备的 HTTP 根本认证流程,适用于 IoT 设备的安全通讯场景。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

徐锦洪

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表