C++模拟Http/Https POST登录web站点(一)

2015-07-20 17:08:16 ? 作者: ? 浏览: 11

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

BOOL SocketClient::ConnectToServer(const CString strServerUrl, const int nPort)
{
	cstrServerUrl = strServerUrl;
	nServerPort = nPort;
	BOOL bRet = FALSE;

	do 
	{
		if (!InitializeContext())
		{
			break;
		}

		if(!Connect())
		{
			break;
		}

		bRet = TRUE;
	} while (FALSE);
	return bRet;
}

BOOL SocketClient::LoginToServer(const CString strUsername, const CString strPasswd)
{
	cstrUserName = strUsername;
	cstrPassWord = strPasswd;
	BOOL bRet = FALSE;

	do 
	{
		if (!SendPostData())
		{
			break;
		}

		bRet = TRUE;
	} while (FALSE);

	return bRet;
}

BOOL SocketClient::LogoutOfServer()
{
	return FALSE;
}

BOOL SocketClient::InitializeContext()
{
	BOOL bRet = FALSE;
	wsaData = new WSADATA;
	WORD wVersion = MAKEWORD(2, 2);

	do 
	{
		if(0 != WSAStartup(wVersion, wsaData))
		{
			break;
		}

		if(LOBYTE( wsaData->wVersion ) != 2 || HIBYTE( wsaData->wVersion ) != 2 )
		{
			WSACleanup();
			break;
		}

		LPHOSTENT lpHostTent;
		lpHostTent = gethostbyname(cstrServerUrl);
		if (NULL == lpHostTent)
		{
			break;
		}

		socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (socketClient == INVALID_SOCKET)
		{
			WSACleanup();
			break;
		}

		socketAddrClient = new SOCKADDR_IN;
		socketAddrClient->sin_family = AF_INET;
		socketAddrClient->sin_port = htons(nServerPort);
		socketAddrClient->sin_addr = *((LPIN_ADDR)*lpHostTent->h_addr_list);
		memset(socketAddrClient->sin_zero, 0, sizeof(socketAddrClient->sin_zero));

		bRet = TRUE;
	} while (FALSE);

	return bRet;
}

BOOL SocketClient::Connect()
{
	BOOL bRet = FALSE;

	do 
	{
		if (SOCKET_ERROR == connect(socketClient, (LPSOCKADDR)socketAddrClient, sizeof(SOCKADDR_IN)))
		{
			 int nErrorCode = WSAGetLastError();
			closesocket(socketClient);
			break;
		}


            
-->

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: