媒介:通过同时讲诉服务器和客户端的处置惩罚情况,来理通思维,便于明白整个Basic Authentication认证过程.
一.先遍及一下根本知识:
Base64 是一种将二进制数据转换为 ASCII 字符串的编码方式,利用 64 个可打印字符(A-Z, a-z, 0-9, +, /)表示二进制内容,并在末尾用 = 填充。其核心目的是解决二进制数据在纯文本协议(如 HTTP)中传输时的兼容性问题。
HTTP 根本认证(Basic Authentication) 作用:将用户名和密码拼接为 username:password 格式后 Base64 编码,置于 Authorization: Basic <凭据> 头中传输。例如:
- GET /protected-resource HTTP/1.1
- 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 服务器。
- #include <string.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "esp_system.h"
- #include "esp_wifi.h"
- #include "esp_event.h"
- #include "esp_log.h"
- #include "nvs_flash.h"
- #include "esp_http_server.h"
- #include "mbedtls/base64.h"
- static const char *TAG = "http_server";
- #define WIFI_SSID "YOUR_SSID"
- #define WIFI_PASS "YOUR_PASSWORD"
- static httpd_handle_t server = NULL;
- // Basic 认证处理函数
- static esp_err_t basic_auth_handler(httpd_req_t *req) {
- const char *auth_header = httpd_req_get_hdr_value_str(req, "Authorization");
- if (!auth_header) {
- httpd_resp_set_status(req, "401 Unauthorized");
- httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm="Restricted Area"");
- httpd_resp_send(req, "Authentication Required", HTTPD_RESP_USE_STRLEN);
- return ESP_OK;
- }
- if (strncmp(auth_header, "Basic ", 6) != 0) {
- httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid auth header");
- return ESP_FAIL;
- }
- const char *encoded_creds = auth_header + 6;
- uint8_t decoded_creds[128];
- size_t out_len;
- int ret = mbedtls_base64_decode(decoded_creds, sizeof(decoded_creds), &out_len,
- (const unsigned char *)encoded_creds, strlen(encoded_creds));
- if (ret != 0) {
- httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Base64 decode failed");
- return ESP_FAIL;
- }
- decoded_creds[out_len] = '\0';
- char *username = strtok((char *)decoded_creds, ":");
- char *password = strtok(NULL, ":");
- if (!username || !password) {
- httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid credentials");
- return ESP_FAIL;
- }
- // 验证用户名密码(示例为 admin/password123)
- if (strcmp(username, "admin") || strcmp(password, "password123")) {
- httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Invalid credentials");
- return ESP_FAIL;
- }
- httpd_resp_send(req, "Authenticated Successfully!", HTTPD_RESP_USE_STRLEN);
- return ESP_OK;
- }
- // URI 路由配置
- static httpd_uri_t uri_handler = {
- .uri = "/",
- .method = HTTP_GET,
- .handler = basic_auth_handler,
- .user_ctx = NULL
- };
- // 启动 HTTP 服务器
- static void start_webserver() {
- httpd_config_t config = HTTPD_DEFAULT_CONFIG();
- config.lru_purge_enable = true;
- if (httpd_start(&server, &config) == ESP_OK) {
- httpd_register_uri_handler(server, &uri_handler);
- ESP_LOGI(TAG, "HTTP server started");
- } else {
- ESP_LOGE(TAG, "Failed to start server");
- }
- }
- // WiFi 事件处理
- static void wifi_event_handler(void *arg, esp_event_base_t event_base,
- int32_t event_id, void *event_data) {
- if (event_id == WIFI_EVENT_STA_START) {
- esp_wifi_connect();
- } else if (event_id == IP_EVENT_STA_GOT_IP) {
- start_webserver();
- }
- }
- // 初始化 WiFi
- static void wifi_init_sta() {
- esp_netif_init();
- esp_event_loop_create_default();
- esp_netif_create_default_wifi_sta();
- wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
- esp_wifi_init(&cfg);
- esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL);
- esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL);
- wifi_config_t wifi_config = {
- .sta = {
- .ssid = WIFI_SSID,
- .password = WIFI_PASS,
- .threshold.authmode = WIFI_AUTH_WPA2_PSK
- }
- };
- esp_wifi_set_mode(WIFI_MODE_STA);
- esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
- esp_wifi_start();
- }
- void app_main() {
- nvs_flash_init();
- wifi_init_sta();
- }
复制代码 四.客户端代码
实现一个通过 Basic 认证访问服务器的客户端。
- #include <string.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "esp_system.h"
- #include "esp_wifi.h"
- #include "esp_event.h"
- #include "esp_log.h"
- #include "nvs_flash.h"
- #include "esp_http_client.h"
- #include "mbedtls/base64.h"
- static const char *TAG = "http_client";
- #define WIFI_SSID "YOUR_SSID"
- #define WIFI_PASS "YOUR_PASSWORD"
- #define SERVER_URL "http://SERVER_IP/"
- // HTTP 客户端任务
- static void http_client_task(void *pvParameters) {
- const char *username = "admin";
- const char *password = "password123";
- char credentials[64];
- snprintf(credentials, sizeof(credentials), "%s:%s", username, password);
- unsigned char encoded_creds[128];
- size_t encoded_len;
- int ret = mbedtls_base64_encode(encoded_creds, sizeof(encoded_creds), &encoded_len,
- (const unsigned char *)credentials, strlen(credentials));
- if (ret != 0) {
- ESP_LOGE(TAG, "Base64 encode failed: %d", ret);
- vTaskDelete(NULL);
- return;
- }
- encoded_creds[encoded_len] = '\0';
- char auth_header[128];
- snprintf(auth_header, sizeof(auth_header), "Basic %s", encoded_creds);
- esp_http_client_config_t config = {
- .url = SERVER_URL,
- .method = HTTP_METHOD_GET,
- };
- esp_http_client_handle_t client = esp_http_client_init(&config);
- esp_http_client_set_header(client, "Authorization", auth_header);
- esp_err_t err = esp_http_client_perform(client);
- if (err == ESP_OK) {
- ESP_LOGI(TAG, "Status = %d, Content Length = %d",
- esp_http_client_get_status_code(client),
- esp_http_client_get_content_length(client));
- } else {
- ESP_LOGE(TAG, "Request failed: %s", esp_err_to_name(err));
- }
- esp_http_client_cleanup(client);
- vTaskDelete(NULL);
- }
- // WiFi 事件处理
- static void wifi_event_handler(void *arg, esp_event_base_t event_base,
- int32_t event_id, void *event_data) {
- if (event_id == WIFI_EVENT_STA_START) {
- esp_wifi_connect();
- } else if (event_id == IP_EVENT_STA_GOT_IP) {
- xTaskCreate(http_client_task, "http_client_task", 4096, NULL, 5, NULL);
- }
- }
- // 初始化 WiFi
- static void wifi_init_sta() {
- esp_netif_init();
- esp_event_loop_create_default();
- esp_netif_create_default_wifi_sta();
- wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
- esp_wifi_init(&cfg);
- esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL);
- esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL);
- wifi_config_t wifi_config = {
- .sta = {
- .ssid = WIFI_SSID,
- .password = WIFI_PASS,
- .threshold.authmode = WIFI_AUTH_WPA2_PSK
- }
- };
- esp_wifi_set_mode(WIFI_MODE_STA);
- esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
- esp_wifi_start();
- }
- void app_main() {
- nvs_flash_init();
- wifi_init_sta();
- }
复制代码 说明
- 配置 WiFi 信息
更换代码中的 YOUR_SSID、YOUR_PASSWORD 和 SERVER_IP。
- 部署服务器和客户端
- 服务器代码:运行在提供资源的 ESP32 上。
- 客户端代码:运行在需要访问资源的 ESP32 上。
- 验证流程
- 客户端初次请求会收到 401,随后携带认证头重新请求。
- 服务器验证通事后返回资源,否则返回 403。
通过上述代码,ESP32 可实现完备的 HTTP 根本认证流程,适用于 IoT 设备的安全通讯场景。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |