C:mbedtls库实现https双向认证连接示例_七侠镇莫尛貝大侠20241122

news2024/11/24 1:26:24

目的:使用C mbedtls库实现https(RSA证书)双向认证连接。

开发环境:windows 11, VS2022,mbedtls-3.6.2

私钥格式:p1/p8

#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"

#include <mbedtls/pk.h>
#include <mbedtls/pem.h>
#include <mbedtls/base64.h>


// 这个函数假设 SSL 握手已经成功完成
void print_server_san(mbedtls_ssl_context* ssl) {
    const mbedtls_x509_crt* cert = mbedtls_ssl_get_peer_cert(ssl);

    if (cert == NULL) {
        printf("No server certificate found.\n");
        return;
    }

    // 确保 `subject_alt_names` 是正确的类型
    const mbedtls_x509_sequence* san = &cert->subject_alt_names;
    while (san != NULL) {
        const mbedtls_asn1_buf* entry = &san->buf;
        unsigned char tag = entry->tag;

        // 检查是否为 IP 地址 (context-specific tag 7)
        if ((tag & MBEDTLS_ASN1_TAG_CLASS_MASK) == MBEDTLS_ASN1_CONTEXT_SPECIFIC &&
            (tag & MBEDTLS_ASN1_TAG_VALUE_MASK) == 7) {
            // IP 地址以二进制形式存储
            if (entry->len == 4) { // IPv4 地址
                printf("Server certificate SAN (IP): %u.%u.%u.%u\n",
                    entry->p[0], entry->p[1], entry->p[2], entry->p[3]);
            }
            else if (entry->len == 16) { // IPv6 地址
                printf("Server certificate SAN (IPv6): ");
                for (int i = 0; i < 16; i++) {
                    printf("%02x", entry->p[i]);
                    if (i % 2 == 1 && i < 15) {
                        printf(":");
                    }
                }
                printf("\n");
            }
        }

        san = san->next;
    }
}

void print_mbedtls_error(int ret) {
    char error_buf[100];
    mbedtls_strerror(ret, error_buf, sizeof(error_buf));
    fprintf(stderr, "Error: %s\n", error_buf);
}

int print_prikey_b64() {
    int ret;
    mbedtls_pk_context pkey;
    unsigned char* key_buffer = NULL;
    size_t key_len = 0;
    unsigned char* base64_buffer = NULL;
    size_t base64_len = 0;

    mbedtls_pk_init(&pkey);

    // 读取私钥文件
    ret = mbedtls_pk_parse_keyfile(&pkey, "res/yax/client_p8.key", NULL);
    if (ret != 0) {
        print_mbedtls_error(ret);
        goto cleanup;
    }

    // 获取私钥的 DER 格式所需的缓冲区长度
    key_len = mbedtls_pk_write_key_der(&pkey, NULL, 0);
    if (key_len <= 0) {
        print_mbedtls_error(key_len);
        goto cleanup;
    }

    printf("Key length required for DER format: %zu bytes\n", key_len);

    // 分配比所需长度更大的缓冲区来确保足够的空间
    key_buffer = (unsigned char*)malloc(key_len);
    if (!key_buffer) {
        fprintf(stderr, "Memory allocation failed for key_buffer with size %zu bytes\n", key_len);
        ret = -1;
        goto cleanup;
    }

    // 将私钥写入 DER 格式缓冲区,注意返回值是实际写入的字节数
    ret = mbedtls_pk_write_key_der(&pkey, key_buffer, key_len);
    if (ret < 0) {
        print_mbedtls_error(ret);
        goto cleanup;
    }

    // 计算 Base64 编码所需的缓冲区长度
    key_len = ret;  // 实际写入的字节数
    ret = mbedtls_base64_encode(NULL, 0, &base64_len, key_buffer + (key_len - ret), key_len);
    if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
        print_mbedtls_error(ret);
        goto cleanup;
    }

    // 分配缓冲区以存储 Base64 编码的数据
    base64_buffer = (unsigned char*)malloc(base64_len);
    if (!base64_buffer) {
        fprintf(stderr, "Memory allocation failed for base64_buffer\n");
        ret = -1;
        goto cleanup;
    }

    // 将 DER 格式的私钥转换为 Base64 编码
    ret = mbedtls_base64_encode(base64_buffer, base64_len, &base64_len, key_buffer + (key_len - ret), key_len);
    if (ret != 0) {
        print_mbedtls_error(ret);
        goto cleanup;
    }

    // 打印 Base64 编码的私钥
    printf("Base64 Encoded Private Key:\n%s\n", base64_buffer);

cleanup:
    mbedtls_pk_free(&pkey);
    if (key_buffer) {
        free(key_buffer);
    }
    if (base64_buffer) {
        free(base64_buffer);
    }
    //Key length required for DER format: 18446744073709551508 bytes
    //Memory allocation failed for key_buffer with size 18446744073709551508 bytes

    return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

int testHttps_p8() {
	printf("Https功能演示start:\n");

    int ret;
    mbedtls_net_context server_fd;
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_x509_crt cacert, clicert;
    mbedtls_pk_context pkey;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    const char* pers = "ssl_client1";

    // Initialize structures
    mbedtls_net_init(&server_fd);
    mbedtls_ssl_init(&ssl);
    mbedtls_ssl_config_init(&conf);
    mbedtls_x509_crt_init(&cacert);
    mbedtls_x509_crt_init(&clicert);
    mbedtls_pk_init(&pkey);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    mbedtls_entropy_init(&entropy);

    // 设置 RNG
    //ret = mbedtls_ctr_drbg_seed(&(hc->tls.ctr_drbg), mbedtls_entropy_func, &hc->tls.entropy, NULL, 0);
    //ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));
    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
    if (ret != 0)
    {
        return ret;
    }


    // Load certificates
    //mbedtls_x509_crt_parse_file(&clicert, "res/yax/client_https_with_chain.cer");  //含有客户端证书链
    mbedtls_x509_crt_parse_file(&clicert, "res/yax/client_https.cer");  //不含有证书链
    mbedtls_x509_crt_parse_file(&cacert, "res/yax/ca.cer");   //所有客户端和服务端所有证书链
    //mbedtls_x509_crt_parse_file(&cacert, "res/yax/root.cer");   //只提供一个服务器证书的root证书即可
    mbedtls_pk_parse_keyfile(&pkey, "res/yax/client_p8.key", NULL);    //p1或p8格式都可以,但必须包含头尾
    //mbedtls_pk_parse_keyfile(&pkey, "res/yax2/client_p8.key", NULL);

    mbedtls_ssl_conf_authmode(&ssl, MBEDTLS_SSL_VERIFY_REQUIRED);  //设置认证模式为 MBEDTLS_SSL_VERIFY_OPTIONAL 或 MBEDTLS_SSL_VERIFY_NONE 来调试是否由于证书验证失败引起的问题
                                                                  //但是,这仅用于调试,生产环境应该始终使用 MBEDTLS_SSL_VERIFY_REQUIRED。          
    // Seed the random number generator
    //mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));

    // Setup SSL configuration
    mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
    mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
    mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
    mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey);

   
    //mbedtls_ssl_set_hostname(&ssl, "4.3.2.1");   //服务器证书alt name dns = ip而不是域名时,不要调用这个
    //mbedtls_ssl_set_hostname(&ssl, NULL); //忽略主机名验证
    //mbedtls_ssl_conf_verify(&conf, 0, NULL);  // 设置自定义的证书验证回调


    // Connect to server
    mbedtls_net_connect(&server_fd, "4.3.2.1", "443", MBEDTLS_NET_PROTO_TCP);    //rsa https 测试服务端
    //mbedtls_net_connect(&server_fd, "4.3.2.1", "443", MBEDTLS_NET_PROTO_TCP); //RSA 国密sm2 双算法证书https 不适用。

    // Setup SSL context
    mbedtls_ssl_setup(&ssl, &conf);
    mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);

    // Perform SSL handshake
    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            char error_buf[100];
            mbedtls_strerror(ret, error_buf, 100);
            printf("Handshake failed: %s\n", error_buf);
            return 1;
        }
    }

    //打印服务器证书的san
    print_server_san(&ssl);
    //print_prikey_b64();

    // Communicate with the server
    // ...
    // Send data to server
    const char* msg = "Hello, Server!";
    mbedtls_ssl_write(&ssl, (const unsigned char*)msg, strlen(msg));

    // Read response
    char buffer[1024];
    do {
        memset(buffer, 0, sizeof(buffer));
        ret = mbedtls_ssl_read(&ssl, (unsigned char*)buffer, sizeof(buffer) - 1);

        if (ret > 0) {
            printf("Received %d bytes:\n%s\n", ret, buffer);
        }
        else if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            break;
        }
    } while (ret > 0);

    // Clean up
    mbedtls_ssl_close_notify(&ssl);
    mbedtls_net_free(&server_fd);
    mbedtls_x509_crt_free(&cacert);
    mbedtls_x509_crt_free(&clicert);
    mbedtls_pk_free(&pkey);
    mbedtls_ssl_free(&ssl);
    mbedtls_ssl_config_free(&conf);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);

    printf("Https功能演示End:\n");

	return EXIT_SUCCESS;
}

//在证书base64编码前后添加头尾
char* cert_add_ht(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        perror("无法打开文件");
        return NULL;
    }

    // 获取文件大小
    fseek(file, 0, SEEK_END);
    long filesize = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 分配内存读取文件内容
    char* base64_data = (char*)malloc(filesize + 1);
    if (!base64_data) {
        perror("内存分配失败");
        fclose(file);
        return NULL;
    }

    fread(base64_data, 1, filesize, file);
    base64_data[filesize] = '\0';  // 确保字符串结束
    fclose(file);

    const char* pem_header = "-----BEGIN CERTIFICATE-----\n";
    const char* pem_footer = "\n-----END CERTIFICATE-----\n";

    // 计算 PEM 格式总长度
    size_t pem_size = strlen(pem_header) + strlen(base64_data) + strlen(pem_footer) + 1;

    // 分配内存以存储 PEM 格式数据
    char* pem_cert = (char*)malloc(pem_size);
    if (!pem_cert) {
        perror("内存分配失败");
        free(base64_data);
        return NULL;
    }

    // 生成 PEM 格式数据
    snprintf(pem_cert, pem_size, "%s%s%s", pem_header, base64_data, pem_footer);

    free(base64_data);
    return pem_cert;
}

char* pkcs1_key_add_ht(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        perror("无法打开文件");
        return NULL;
    }

    // 获取文件大小
    fseek(file, 0, SEEK_END);
    long filesize = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 分配内存读取文件内容
    char* base64_data = (char*)malloc(filesize + 1);
    if (!base64_data) {
        perror("内存分配失败");
        fclose(file);
        return NULL;
    }

    fread(base64_data, 1, filesize, file);
    base64_data[filesize] = '\0';  // 确保字符串结束
    fclose(file);

    const char* pem_header = "-----BEGIN RSA PRIVATE KEY-----\n";
    const char* pem_footer = "\n-----END RSA PRIVATE KEY-----\n";

    // 计算 PEM 格式总长度
    size_t pem_size = strlen(pem_header) + strlen(base64_data) + strlen(pem_footer) + 1;

    // 分配内存以存储 PEM 格式数据
    char* pem_cert = (char*)malloc(pem_size);
    if (!pem_cert) {
        perror("内存分配失败");
        free(base64_data);
        return NULL;
    }

    // 生成 PEM 格式数据
    snprintf(pem_cert, pem_size, "%s%s%s", pem_header, base64_data, pem_footer);

    free(base64_data);
    return pem_cert;
}

