HTTP Digest Auth 及HTTP长连接 Libcurl c++实现

1、 HTTP Digest Auth

由于HTTP Auth的安全性差,所以出现了 HTTP Digest Auth。顾名思义,HTTP Digest Auth 就是对账密等信息生成摘要进行对比来验证的,具体的实现可以看下面的内容。

1.1、Digest Auth 的基本原理

首先,当客户端向服务器端请求资源时,服务器端会发送状态为 401的响应码,同时会返回一串随机字符(而这个随机数只有每次"401"状态码响应后才会更新);

客户端获取到 Response之后,会取出其中的随机字串,然后和账密信息一块进行 MD5 加密;

客户端将加密信息和请求一同发送到服务器端;

服务器收到请求后,从 Request 中取出用户名,然后从数据库查找到该用户的密码;

服务器将获取到信息以相同的方式进行 MD5加密,如果和客户端发送来的相同,则验证通过,否则验证失败。

1.2、Digest Auth 认证过程

使用postman+Wireshark做测试,首先配置postman Digest Auth 认证:
在这里插入图片描述
接下来,点击发送我们看到Wireshark内的内容:
(由于保密原因,接口不能展示,下面的接口数据也是参考别人博客拿的数据,见谅!)在这里插入图片描述
发送不看,正常请求。服务端收到请求,返回401,以及随机字串,内容如下

HTTP /1.1 401 Unauthorized
WWW-Authenticate:Digest realm= ”pets”,qop=auth,auth-int,nonce=66C4Edqwdqr1231414”,opaque="5dsa9c403ebaf9dadqe41"

在服务端返回的 Header中有一个字段 www-Authenticate就是告诉客户端验证方式,其中的几个字段的含义:

节点名称解析
Digest指明是 Digest Auth的认证方式
realm请求域
qop校验的方式,质量保护,值为auth或auth-int或[token],auth-int包含对实体主体做完整性校验
nonce服务端返回的随机数,生成的 Digest加密信息中就包含该信息
opaque这是一个不透明的数据字符串,在盘问中发送给客户端,客户端会将这个数据字符串再发送回服务端器。如果需要在服务端和客户端之间维护一些状态,用nonce来维护状态数据是一种更容易也更安全的实现方式
stale当密码摘要使用的随机数过期时,服务器可以返回一个附带有新随机数的401响应,并指定stale=true,表示服务器在告知客户端用新的随机数来重试,而不再要求用户重新输入用户名和密码了
algorithm摘要算法,值为MD5或MD5-sess或[token],默认为MD5

客户端收到401的响应后,会提示用户输入帐密,客户端会对账密、nonce、请求方法、请求资源的 URL 进行 MD5 运算,然后将运算生成的信息和请求头其他信息一同发送给服务器端,请求 Request 如下:

GET/pets/dog.png HTTP/1.1
 Authorization: Digest
 username="test", 
 realm="pets", 
 nonce="dcddsadqw0f600bfb0c0",  uri="/xxxx/pets/dog.png",  
 qop=auth,  nc=00000001,  cnonce="0a4f113b",
 response="6629fdsadqwdsadqwdwqdwq",  
 opaque="5ccc069c403ebaf9f0171e9517f40e41"

服务端获取到请求之后就会解析,请求头字段的具体含义如下:

节点名称解析
username用户名
realm请求域
cnonce客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
ncnonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量。例如,在响应的第一个请求中,客户端将发送“nc=00000001”。这个指示值的目的是让服务器保持这个计数器的一个副本,以便检测重复的请求
response这是由用户代理软件计算出的一个字符串,以证明用户知道口令

服务器收到请求后会获取到 username ,然后找到对应的密码,也按照相同的方式生成摘要,与 client 发送的对比,如果相同则认证通过,之后服务端会向客户端发送包含如下的Response Header:

HTTP 1.1/200 OK
Authorization-Info: nextonce="csadadqwdq0fdqwdq",qop="auth",rspauth="fsdsadqwfwqgq",conce="0a4f113b"

上面就是说明认证成功,其中的几个字段的含义如下:

