• 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

  • 相关阅读:
    能帮你找到网页设计灵感的16个网站
    [转]自定义SqlMembershipProvider方法
    C#实现的根据年月日计算星期几的函数
    分享一个我自己写的支持多条件组合查询的分页存储过程
    史上最强的福克斯遥控钥匙失灵解决方案(zt)
    在页面实现数据还原,在终止数据库进程时,报不能用kill来终结自己的进程
    ViewState使用兼谈序列化
    jQuery 的上传图片预览插件
    Asp.net 备份、还原Ms SQLServer及压缩Access数据库
    aspnet_Membership表的意义
  • 原文地址:https://www.cnblogs.com/simadi/p/7160572.html
Copyright © 2020-2023  润新知