一、概述

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.核心代码

  1. BOOL SocketClient::ConnectToServer(const CString strServerUrl, const int nPort)
  2. {
  3. cstrServerUrl = strServerUrl;
  4. nServerPort = nPort;
  5. BOOL bRet = FALSE;
  6. do
  7. {
  8. if (!InitializeContext())
  9. {
  10. break;
  11. }
  12. if(!Connect())
  13. {
  14. break;
  15. }
  16. bRet = TRUE;
  17. } while (FALSE);
  18. return bRet;
  19. }
  20. BOOL SocketClient::LoginToServer(const CString strUsername, const CString strPasswd)
  21. {
  22. cstrUserName = strUsername;
  23. cstrPassWord = strPasswd;
  24. BOOL bRet = FALSE;
  25. do
  26. {
  27. if (!SendPostData())
  28. {
  29. break;
  30. }
  31. bRet = TRUE;
  32. } while (FALSE);
  33. return bRet;
  34. }
  35. BOOL SocketClient::LogoutOfServer()
  36. {
  37. return FALSE;
  38. }
  39. BOOL SocketClient::InitializeContext()
  40. {
  41. BOOL bRet = FALSE;
  42. wsaData = new WSADATA;
  43. WORD wVersion = MAKEWORD(2, 2);
  44. do
  45. {
  46. if(0 != WSAStartup(wVersion, wsaData))
  47. {
  48. break;
  49. }
  50. if(LOBYTE( wsaData->wVersion ) != 2 || HIBYTE( wsaData->wVersion ) != 2 )
  51. {
  52. WSACleanup();
  53. break;
  54. }
  55. LPHOSTENT lpHostTent;
  56. lpHostTent = gethostbyname(cstrServerUrl);
  57. if (NULL == lpHostTent)
  58. {
  59. break;
  60. }
  61. socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  62. if (socketClient == INVALID_SOCKET)
  63. {
  64. WSACleanup();
  65. break;
  66. }
  67. socketAddrClient = new SOCKADDR_IN;
  68. socketAddrClient->sin_family = AF_INET;
  69. socketAddrClient->sin_port = htons(nServerPort);
  70. socketAddrClient->sin_addr = *((LPIN_ADDR)*lpHostTent->h_addr_list);
  71. memset(socketAddrClient->sin_zero, 0, sizeof(socketAddrClient->sin_zero));
  72. bRet = TRUE;
  73. } while (FALSE);
  74. return bRet;
  75. }
  76. BOOL SocketClient::Connect()
  77. {
  78. BOOL bRet = FALSE;
  79. do
  80. {
  81. if (SOCKET_ERROR == connect(socketClient, (LPSOCKADDR)socketAddrClient, sizeof(SOCKADDR_IN)))
  82. {
  83. int nErrorCode = WSAGetLastError();
  84. closesocket(socketClient);
  85. break;
  86. }
  87. bRet = TRUE;
  88. } while (FALSE);
  89. return bRet;
  90. }
  91. BOOL SocketClient::SendPostData()
  92. {
  93. CString cstrSendData;
  94. CString cstrSendParam = "redirect=&username="+cstrUserName+"&password="+cstrPassWord+"&auto_login=checked&submit=%E7%99%BB%E5%BD%95";
  95. BOOL bRet = FALSE;
  96. CString cstrSendParamLen;
  97. cstrSendParamLen.Format("%d", cstrSendParam.GetLength());
  98. cstrSendData = "POST http://account.vsochina.com/user/login HTTP/1.1\r\n";
  99. cstrSendData += "Host: account.vsochina.com\r\n";
  100. cstrSendData += "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0\r\n";
  101. cstrSendData += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
  102. cstrSendData += "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
  103. cstrSendData += "Accept-Encoding: gzip, deflate\r\n";
  104. cstrSendData += "DNT: 1\r\n";
  105. cstrSendData += "Referer: http://account.vsochina.com/user/login\r\n";
  106. cstrSendData += "Connection: keep-alive\r\n";
  107. cstrSendData += "Content-Type: application/x-www-form-urlencoded\r\n";
  108. cstrSendData += "Content-Length: " + cstrSendParamLen +"\r\n";
  109. cstrSendData += "\r\n";
  110. cstrSendData += cstrSendParam;
  111. CString cstrRecvData;
  112. do
  113. {
  114. if (-1 == send(socketClient, cstrSendData.GetBuffer(), cstrSendData.GetLength(), 0))
  115. {
  116. break;
  117. }
  118. char recvData[1000] = {0};
  119. int nRecvLen;
  120. while((nRecvLen = recv(socketClient, recvData, sizeof(recvData), 0)) > 0)
  121. {
  122. cstrRecvData += recvData;
  123. }
  124. if (cstrRecvData.GetLength() == 0)
  125. {
  126. break;
  127. }
  128. ParseCookieFromRecvData(cstrRecvData);
  129. //!判断返回的COOKIE信息中,UID是否存在
  130. if (cstrCookieUid.IsEmpty())
  131. {
  132. break;
  133. }
  134. bRet = TRUE;
  135. } while (FALSE);
  136. return bRet;
  137. }
  138. void SocketClient::ParseCookieFromRecvData(const CString cstrRecvData)
  139. {
  140. list<CString> lstCookiesLine;        //!存放Set-Cookie的一行,例:Set-Cookie: vso_uname=houqd_1111;
  141. CString cstrFind = "Set-Cookie:";    //!查找标记
  142. CString cstrSeperator = "\r\n";      //!以"\r\n"分割号来分割字符串
  143. int nPos = 0;
  144. int nStart = cstrRecvData.Find(cstrSeperator);
  145. while(nStart != -1)
  146. {
  147. CString cstrSessionLine = cstrRecvData.Mid(nPos, nStart - nPos + 1);
  148. if (cstrSessionLine.Find(cstrFind) != -1)
  149. {
  150. CString cstrRealRecord = cstrSessionLine.Right(cstrSessionLine.GetLength() - cstrFind.GetLength() - 3);
  151. list<CString>::iterator it = find(lstCookiesLine.begin(), lstCookiesLine.end(), cstrRealRecord);
  152. if (it == lstCookiesLine.end())
  153. {
  154. lstCookiesLine.push_back(cstrRealRecord);
  155. }
  156. }
  157. nPos = nStart;
  158. nStart = cstrRecvData.Find(cstrSeperator, nPos + 2);
  159. }
  160. //!根据每行获取的cookie值,解析为key-value的形式
  161. vector<CString> vecCookieSet;
  162. for (list<CString>::iterator it = lstCookiesLine.begin(); it != lstCookiesLine.end(); it++)
  163. {
  164. CString cstrCookies = *it;
  165. CString cstrSeperator = ";";
  166. StaticUtility::StringSplit(cstrCookies, cstrSeperator, vecCookieSet);
  167. }
  168. vector<CString> vecTemp;
  169. for (vector<CString>::iterator it = vecCookieSet.begin(); it != vecCookieSet.end(); it++)
  170. {
  171. vecTemp.clear();
  172. CString cstrOneCookies = *it;
  173. CString cstrSeperator = "=";
  174. StaticUtility::StringSplit(cstrOneCookies, cstrSeperator, vecTemp);
  175. CString cstrKey = vecTemp[0];
  176. CString cstrVal = vecTemp[1];
  177. if(cstrKey.Compare("vso_uid") == 0)
  178. {
  179. cstrCookieUid = cstrVal;
  180. break;
  181. }
  182. }
  183. }