int testHttps() {
    printf("Https功能演示start:\n");

    int ret;
    mbedtls_net_context server_fd;
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_x509_crt cacert, clicert;
    mbedtls_pk_context pkey;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    const char* pers = "ssl_client1";

    // Initialize structures
    mbedtls_net_init(&server_fd);
    mbedtls_ssl_init(&ssl);
    mbedtls_ssl_config_init(&conf);
    mbedtls_x509_crt_init(&cacert);
    mbedtls_x509_crt_init(&clicert);
    mbedtls_pk_init(&pkey);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    mbedtls_entropy_init(&entropy);

    // 设置 RNG
    //ret = mbedtls_ctr_drbg_seed(&(hc->tls.ctr_drbg), mbedtls_entropy_func, &hc->tls.entropy, NULL, 0);
    //ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));
    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
    if (ret != 0)
    {
        return ret;
    }


    const char* file_cert_b64 = "res/yax2/client_https_noht.cer";
    // 读取证书文件(不包含头尾)并转换为 PEM 格式(包含头尾)
    char* pem_cert = cert_add_ht(file_cert_b64);
    // 获取 PEM 证书的大小
    size_t pem_size = strlen(pem_cert) + 1;  // 包括终止符
    mbedtls_x509_crt_parse(&clicert, (const unsigned char*)pem_cert, pem_size);
    free(pem_cert);


    const char* file_key_p1_b64 = "res/yax2/client_p1_noht.key";
    // 读取证书文件(不包含头尾)并转换为 PEM 格式(包含头尾)
    char* pem_key = pkcs1_key_add_ht(file_key_p1_b64);
    // 获取 PEM 证书的大小
    size_t key_size = strlen(pem_key) + 1;  // 包括终止符
    mbedtls_pk_parse_key(&pkey, (const unsigned char*)pem_key, key_size,NULL,0);
    free(pem_key);


    mbedtls_x509_crt_parse_file(&cacert, "res/yax/ca.cer");   //所有客户端和服务端所有证书链


    // Load certificates
    //mbedtls_x509_crt_parse_file(&clicert, "res/yax/client_https_with_chain.cer");  //含有客户端证书链
    //mbedtls_x509_crt_parse_file(&clicert, "res/yax2/client_https_noht.cer");  //不含有证书链

    //mbedtls_x509_crt_parse_file(&cacert, "res/yax/ca.cer");   //所有客户端和服务端所有证书链
    //mbedtls_x509_crt_parse_file(&cacert, "res/yax/root.cer");   //只提供一个服务器证书的root证书即可
    //mbedtls_pk_parse_keyfile(&pkey, "res/yax2/client_p1.key", NULL);    //p1或p8格式都可以,但必须包含头尾
    //mbedtls_pk_parse_keyfile(&pkey, "res/yax2/client_p8.key", NULL);

    mbedtls_ssl_conf_authmode(&ssl, MBEDTLS_SSL_VERIFY_REQUIRED);  //设置认证模式为 MBEDTLS_SSL_VERIFY_OPTIONAL 或 MBEDTLS_SSL_VERIFY_NONE 来调试是否由于证书验证失败引起的问题
    //但是,这仅用于调试,生产环境应该始终使用 MBEDTLS_SSL_VERIFY_REQUIRED。          
// Seed the random number generator
//mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));

// Setup SSL configuration
    mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
    mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
    mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
    mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey);


    //mbedtls_ssl_set_hostname(&ssl, "1.2.3.4");   //服务器证书alt name dns = ip而不是域名时,不要调用这个
    //mbedtls_ssl_set_hostname(&ssl, NULL); //忽略主机名验证
    //mbedtls_ssl_conf_verify(&conf, 0, NULL);  // 设置自定义的证书验证回调


    // Connect to server
    mbedtls_net_connect(&server_fd, "2.3.4.5", "443", MBEDTLS_NET_PROTO_TCP);    //rsa https 测试服务端
    //mbedtls_net_connect(&server_fd, "2.3.4.5", "443", MBEDTLS_NET_PROTO_TCP); //RSA 国密sm2 双算法证书https 不适用。

    // Setup SSL context
    mbedtls_ssl_setup(&ssl, &conf);
    mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);

    // Perform SSL handshake
    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            char error_buf[100];
            mbedtls_strerror(ret, error_buf, 100);
            printf("Handshake failed: %s\n", error_buf);
            return 1;
        }
    }

    //打印服务器证书的san
    print_server_san(&ssl);
    //print_prikey_b64();

    // Communicate with the server
    // ...
    // Send data to server
    const char* msg = "Hello, Server!";
    mbedtls_ssl_write(&ssl, (const unsigned char*)msg, strlen(msg));

    // Read response
    char buffer[1024];
    do {
        memset(buffer, 0, sizeof(buffer));
        ret = mbedtls_ssl_read(&ssl, (unsigned char*)buffer, sizeof(buffer) - 1);

        if (ret > 0) {
            printf("Received %d bytes:\n%s\n", ret, buffer);
        }
        else if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            break;
        }
    } while (ret > 0);

    // Clean up
    mbedtls_ssl_close_notify(&ssl);
    mbedtls_net_free(&server_fd);
    mbedtls_x509_crt_free(&cacert);
    mbedtls_x509_crt_free(&clicert);
    mbedtls_pk_free(&pkey);
    mbedtls_ssl_free(&ssl);
    mbedtls_ssl_config_free(&conf);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);

    printf("Https功能演示End:\n");

    return EXIT_SUCCESS;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2246344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MIT 6.S081 | 操作系统 | Lab1: Xv6 and Unix utilities