节点名称解析
Authorization-Info用于返回一些与授权会话相关的附加信息
nextnonce下一个服务端随机数,使客户端可以预先发送正确的摘要
rspauth响应摘要,用于客户端对服务端进行认证

参考博客链接

1.3、C++ libcurl实现Digest Auth 认证

	code = curl_easy_setopt(conn,CURLOPT_USERPWD, "admin:admin123");  
	code = curl_easy_setopt(conn,CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);  

就这两句。

2、HTTP 长连接

2.1 目的

HTTP服务认证连接后,对方要求长连接等待他们下发数据。

2.2 C++ libcurl实现

其实也简单:
1、设置长连接参数

/* 设置TCP连接为长连接 */
curl_easy_setopt(conn, CURLOPT_TCP_KEEPALIVE, 1L);
/* 设置长连接的休眠时间*/
curl_easy_setopt(conn, CURLOPT_TCP_KEEPIDLE, 120L);
/* 设置心跳发送时间,心使得socket长时间保活,小于KEEPIDLE时间 */
curl_easy_setopt(conn, CURLOPT_TCP_KEEPINTVL, 20L);

2、注销关闭连接(在程序关闭记得释放)

//curl_easy_cleanup(conn);  	
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要用C语言实现HTTP Digest登录,需要进行以下步骤: 1. 创建HTTP Digest请求头部。HTTP Digest登录需要在请求头部添加Authorization字段,其中包含了用户名、密码、请求方法、URI等信息的摘要。要创建这个请求头部,可以使用OpenSSL库中的md5函数来计算摘要。 2. 发送HTTP请求。可以使用C语言的socket库来建立连接并发送HTTP请求。在发送请求时,需要将创建的请求头部添加到HTTP请求的头部中。 3. 接收HTTP响应。使用socket库从务器接收HTTP响应,然后对响应进行解析,判断是否登录成功。 以下是一个简单的C语言HTTP Digest登录的代码示例: ```c #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <openssl/md5.h> // HTTP请求头部中的Authorization字段 void make_http_digest_auth(char *username, char *password, char *method, char *uri, char *realm, char *nonce, char *cnonce, char *qop, char *nc, char *digest) { char ha1[MD5_DIGEST_LENGTH]; char ha2[MD5_DIGEST_LENGTH]; char response[MD5_DIGEST_LENGTH]; // 计算HA1 char ha1_str[1024]; snprintf(ha1_str, sizeof(ha1_str), "%s:%s:%s", username, realm, password); MD5((unsigned char*)ha1_str, strlen(ha1_str), (unsigned char*)ha1); // 计算HA2 char ha2_str[1024]; snprintf(ha2_str, sizeof(ha2_str), "%s:%s", method, uri); MD5((unsigned char*)ha2_str, strlen(ha2_str), (unsigned char*)ha2); // 计算response char response_str[1024]; snprintf(response_str, sizeof(response_str), "%s:%s:%s:%s:%s:%s", ha1, nonce, nc, cnonce, qop, ha2); MD5((unsigned char*)response_str, strlen(response_str), (unsigned char*)response); // 组装Authorization字段 snprintf(digest, 1024, "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\", cnonce=\"%s\", nc=%s, qop=%s", username, realm, nonce, uri, response, cnonce, nc, qop); } int main() { int sockfd; struct sockaddr_in servaddr; // 创建socket sockfd = socket(AF_INET, SOCK_STREAM, 0); // 设置务器地址 memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(80); inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); // 连接务器 connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); // 创建HTTP Digest请求头部 char digest[1024]; char *username = "user"; char *password = "password"; char *method = "GET"; char *uri = "/"; char *realm = "test"; char *nonce = "123456"; char *cnonce = "654321"; char *qop = "auth"; char *nc = "00000001"; make_http_digest_auth(username, password, method, uri, realm, nonce, cnonce, qop, nc, digest); // 发送HTTP请求 char request[1024]; snprintf(request, 1024, "GET / HTTP/1.1\r\nHost: localhost\r\nAuthorization: %s\r\n\r\n", digest); write(sockfd, request, strlen(request)); // 接收HTTP响应 char response[1024]; int len = read(sockfd, response, 1024); response[len] = '\0'; printf("%s", response); // 关闭socket close(sockfd); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值