通过接收来的头部信息中,将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.核心代码

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

同理,判断登录也是在返回的信息中拿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

C++模拟Http/Https访问web站点的更多相关文章

  1. java 网络API访问 web 站点

    package cn.magicdu.think.socket; import java.io.BufferedReader; import java.io.InputStreamReader; im ...

  2. Nginx实战之让用户通过用户名密码认证访问web站点

    1.Nginx实战之让用户通过用户名密码认证访问web站点 [root@master ~]# vim /usr/local/nginx/conf/extra/www.conf server { lis ...

  3. 启动Nginx目录浏览功能及 让用户通过用户名密码认证访问web站点

    一.启动Nginx目录浏览功能  [root@abcdocker extra]# cat w.conf server { listen 80; server_name IP地址; location / ...

  4. apache配置,禁止ip访问web站点

    由于一台服务器上面部署了好几个应用,对应不同的域名,如果用户知道ip地址的话,直接用户ip地址访问,会显示第一个虚拟主机的页面(更改了虚拟主机的顺序,每次都是显示第一个).这样对用户造成不好的印象,所 ...

  5. Nginx之让用户通过用户名密码认证访问web站点

    有时我们会有这么一种需求,就是你的网站并不想提供一个公共的访问或者某些页面不希望公开,我们希望的是某些特定的客户端可以访问. 那么我们可以在访问时要求进行身份认证,就如给你自己的家门加一把锁,以拒绝那 ...

  6. 实战:Nginx如何让用户通过用户名和密码认证访问WEB站点

    有时我们会有这么一种需求,就是你的网站并不想提供一个公共的访问或者某些页面不希望公开,我们希望的是某些特定的客户端可以访问.那么我们可以在访问时要求进行身份认证,就如给你自己的家门加一把锁,以拒绝那些 ...

  7. 浏览器访问web站点原理图

    启动tomcat,在浏览器中输入http://localhost:8080/web_kevin/hello.html,发生的事情如下: 1.浏览器解析主机名,即解析localhost.浏览器首先会到本 ...

  8. web站点启用https (二)

    接上篇内容 二.实际配置案例 实验案例:为web站点启用https 实验环境:seven公司有一个web站点,域名为www.seven.com,启用的身份验证方式是基本验证方式.随着业务发展想成为网上 ...

  9. DNS服务——智能域名解析、镜像Web站点、直接域名泛域名

    智能域名解析 智能域名解析只有Linux DNS服务器才有.下面给出2种智能域名解析应用场景. 应用场景1 整个互联网由众多ISP组成,在中国就是联通.电信.移动等等 各家ISP内部网络四通八达,速度 ...

随机推荐

  1. Unity-Animator(Mecanim)深入系列总索引

    花了不少时间完成了这篇Unity Animator学习系列文章,其中大多数内容都来自个人实践,包括API部分很多都是亲测,期望和网上的诸多教程达到互补. 相关参考文档 Unity Animator官方 ...

  2. catch(…) vs catch(CException *)?

    转自:https://stackoverflow.com/questions/7412185/what-is-the-difference-between-catch-vs-catchcexcepti ...

  3. JS怎样捕获浏览器关闭时间弹出自定义对话框

    <script type="text/javascript">window.onbeforeunload = function (e) { e = e || windo ...

  4. 对于jsp中编码的理解

    1.会话都是从客户端也就是浏览器开始发起的,首先用户将地址输入到地址栏中, 当用户输入enter或者点击转到的按钮时,浏览器会根据当前页面的charset对地址栏中的地址进行encode一次,当服务器 ...

  5. CSS3 transform 引起z-index失效

    https://my.oschina.net/u/2941696/blog/1529373

  6. C语言分支结构之if else语句

    前面我们看到的代码都是顺序执行的,也就是先执行第一条语句,然后是第二条.第三条……一直到最后一条语句,这称为顺序结构. 但是对于很多情况,顺序结构的代码是远远不够的,比如一个程序限制了只能成年人使用, ...

  7. Sphinx以及coreseek的安装及使用 .No1

    检索结构php -> sphinx -> mysql非结构化数据又叫全文数据,非固定长度字段例如文章标题搜索这类适用sphinx 全文数据搜索:顺序扫描 : 如like查找索引扫描 : 把 ...

  8. iPad UIPopoverController弹出窗口的位置和坐标

    本文转载至:http://blog.csdn.net/chang6520/article/details/7921181 TodoViewController *contentViewControll ...

  9. 《C++ Primer Plus》14.2 私有继承 学习笔记

    C++(除了成员变量之外)还有另一种实现has-a关系的途径——私有继承.使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员.(如果使用保护继承,基类的公有成员和保护成员都将称为派生类的保 ...

  10. ubuntu安装TexturePicker

    TexturePacker网页:https://www.codeandweb.com/texturepackerTexturePacker下载页面:https://www.codeandweb.com ...