Lab1: Xv6 and Unix utilities 文章目录 Lab1: Xv6 and Unix utilities实验任务1.启动XV6(easy)2.Sleep(easy)-练手的&#xff0c;就是熟悉一下怎么在xv6项目中加.c文件&#xff0c;生成可执行程序并进行测试的1.解析rm.c2.argc 如何被赋值3.Sleep代码4.makefile编辑5.通过make…

在SpringBoot项目中集成MongoDB

文章目录 1. 准备工作2. 在SpringBoot项目中集成MongoDB2.1 引入依赖2.2 编写配置文件2.3 实体类 3. 测试4. 文档操作4.1 插入操作4.1.1 单次插入4.1.2 批量插入 4.2 查询操作4.2.1 根据id查询4.2.2 根据特定条件查询4.2.3 正则查询4.2.4 查询所有文档4.2.5 排序后返回 4.3 删除…

美团-Leaf ID算法集成到SpringBoot项目

提前准备 下载源码 GitHub地址&#xff1a;https://github.com/Meituan-Dianping/Leaf 下载下来 然后 maven install 安装到本地仓库 再需要用到该ID算法的项目中引入 以下内容 <!-- 本地仓库中的Leaf --> <dependency><artifactId>leaf-boot-starte…

AI+若依框架项目

基础应用篇 1.若依搭建 技术选型 RuoYi-Vue版本&#xff0c;采用了前后端分离的单体架构设计&#xff1a; 软件环境&#xff1a;JDK、MySQL 、Redis 、Maven、Node 技术选型&#xff1a;Spring Boot、Spring Security、MyBatis、Jwt、V 官方推荐 课程版本 JDK > 1.8 …

RabbitMQ高可用延迟消息惰性队列

目录 生产者确认 消息持久化 消费者确认 TTL延迟队列 TTL延迟消息 惰性队列 生产者确认 生产者确认就是&#xff1a;发送消息的人&#xff0c;要确保消息发送给了消息队列&#xff0c;分别是确保到了交换机&#xff0c;确保到了消息队列这两步。 1、在发送消息服务的ap…

将django+vue项目发布部署到服务器

1.部署django后端服务 部署架构 1.1 下载依赖插件 pip3.8 freeze > requirements.txt1.2 安装依赖插件 pip3 install -r requirements.txt1.3 安装mysql数据库 apt install mysql-server初始化数据库 CREATE USER admin% IDENTIFIED WITH mysql_native_password BY 123…

论文阅读:SIMBA: single-cell embedding along with features

Chen, H., Ryu, J., Vinyard, M.E. et al. SIMBA: single-cell embedding along with features. Nat Methods 21, 1003–1013 (2024). 论文地址&#xff1a;https://doi.org/10.1038/s41592-023-01899-8 代码地址&#xff1a;https://github.com/pinellolab/simba. 摘要 大多…

商业物联网:拥抱生产力的未来

在现代商业格局中&#xff0c;数据占据至高无上的地位。物联网&#xff08;IoT&#xff09;站在这场数字革命的前沿&#xff0c;将以往模糊不清的不确定因素转变为可衡量、可付诸行动的深刻见解。物联网技术为日常物品配备传感器与连接功能&#xff0c;使其能够实时收集并传输数…

【FRP 内网穿透 从0到1 那些注意事项】

【摘要】 最近跟第三方团队调试问题&#xff0c;遇到一个比较烦的操作。就是&#xff0c;你必须要发个版到公网环境&#xff0c;他们才能链接到你的接口地址&#xff0c;才能进行调试。按理说&#xff0c;也没啥&#xff0c;就是费点时间。但是&#xff0c;在调试的时候&#…

最新Kali安装详细版教程(附安装包,傻瓜式安装教程)

本文主要详细介绍 kali 的安装过程&#xff0c;以及安装完成后的基本设置&#xff0c;比如安装增强工具&#xff0c;安装中文输入法以及更新升级等操作。 文章目录 实验环境准备工作步骤说明安装虚拟机安装 Kali安装增强工具安装中文输入法更新升级 实验环境 VMware &#x…

【山大909算法题】2014-T1

文章目录 1.原题2.算法思想3.关键代码4.完整代码5.运行结果 1.原题 为带表头的单链表类Chain编写一个成员函数Reverse&#xff0c;该函数对链表进行逆序操作&#xff08;将链表中的结点按与原序相反的顺序连接&#xff09;&#xff0c;要求逆序操作就地进行&#xff0c;不分配…

论文浅尝 | MindMap:知识图谱提示激发大型语言模型中的思维图(ACL2024)

笔记整理&#xff1a;和东顺&#xff0c;天津大学硕士&#xff0c;研究方向为软件缺陷分析 论文链接&#xff1a;https://aclanthology.org/2024.acl-long.558/ 发表会议&#xff1a;ACL 2024 1. 动机 虽然大语言模型&#xff08;LLMs&#xff09;已经在自然语言理解和生成任务…

Win11 22H2/23H2系统11月可选更新KB5046732发布!

系统之家11月22日报道&#xff0c;微软针对Win11 22H2/23H2版本推送了2024年11月最新可选更新补丁KB5046732&#xff0c;更新后&#xff0c;系统版本号升至22621.4541和22631.4541。本次更新后系统托盘能够显示缩短的日期和时间&#xff0c;文件资源管理器窗口很小时搜索框被切…

SpringSecurity创建一个简单的自定义表单的认证应用

1、SpringSecurity 自定义表单 在 Spring Security 中创建自定义表单认证应用是一个常见的需求&#xff0c;特别是在需要自定义登录页面、认证逻辑或添加额外的表单字段时。以下是一个详细的步骤指南&#xff0c;帮助你创建一个自定义表单认证应用。 2、基于 SpringSecurity 的…

Cloud Native 云原生后端的开发注意事项

在云原生后端开发里&#xff0c;数据管理和存储这块得好好弄。数据库选型得综合考虑&#xff0c;像关系型数据有复杂查询需求就选 MySQL、PostgreSQL&#xff0c;海量非结构化数据就可以考虑 MongoDB、Cassandra 这些。设计数据库得遵循规范化原则&#xff0c;像设计电商订单表…

通达OA前台submenu.php存在SQL注入漏洞(CVE-2024-10600)

通达OA前台submenu.php存在SQL注入漏洞(CVE-2024-10600) pda/appcenter/submenu.php 未包含inc/auth.inc.php且 $appid 参数未用’包裹导致前台SQL注入 影响范围 v2017-v11.6 fofa app"TDXK-通达OA" && icon_hash"-759108386"poc http://url…

TCP连接(三次握手)(四次挥手)

建立TCP连接&#xff08;三次握手&#xff09; 以下是简单阐述 在确定目标服务器 IP 地址后&#xff0c;则经历三次握手建立TCP 连接 三次握手 代表客户端和服务端 之间的传递信息有三次 A说&#xff1a;我想和你聊天 &#xff0c;你能听到我说话吗 B说&#xff1a;我可以听到…

【MySQL实战45讲笔记】基础篇——事务隔离

系列文章 基础篇——MySQL 的基础架构 基础篇——redo log 和 binlog 目录 系列文章1. 事务隔离1.1 隔离性与隔离级别1.2 如何实现事务隔离1.3 事务的启动方式1.4 思考&#xff1a; 使用什么方案来避免长事务 1. 事务隔离 简单来说&#xff0c;事务就是要保证一组数据库操作&…

upload-labs-master第12关详细教程

成功了别忘了回来留下你的评论哦&#xff0c;嘻嘻 目录 环境配置闯关 环境配置 需要的东西 phpstudy-2018 链接&#xff1a; https://pan.baidu.com/s/1D9l13XTQw7o6A8CSJ2ff9Q 提取码&#xff1a;0278 32位 vc9和11运行库 链接&#xff1a; https://pan.baidu.com/s/1pBV3W…

Mac 修改默认jdk版本

当前会话生效 这里演示将 Java 17 版本降低到 Java 8 查看已安装的 Java 版本&#xff1a; 在终端&#xff08;Terminal&#xff09;中运行以下命令&#xff0c;查看已安装的 Java 版本列表 /usr/libexec/java_home -V设置默认 Java 版本&#xff1a; 找到 Java 8 的安装路…