其他分享
首页 > 其他分享> > SSL / TLS协议解析!SNI 识别

SSL / TLS协议解析!SNI 识别

作者:互联网

自Web诞生以来,我们所接触的互联网时代,都有可能存在信息的截断,而SSL协议及其后代TLS提供了加密和安全性,使现代互联网安全成为可能。

这些协议已有将近二十多年的历史,其特点是不断更新,旨在与日趋复杂的攻击者保持同步。

什么是SSL!什么是TLS!

SSL代表安全套接字层,该协议是由Netscape于1990年代中期开发的,Netscape是当时最受欢迎的Web浏览器。SSL 1.0从未向公众发布,而SSL 2.0具有严重的缺陷。1996年发布的SSL 3.0进行了彻底的改进,为后续工作奠定了基础。

而TLS与SSL,当一版本于1999年发布时,它由Internet工程任务组(IETF)进行了标准化,并被赋予了一个新名称:传输层安全性( TLS)。

正如TLS规范指出的那样,“此协议与SSL 3.0的区别并不明显。” 因此,TLS和SSL并不是真正的问题。而是,这两者形成了一系列不断更新的协议,并且经常被合并为SSL / TLS。

这样我们就明白了TLS(传输层安全性)只是SSL的更新,更安全的版本。目前已经升级到TLS1.3版本,TLS协议对所有类型的Internet通信进行加密。最常见的是网络流量;

简而言之,它们是保持Internet连接安全并保护两个系统之间发送的任何敏感数据的标准技术,可防止犯罪分子读取和修改所传输的任何信息,包括潜在的个人详细信息。

SSL/TLS握手过程

握手过程非常复杂,并且协议允许有多种变体。以下步骤提供了一个大致的概述。

第一

在这里插入图片描述

在这里插入图片描述
第二

在这里插入图片描述

第三

在这里插入图片描述

TLS1.2和TLS1.3比较

TLS1.2它也允许使用较旧的加密技术,以支持较旧的计算机。不幸的是,这使它容易受到攻击,在中间人攻击中,黑客拦截了通信中的数据包,并在读取或更改数据包后将其发送出去。

幸运的是,TLS1.3通过抛弃对旧加密系统的支持,填补了许多此类漏洞。使通信中的数据包受到了保护。

什么是SNI

Server Name Indication (SNI) 是TLS协议(以前称为SSL协议)的扩展,该协议在HTTPS中使用。它包含在TLS/SSL握手流程中,以确保客户端设备能够看到他们尝试访问的网站的正确SSL证书。该扩展使得可以在TLS握手期间指定网站的主机名或域名 ,而不是在握手之后打开HTTP连接时指定。

SNI的技术原理

SNI通过让客户端发送虚拟域的名称作为TLS协商的ClientHello消息的一部分来解决此问题。这使服务器可以及早选择正确的虚拟域,并向浏览器提供包含正确名称的证书。

在这里插入图片描述
这样要说一下,服务器名称指示(SNI)有效负载未加密,因此客户端尝试连接的服务器的主机名对于被动的窃听者是可见的。

TLS的SNI扩展有什么作用?

下面,我们就开始对TLS协议的SNI进行解析。

TLS协议的SNI识别

这里给出的只是一部分代码实现。

static bool is_sslv3_or_tls(u_char *tls_data,int PayloadLen,int offset)
{
    uint8_t   content_type = 0;
    uint16_t  protocol_version = 0, record_length = 0;
	SslSession        *session;


    if (PayloadLen < 5) {
        return false;
    }

    content_type = tls_data[offset];
	offset += 1;
    protocol_version = ntohs(*(uint16_t*)(tls_data + offset));
	offset += 2;
	record_length = ntohs(*(uint16_t*)(tls_data + offset));
	//printf("record_length: %d\n",record_length);
    /* These are the common types. */
    if (content_type != SSL_ID_HANDSHAKE) {
        return false;
    }


    if (protocol_version != SSLV3_VERSION &&
        protocol_version != TLSV1_VERSION &&
        protocol_version != TLSV1DOT1_VERSION &&
        protocol_version != TLSV1DOT2_VERSION) {
        return false;
    }

    if (record_length == 0 || record_length >= TLS_MAX_RECORD_LENGTH + 2048) {
        return false;
    }

    return true;
}


