C++模拟Http/Https访问web站点

本文详细介绍了C++如何模拟Http和Https协议访问web站点,包括Http与Https的区别、web访问安全性、使用SOCKET发送HTTP请求的核心流程和代码,以及通过OpenSSL发送HTTPS请求的基本步骤和关键代码。通过对账号密码加密、HTTPS登录的安全性分析,展示了如何通过C++实现安全的网络通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

1.Http与Https的区别与联系

在OSI参考模型中Http与Https均属于应用层协议。Http即Hypertext Transfer Protocol,超文本传输协议;而Https为Secure Hypertext Transfer Protocol安全超文本传输协议,它是一个安全通信通道,基于HTTP开发,用于在客户端与服务器之间交换信息,它使用安全套接字层SSL进行信息交换,简单来说它就是HTTP的安全版。

Http默认使用80端口,Https使用443端口。

Http的数据在网络上是明文传输,而Https则是通过加密后的传输,因此它相比http会更加安全,但是由于需要额外加解密操作,因为Https的效率没有那么高。在登录Https站点和Http站点时,可以明显感觉到性能差异。

2.关于web访问的安全性

当前许多的web站点登录时都是采用普通的http进行传输,这种方式有着极大的安全隐患。当前web开发登录系统常用的有以下四种方式:

1) 账号和密码完全没有加密,明文传送。这种方式的安全级别是最低的,它无疑是将自己的账号和密码直接暴露给别人,通过抓包工具(例:WireShark)可以很容易的截获到账号和密码。

2) 密码采用MD5或其它加密方式进行加密,声称不可破解。其实,完全没有必要破解,只要截获加密后的密码串,就可以以你的身份访问服务器,这样也是可以通过认证授权的。这种方式在加密程度上有了一定程度的提高,但仍是不安全的。

3) 客户端在登录前去服务端拿一次密钥,通过该密钥进行加密,而服务器端的密钥是随机生成的,每次访问均会用不同的密钥。这种方式的安全性比较高。

4) 采用“安全性最高”的HTTPS方式传输,客户端与服务端会经过认证,且中间的传输数据全部进行加密。之所以在安全性最高上加引号,是因为它也不是绝对安全的,比如前段时间Openssl曝出安全漏洞,大名鼎鼎的“心脏出血”,黑客利用它的一个memcpy的bug,可以从溢出的内存中拿到64K的用户数据,导致用户信息泄露。但是这个安全性级别相对前面三个是最高的,当前服务端的证书一年收费大约3-5千,用这点钱换来相对安全,是很划算的事情了。

二、SOCKET发送HTTP请求

1.基本流程

无论是Http还是Https都是基于TCP进行传输的,因此使用SOCKET模拟HTTP访问web站点的方式,很简单,就是将头部数据拼接成数据包,发送给服务端,然后接收返回再解析就可以了。

其基本流程和编写普通SOCKET通信是一样的。Windows下的流程为:

a. WSAStartup对Winsock服务进行初始化

b. 建立socket套接字

c. connect连接服务端

d. send发送数据

e. recv接收数据

下面,以某站点的登录为例,利用Fiddler抓到的POST的头部信息如下:

                                             

这样,我们就可以构建这样的数据包发送出去,然后接收响应了,C++实现核心代码请见下部分。

2.核心代码

[cpp]  view plain   copy
 
  1. BOOL SocketClient::ConnectToServer(const CString strServerUrl, const int nPort)  
  2. {  
  3.     cstrServerUrl = strServerUrl;  
  4.     nServerPort = nPort;  
  5.     BOOL bRet = FALSE;  
  6.   
  7.     do   
  8.     {  
  9.         if (!InitializeContext())  
  10.         {  
  11.             break;  
  12.         }  
  13.   
  14.         if(!Connect())  
  15.         {  
  16.             break;  
  17.         }  
  18.   
  19.         bRet = TRUE;  
  20.     } while (FALSE);  
  21.     return bRet;  
  22. }  
  23.   
  24. BOOL SocketClient::LoginToServer(const CString strUsername, const CString strPasswd)  
  25. {  
  26.     cstrUserName = strUsername;  
  27.     cstrPassWord = strPasswd;  
  28.     BOOL bRet = FALSE;  
  29.   
  30.     do   
  31.     {  
  32.         if (!SendPostData())  
  33.         {  
  34.             break;  
  35.         }  
  36.   
  37.         bRet = TRUE;  
  38.     } while (FALSE);  
  39.   
  40.     return bRet;  
  41. }  
  42.   
  43. BOOL SocketClient::LogoutOfServer()  
  44. {  
  45.     return FALSE;  
  46. }  
  47.   
  48. BOOL SocketClient::InitializeContext()  
  49. {  
  50.     BOOL bRet = FALSE;  
  51.     wsaData = new WSADATA;  
  52.     WORD wVersion = MAKEWORD(2, 2);  
  53.   
  54.     do   
  55.     {  
  56.         if(0 != WSAStartup(wVersion, wsaData))  
  57.         {  
  58.             break;  
  59.         }  
  60.   
  61.         if(LOBYTE( wsaData->wVersion ) != 2 || HIBYTE( wsaData->wVersion ) != 2 )  
  62.         {  
  63.             WSACleanup();  
  64.             break;  
  65.         }  
  66.   
  67.         LPHOSTENT lpHostTent;  
  68.         lpHostTent = gethostbyname(cstrServerUrl);  
  69.         if (NULL == lpHostTent)  
  70.         {  
  71.             break;  
  72.         }  
  73.   
  74.         socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  75.         if (socketClient == INVALID_SOCKET)  
  76.         {  
  77.             WSACleanup();  
  78.             break;  
  79.         }  
  80.   
  81.         socketAddrClient = new SOCKADDR_IN;  
  82.         socketAddrClient->sin_family = AF_INET;  
  83.         socketAddrClient->sin_port = htons(nServerPort);  
  84.         socketAddrClient->sin_addr = *((LPIN_ADDR)*lpHostTent->h_addr_list);  
  85.         memset(socketAddrClient->sin_zero, 0, sizeof(socketAddrClient->sin_zero));  
  86.   
  87.         bRet = TRUE;  
  88.     } while (FALSE);  
  89.   
  90.     return bRet;  
  91. }  
  92.   
  93. BOOL SocketClient::Connect()  
  94. {  
  95.     BOOL bRet = FALSE;  
  96.   
  97.     do   
  98.     {  
  99.         if (SOCKET_ERROR == connect(socketClient, (LPSOCKADDR)socketAddrClient, sizeof(SOCKADDR_IN)))  
  100.         {  
  101.              int nErrorCode = WSAGetLastError();  
  102.             closesocket(socketClient);  
  103.             break;  
  104.         }  
  105.   
  106.         bRet = TRUE;  
  107.     } while (FALSE);  
  108.   
  109.     return bRet;  
  110. }  
  111.   
  112. BOOL SocketClient::SendPostData()  
  113. {  
  114.     CString cstrSendData;  
  115.     CString cstrSendParam = "redirect=&username="+cstrUserName+"&password="+cstrPassWord+"&auto_login=checked&submit=%E7%99%BB%E5%BD%95";  
  116.     BOOL bRet =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值