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

一、概述

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 = FALSE;  
  117.   
  118.     CString cstrSendParamLen;  
  119.     cstrSendParamLen.Format("%d", cstrSendParam.GetLength());  
  120.   
  121.     cstrSendData = "POST http://account.vsochina.com/user/login HTTP/1.1 ";  
  122.     cstrSendData += "Host: account.vsochina.com ";  
  123.     cstrSendData += "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0 ";  
  124.     cstrSendData += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 ";  
  125.     cstrSendData += "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 ";  
  126.     cstrSendData += "Accept-Encoding: gzip, deflate ";  
  127.     cstrSendData += "DNT: 1 ";  
  128.     cstrSendData += "Referer: http://account.vsochina.com/user/login ";  
  129.     cstrSendData += "Connection: keep-alive ";  
  130.     cstrSendData += "Content-Type: application/x-www-form-urlencoded ";  
  131.     cstrSendData += "Content-Length: " + cstrSendParamLen +" ";  
  132.     cstrSendData += " ";  
  133.     cstrSendData += cstrSendParam;  
  134.   
  135.     CString cstrRecvData;  
  136.     do   
  137.     {  
  138.         if (-1 == send(socketClient, cstrSendData.GetBuffer(), cstrSendData.GetLength(), 0))  
  139.         {  
  140.             break;  
  141.         }  
  142.   
  143.         char recvData[1000] = {0};  
  144.         int nRecvLen;  
  145.   
  146.         while((nRecvLen = recv(socketClient, recvData, sizeof(recvData), 0)) > 0)  
  147.         {  
  148.             cstrRecvData += recvData;  
  149.         }  
  150.   
  151.         if (cstrRecvData.GetLength() == 0)  
  152.         {  
  153.             break;  
  154.         }  
  155.   
  156.         ParseCookieFromRecvData(cstrRecvData);  
  157.   
  158.         //!判断返回的COOKIE信息中,UID是否存在  
  159.         if (cstrCookieUid.IsEmpty())  
  160.         {  
  161.             break;  
  162.         }  
  163.   
  164.         bRet = TRUE;  
  165.     } while (FALSE);  
  166.   
  167.   
  168.     return bRet;  
  169. }  
  170.   
  171. void SocketClient::ParseCookieFromRecvData(const CString cstrRecvData)  
  172. {  
  173.     list<CString> lstCookiesLine;        //!存放Set-Cookie的一行,例:Set-Cookie: vso_uname=houqd_1111;  
  174.     CString cstrFind = "Set-Cookie:";    //!查找标记  
  175.     CString cstrSeperator = " ";      //!以" "分割号来分割字符串  
  176.   
  177.     int nPos = 0;  
  178.     int nStart = cstrRecvData.Find(cstrSeperator);  
  179.   
  180.     while(nStart != -1)  
  181.     {  
  182.         CString cstrSessionLine = cstrRecvData.Mid(nPos, nStart - nPos + 1);  
  183.   
  184.         if (cstrSessionLine.Find(cstrFind) != -1)  
  185.         {  
  186.             CString cstrRealRecord = cstrSessionLine.Right(cstrSessionLine.GetLength() - cstrFind.GetLength() - 3);  
  187.             list<CString>::iterator it = find(lstCookiesLine.begin(), lstCookiesLine.end(), cstrRealRecord);  
  188.             if (it == lstCookiesLine.end())  
  189.             {  
  190.                 lstCookiesLine.push_back(cstrRealRecord);  
  191.             }  
  192.         }  
  193.   
  194.         nPos = nStart;  
  195.         nStart = cstrRecvData.Find(cstrSeperator, nPos + 2);  
  196.     }  
  197.   
  198.     //!根据每行获取的cookie值,解析为key-value的形式  
  199.     vector<CString> vecCookieSet;  
  200.     for (list<CString>::iterator it = lstCookiesLine.begin(); it != lstCookiesLine.end(); it++)  
  201.     {  
  202.         CString cstrCookies = *it;  
  203.         CString cstrSeperator = ";";  
  204.         StaticUtility::StringSplit(cstrCookies, cstrSeperator, vecCookieSet);  
  205.     }  
  206.   
  207.     vector<CString> vecTemp;  
  208.     for (vector<CString>::iterator it = vecCookieSet.begin(); it != vecCookieSet.end(); it++)  
  209.     {  
  210.         vecTemp.clear();  
  211.         CString cstrOneCookies = *it;  
  212.         CString cstrSeperator = "=";  
  213.   
  214.         StaticUtility::StringSplit(cstrOneCookies, cstrSeperator, vecTemp);  
  215.         CString cstrKey = vecTemp[0];  
  216.         CString cstrVal = vecTemp[1];  
  217.   
  218.         if(cstrKey.Compare("vso_uid") == 0)  
  219.         {  
  220.             cstrCookieUid = cstrVal;  
  221.             break;  
  222.         }  
  223.     }  
  224. }  

通过接收来的头部信息中,将cookie信息解析出来,就可以判断是否登录成功了。然后,如果有或许的操作,在请求中挂上这些cookie信息,就可以获取想要的数据,完成想要的操作了。

三、OpenSSL发送HTTPS请求

1.基本流程

HTTPS=HTTP + SSL,因此利用OpenSSL发送请求给HTTPS站点和第二章的SOCKET发送HTTP是非常相似的,只不过要在原生的套接字上套上SSL层,基本流程如下:

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

b. 建立socket套接字

c. connect连接服务端

d. 建立SSL上下文

e. 建立SSL

f. 将SSL与前面建立的socket套接字绑定

g. SSL_write()发送数据

h. SSL_read()接收数据

下面以小米官网站点的登录为例,来展示利用OpenSSL如何访问HTTPS站点,模拟登陆,核心代码,见下一章节。

2.核心代码

[cpp] view plain copy
 
  1. #pragma comment( lib, "libeay32.lib" )  
  2. #pragma comment( lib, "ssleay32.lib" )  
  3. HttpsClient::HttpsClient(void):  
  4.              wsaData(NULL),  
  5.              socketAddrClient(NULL),  
  6.              ssl(NULL),  
  7.              sslCtx(NULL),  
  8.              sslMethod(NULL),  
  9.              serverCertification(NULL)  
  10. {  
  11.     SSL_load_error_strings();  
  12.     SSLeay_add_ssl_algorithms();  
  13. }  
  14.   
  15.   
  16. HttpsClient::~HttpsClient(void)  
  17. {  
  18.     //!清理打开的句柄  
  19.     if (NULL != ssl)  
  20.     {  
  21.         SSL_shutdown(ssl);  
  22.         closesocket(socketClient);  
  23.         SSL_free(ssl);  
  24.         ssl = NULL;  
  25.     }  
  26.   
  27.     if (NULL != sslCtx)  
  28.     {  
  29.         SSL_CTX_free(sslCtx);  
  30.     }  
  31.   
  32.     WSACleanup();  
  33. }  
  34.   
  35. BOOL HttpsClient::ConnectToServer(const CString strServerUrl, const int nPort)  
  36. {  
  37.     cstrServerUrl = strServerUrl;  
  38.     nServerPort = nPort;  
  39.     BOOL bRet = FALSE;  
  40.   
  41.     do   
  42.     {  
  43.         if (!InitializeSocketContext())  
  44.         {  
  45.             break;  
  46.         }  
  47.   
  48.         if (!SocketConnect())  
  49.         {  
  50.             break;  
  51.         }  
  52.   
  53.         if (!InitializeSslContext())  
  54.         {  
  55.             break;  
  56.         }  
  57.   
  58.         if (!SslConnect())  
  59.         {  
  60.             break;  
  61.         }  
  62.   
  63.         bRet = TRUE;  
  64.     } while (FALSE);  
  65.     return bRet;  
  66. }  
  67.   
  68. BOOL HttpsClient::LoginToServer(const CString strUsername, const CString strPasswd)  
  69. {  
  70.     cstrUserName = strUsername;  
  71.     cstrPassWord = strPasswd;  
  72.     BOOL bRet = FALSE;  
  73.   
  74.     do   
  75.     {  
  76.         if (!SendLoginPostData())  
  77.         {  
  78.             break;  
  79.         }  
  80.   
  81.         CString cstrRecvData;  
  82.         RecvLoginPostData(cstrRecvData);  
  83.         if (cstrRecvData.GetLength() == 0)  
  84.         {  
  85.             break;  
  86.         }  
  87.   
  88.         ParseCookieFromRecvData(cstrRecvData);  
  89.   
  90.         if (cstrCookieUid.IsEmpty() || cstrCookieUid.Compare("EXPIRED") == 0)  
  91.         {  
  92.             break;  
  93.         }  
  94.   
  95.         bRet = TRUE;  
  96.     } while (FALSE);  
  97.     return bRet;  
  98. }  
  99.   
  100. BOOL HttpsClient::LogoutOfServer()  
  101. {  
  102.     return FALSE;  
  103. }  
  104.   
  105. BOOL HttpsClient::InitializeSocketContext()  
  106. {  
  107.     //!初始化winSocket环境  
  108.     BOOL bRet = FALSE;  
  109.     wsaData = new WSADATA;  
  110.     WORD wVersion = MAKEWORD(2, 2);  
  111.   
  112.     do   
  113.     {  
  114.         if(0 != WSAStartup(wVersion, wsaData))  
  115.         {  
  116.             break;  
  117.         }  
  118.   
  119.         if(LOBYTE( wsaData->wVersion ) != 2 || HIBYTE( wsaData->wVersion ) != 2 )  
  120.         {  
  121.             WSACleanup();  
  122.             break;  
  123.         }  
  124.   
  125.         LPHOSTENT lpHostTent;  
  126.         lpHostTent = gethostbyname(cstrServerUrl);  
  127.         if (NULL == lpHostTent)  
  128.         {  
  129.             break;  
  130.         }  
  131.   
  132.         socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  133.         if (socketClient == INVALID_SOCKET)  
  134.         {  
  135.             WSACleanup();  
  136.             break;  
  137.         }  
  138.   
  139.         socketAddrClient = new SOCKADDR_IN;  
  140.         socketAddrClient->sin_family = AF_INET;  
  141.         socketAddrClient->sin_port = htons(nServerPort);  
  142.         socketAddrClient->sin_addr = *((LPIN_ADDR)*lpHostTent->h_addr_list);  
  143.         memset(socketAddrClient->sin_zero, 0, sizeof(socketAddrClient->sin_zero));  
  144.   
  145.         bRet = TRUE;  
  146.     } while (FALSE);  
  147.   
  148.     return bRet;  
  149. }  
  150.   
  151. BOOL HttpsClient::SocketConnect()  
  152. {  
  153.     //!原生socket连接  
  154.     BOOL bRet = FALSE;  
  155.   
  156.     do   
  157.     {  
  158.         if (SOCKET_ERROR == connect(socketClient, (LPSOCKADDR)socketAddrClient, sizeof(SOCKADDR_IN)))  
  159.         {  
  160.             int nErrorCode = WSAGetLastError();  
  161.             closesocket(socketClient);  
  162.             break;  
  163.         }  
  164.   
  165.         bRet = TRUE;  
  166.     } while (FALSE);  
  167.   
  168.     return bRet;  
  169. }  
  170.   
  171. BOOL HttpsClient::InitializeSslContext()  
  172. {  
  173.     //!SSL通信初始化  
  174.     BOOL bRet = FALSE;  
  175.   
  176.     do   
  177.     {  
  178.         sslMethod = SSLv23_client_method();  
  179.         if(NULL == sslMethod)  
  180.         {  
  181.             break;  
  182.         }  
  183.   
  184.         sslCtx = SSL_CTX_new(sslMethod);  
  185.         if (NULL == sslCtx)  
  186.         {  
  187.             break;  
  188.         }  
  189.   
  190.         ssl = SSL_new(sslCtx);  
  191.         if (NULL == ssl)  
  192.         {  
  193.             break;  
  194.         }  
  195.   
  196.         bRet = TRUE;  
  197.     } while (FALSE);  
  198.   
  199.     return bRet;  
  200. }  
  201.   
  202. BOOL HttpsClient::SslConnect()  
  203. {  
  204.     //!SSL绑定原生socket,并连接服务器  
  205.     BOOL bRet = FALSE;  
  206.   
  207.     do   
  208.     {  
  209.         SSL_set_fd(ssl, socketClient);  
  210.   
  211.         int nRet = SSL_connect(ssl);  
  212.         if (-1 == nRet)  
  213.         {  
  214.             break;  
  215.         }  
  216.   
  217.         bRet = TRUE;  
  218.     } while (FALSE);  
  219.   
  220.     return bRet;  
  221. }  
  222.   
  223. BOOL HttpsClient::SslGetCipherAndCertification()  
  224. {  
  225.     BOOL bRet = FALSE;  
  226.   
  227.     do   
  228.     {  
  229.         cstrSslCipher = SSL_get_cipher(ssl);  
  230.         serverCertification = SSL_get_certificate(ssl);  
  231.   
  232.         if (NULL == serverCertification)  
  233.         {  
  234.             break;  
  235.         }  
  236.   
  237.         cstrSslSubject = X509_NAME_oneline(X509_get_subject_name(serverCertification), 0, 0);  
  238.         cstrSslIssuer = X509_NAME_oneline(X509_get_issuer_name(serverCertification), 0, 0);  
  239.   
  240.         X509_free(serverCertification);  
  241.   
  242.         bRet = TRUE;  
  243.     } while (FALSE);  
  244.   
  245.     return bRet;  
  246. }  
  247.   
  248. BOOL HttpsClient::SendLoginPostData()  
  249. {  
  250.     CString cstrSendData;  
  251.     //CString cstrSendParam = "redirect=&username="+cstrUserName+"&password="+cstrPassWord+"&auto_login=checked&submit=%E7%99%BB%E5%BD%95";  
  252.     CString cstrSendParam = "user="+cstrUserName+"&_json=true&pwd="+cstrPassWord+"&callback=http%3A%2F%2Forder.mi.com%2Flogin%2Fcallback%3Ffollowup%3Dhttp%253A%252F%252Fwww.mi.com%252F%26sign%3DNWU4MzRmNjBhZmU4MDRmNmZkYzVjMTZhMGVlMGFmMTllMGY0ZTNhZQ%2C%2C&sid=mi_eshop&qs=%253Fcallback%253Dhttp%25253A%25252F%25252Forder.mi.com%25252Flogin%25252Fcallback%25253Ffollowup%25253Dhttp%2525253A%2525252F%2525252Fwww.mi.com%2525252F%252526sign%25253DNWU4MzRmNjBhZmU4MDRmNmZkYzVjMTZhMGVlMGFmMTllMGY0ZTNhZQ%25252C%25252C%2526sid%253Dmi_eshop&hidden=&_sign=%2Bw73Dr7cAfRlMfOR6fW%2BF0QG4jE%3D&serviceParam=%7B%22checkSafePhone%22%3Afalse%7D&captCode=";  
  253.     BOOL bRet = FALSE;  
  254.   
  255.     CString cstrSendParamLen;  
  256.     cstrSendParamLen.Format("%d", cstrSendParam.GetLength());  
  257.   
  258.     cstrSendData = "POST https://account.xiaomi.com/pass/serviceLoginAuth2 HTTP/1.1 ";  
  259.     cstrSendData += "Host: account.xiaomi.com ";  
  260.     cstrSendData += "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0 ";  
  261.     cstrSendData += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 ";  
  262.     cstrSendData += "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 ";  
  263.     cstrSendData += "Accept-Encoding: gzip, deflate ";  
  264.     cstrSendData += "DNT: 1 ";  
  265.     cstrSendData += "Content-Type: application/x-www-form-urlencoded; charset=UTF-8 ";  
  266.     cstrSendData += "Referer: https://account.xiaomi.com/pass/serviceLogin?callback=http%3A%2F%2Forder.mi.com%2Flogin%2Fcallback%3Ffollowup%3Dhttp%253A%252F%252Fwww.mi.com%252Findex.html%26sign%3DNDRhYjQwYmNlZTg2ZGJhZjI0MTJjY2ZiMTNiZWExODMwYjkwNzg2ZQ%2C%2C&sid=mi_eshop ";  
  267.     cstrSendData += "Content-Length: " + cstrSendParamLen +" ";  
  268.     cstrSendData += "Connection: keep-alive ";     
  269.     cstrSendData += " ";  
  270.     cstrSendData += cstrSendParam;  
  271.   
  272.     CString cstrRecvData;  
  273.     do   
  274.     {  
  275.         int nRet = SSL_write(ssl, cstrSendData, cstrSendData.GetLength());  
  276.   
  277.         if(-1 == nRet)  
  278.         {  
  279.             break;  
  280.         }  
  281.           
  282.         bRet = TRUE;  
  283.     } while (FALSE);  
  284.   
  285.     return bRet;  
  286. }  
  287.   
  288. void HttpsClient::RecvLoginPostData(CString &cstrRecvData)  
  289. {  
  290.     BOOL bRet = FALSE;  
  291.   
  292.     do   
  293.     {  
  294.         TIMEVAL tval;  
  295.         tval.tv_sec = 20;  
  296.         tval.tv_usec = 0;  
  297.   
  298.         while(TRUE)  
  299.         {  
  300.             FD_SET fds;  
  301.             FD_ZERO(&fds);  
  302.             FD_SET(socketClient, &fds);  
  303.   
  304.             char recvData[1000] = {0};  
  305.             int nRecvLen;  
  306.   
  307.             //int nSelect = select(FD_SETSIZE, &fds, NULL, NULL, &tval);  
  308.             //if (1 != nSelect)  
  309.             //{  
  310.             //  break;  
  311.             //}  
  312.   
  313.             int nErr = SSL_read(ssl, recvData, sizeof(recvData));  
  314.             if (nErr <= 0)  
  315.             {  
  316.                 break;  
  317.             }  
  318.   
  319.             cstrRecvData += recvData;  
  320.         }  
  321.   
  322.         if (cstrRecvData.GetLength() == 0)  
  323.         {  
  324.             break;  
  325.         }  
  326.   
  327.         bRet = TRUE;  
  328.     } while (FALSE);  
  329. }  
  330.   
  331. void HttpsClient::ParseCookieFromRecvData(const CString cstrRecvData)  
  332. {  
  333.     list<CString> lstCookiesLine;        //!存放Set-Cookie的一行,例:Set-Cookie: vso_uname=houqd_1111;  
  334.     CString cstrFind = "Set-Cookie:";    //!查找标记  
  335.     CString cstrSeperator = " ";      //!以" "分割号来分割字符串  
  336.   
  337.     int nPos = 0;  
  338.     int nStart = cstrRecvData.Find(cstrSeperator);  
  339.   
  340.     while(nStart != -1)  
  341.     {  
  342.         CString cstrSessionLine = cstrRecvData.Mid(nPos, nStart - nPos + 1);  
  343.   
  344.         if (cstrSessionLine.Find(cstrFind) != -1)  
  345.         {  
  346.             CString cstrRealRecord = cstrSessionLine.Right(cstrSessionLine.GetLength() - cstrFind.GetLength() - 3);  
  347.             list<CString>::iterator it = find(lstCookiesLine.begin(), lstCookiesLine.end(), cstrRealRecord);  
  348.             if (it == lstCookiesLine.end())  
  349.             {  
  350.                 lstCookiesLine.push_back(cstrRealRecord);  
  351.             }  
  352.         }  
  353.   
  354.         nPos = nStart;  
  355.         nStart = cstrRecvData.Find(cstrSeperator, nPos + 2);  
  356.     }  
  357.   
  358.     //!根据每行获取的cookie值,解析为key-value的形式  
  359.     vector<CString> vecCookieSet;  
  360.     for (list<CString>::iterator it = lstCookiesLine.begin(); it != lstCookiesLine.end(); it++)  
  361.     {  
  362.         CString cstrCookies = *it;  
  363.         CString cstrSeperator = ";";  
  364.         StaticUtility::StringSplit(cstrCookies, cstrSeperator, vecCookieSet);  
  365.     }  
  366.   
  367.     vector<CString> vecTemp;  
  368.     for (vector<CString>::iterator it = vecCookieSet.begin(); it != vecCookieSet.end(); it++)  
  369.     {  
  370.         vecTemp.clear();  
  371.         CString cstrOneCookies = *it;  
  372.         CString cstrSeperator = "=";  
  373.   
  374.         StaticUtility::StringSplit(cstrOneCookies, cstrSeperator, vecTemp);  
  375.         CString cstrKey;  
  376.         CString cstrVal;  
  377.   
  378.         if (vecTemp.size() == 2)  
  379.         {  
  380.             cstrKey = vecTemp[0];  
  381.             cstrVal = vecTemp[1];  
  382.         }  
  383.   
  384.         if(cstrKey.Compare("userId") == 0)  
  385.         {  
  386.             cstrCookieUid = cstrVal;  
  387.             break;  
  388.         }  
  389.     }  
  390. }  

同理,判断登录也是在返回的信息中拿cookie信息,再进行下一步操作。

四、参考资料及代码下载链接

1) 使用OpenSSL API进行安全编程:http://www.ibm.com/developerworks/cn/linux/l-openssl.html

2) SSL建立过程分析:http://blog.chinaunix.net/uid-127037-id-2919489.html

3) Openssl使用:http://www.cppblog.com/woomsg/archive/2008/11/03/64508.html

4) 知乎OpenSSL:http://www.zhihu.com/topic/19584279

5) Retrieving a file via HTTP:http://www.codeproject.com/Articles/1876/Retrieving-a-file-via-HTTP

6) Step in a Typical HTTP Client Application:https://msdn.microsoft.com/en-us/library/8yh4zs9e%28v=VS.80%29.aspx

7) Make a POST HTTP request over a socket:http://paul.grozav.info/2013/05/16/c-make-a-post-http-request-over-a-socket/

8) C++ STL中哈希表hash_map介绍:blog.csdn.NET/ddkxddkx/article/details/6555754

9) 我的代码实现的下载链接为:http://download.csdn.net/detail/houqingdong2012/8540317

原文地址:https://www.cnblogs.com/simadi/p/7160572.html