static void dissect_ssl2_hnd_client_hello(u_char *tls_data,int PayloadLen, int offset)
{
	uint32_t offset_end = 0;
	uint16_t ext_type = 0;
    uint32_t ext_len = 0;
	uint32_t next_offset = 0;
	int    msg_length = 0;
	int    remaining_length = 0;
	uint32_t server_name_length = 0;
	uint16_t length = 0;
	uint16_t version = 0;
	int session_id_len = 0;
	uint32_t extensions_length = 0;
	uint8_t random[32];	
	char s_name[256] = {0};
	int i = 0;	
	uint32_t     cipher_suite_length = 0;
	offset += 3;/*Length*/
	
	version = ntohs(*(uint16_t*)(tls_data + offset));
	printf("Version: 0x%.2X\n",version);
	offset += 2; /*Version*/
	
	if (offset > PayloadLen)
		return;
	memcpy(random,tls_data + offset,32);
	
	for (i = 0; i < 32;i++)
		printf("%x",random[i]);
	printf("\n");
	
	offset += 32; /*random*/
	
	session_id_len = tls_data[offset];
	printf("session_id_len: %d\n",session_id_len);
	offset += 1; /*Session ID Length*/
	if (session_id_len > PayloadLen)
		return;
	uint8_t session_id[session_id_len];
	memcpy(session_id,tls_data + offset,session_id_len);

	for (i = 0; i < session_id_len;i++)
		printf("%x",session_id[i]);
	printf("\n");
	
	offset += session_id_len; /*Session ID */
	
	cipher_suite_length = ntohs(*(uint16_t*)(tls_data + offset));	
	printf("cipher_suite_length: %d\n",cipher_suite_length);
	
	offset += 2;/*cipher_suite_length*/
	
	offset += cipher_suite_length; /*Session ID */
	
	offset += 1;/*compression_method length*/
	
	offset += 1;/*compression_method */
	extensions_length = ntohs(*(uint16_t*)(tls_data + offset));
	printf("Extensions Length: %d\n",extensions_length);
	printf("Extensions Length: 0x%.2X\n",extensions_length);
	offset += 2;
	//offset_end = PayloadLen - offset;
	//printf("offset_end: %d\n",offset_end);
	msg_length = PayloadLen;
	while (offset < msg_length)
	{
        /* Get the type and length */
        remaining_length = msg_length - offset;
        if (remaining_length < 3) {
			printf("Not enough data left for IE and length, %i bytes\n", remaining_length);
            return;
        }
		
		ext_type = ntohs(*(uint16_t*)(tls_data + offset));
		//printf("ext_type: 0x%.2X\n",ext_type);
		offset += 2;
        ext_len  = ntohs(*(uint16_t*)(tls_data + offset));
		//printf("ext_len: %d\n",ext_len);
		offset += 2;
		
		switch (ext_type) 
		{
			case SSL_HND_HELLO_EXT_SERVER_NAME:
				 printf("==========SERVER_NAME======\n");
				 
				 offset += 2; //Server Name list length
				 
				 offset += 1; //Server Name Type
				 server_name_length = ntohs(*(uint16_t*)(tls_data + offset));
				 printf("server_name_length: %d\n",server_name_length);
				 offset += 2; //Server Name length

				 memset(s_name,0,256);
				 memcpy(s_name,tls_data + offset,server_name_length);
				 printf("Server Name: %s\n",s_name);
				 
				 
			break;
			default:
			break;
        }

	   offset += ext_len;

	}
	
	
}


void dissect_tls(u_char *tls_data,int PayloadLen,int offset)
{
	SslSession   *session;
	uint16_t version = 0;
	uint16_t length = 0;
	uint8_t  msg_type = 0;
	printf("0x%.2X,0x%.2X,0x%.2X 0x%.2X,0x%.2X,0x%.2X \n",tls_data[offset],tls_data[offset+1],tls_data[offset+2],tls_data[offset+3],tls_data[offset+4],tls_data[offset+5]);
	
	if (!is_sslv3_or_tls(tls_data,PayloadLen,offset)) {
        return;
    }
	
	printf("====tls=========\n");
	offset += 1; /*Content Type*/
	version = ntohs(*(uint16_t*)(tls_data + offset));	
	printf("Version: 0x%.2X\n",version);	
	offset += 2; /*Version*/
	
	length = ntohs(*(uint16_t*)(tls_data + offset));
	printf("Length: %d\n",length);
	offset += 2; /*length*/
	/* fetch the msg_type */
	msg_type = tls_data[offset]; 
	offset += 1; /*handshake type*/
	printf("handshake type: 0x%.2X\n",msg_type);	
	switch (version) 
	{
		case SSLV3_VERSION:
		case TLSV1_VERSION:
		case TLSV1DOT1_VERSION:
		case TLSV1DOT2_VERSION:
			if (PayloadLen < 5) 
			{
				break;
			}
			ssl_looks_like_valid_v2_handshake(tls_data,PayloadLen,msg_type,offset);
		break;
		default:
		if (PayloadLen < 5) 
		{
			break;
		}
	}

}

编译运行:

在这里插入图片描述

在客户端到服务端方向的 ClientHello 包中,提取 SNI 扩展字段中的 SNI_NAME 字段,通过数据包偏移量进行逐步匹配得到 SNI_NAME。对 SNI_NAME 进行规则匹配。

总结

这篇文章只是对SSL/TLS做一些简单的介绍,想通过更多认识,可以阅读官方的RFC文档,对于SNI(Server Name Indication)是 TLS 的扩展,它主要是用来解决一个服务器拥有多个域名的情况。通过 SNI,拥有多虚拟机主机和多域名的服务器就可以正常建立 TLS 连接了。

欢迎关注微信公众号【程序猿编码】,欢迎添加本人微信号(17865354792),交个朋友,咱们一起学习进步!

标签:TLS,tls,printf,SNI,SSL,length,offset,data
来源: https://blog.csdn.net/chen1415886044/article/details/116330304