HTTPS
HTTP Secure
- HTTP layer
- SSL(安全套接字层)/TLS(安全传输层协议) encryption layer on top of it TLS前身是SSL, SSL3.0和TLS 1.0存在安全漏洞,现已很少使用
TLS/SSL中使用了非对称加密,对称加密以及HASH算法
- 非对称加密算法用于在握手过程中加密生成的密码
- 对称加密算法用于对真正传输的数据进行加密 由于浏览器生成的密码是整个数据加密的关键,因此在传输的时候使用了非对称加密算法对其加密。
- HASH算法用于验证数据的完整性
TLS Glossary
- Session key This is the end result of a handshake. It’s a key for a symmetric cipher, and allows the client and server to encrypt messages to each other.
- Client random This is a sequence of 32 bytes created by the client. It’s unique for each connection, and is supposed to contain a four-byte timestamp followed by 28 random bytes. Recently, Google Chrome switched to using 32 bytes of random in order to prevent client fingerprinting. These random values are often called a nonce.
- Server random A server random is the same as the client random except generated by the server.
- Pre-master secret This is a 48-byte blob of data. It can be combined with both the client random and the server random to create the session key using a “pseudorandom function” (PRF).
- Cipher suite
This is a unique identifier for combining algorithms making up a TLS connection. It defines one algorithm for each of the following:
- key establishment (typically a Diffie-Hellman variant or RSA)
- authentication (the certificate type)
- confidentiality (a symmetric cipher)
- integrity (a hash function)
For example “AES128-SHA” defines a session that uses:
- RSA for key establishment (implied)
- RSA for authentication (implied)
- 128-bit Advanced Encryption Standard in Cipher Block Chaining (CBC) mode for confidentiality
- 160-bit Secure Hashing Algorithm (SHA) for integrity
Process
握手过程的简单描述如下:
- 浏览器将自己支持的一套加密规则发送给网站。
- 网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
- 获得网站证书之后浏览器要做以下工作: a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等) b) 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码(Pre-master secret),并用证书中提供的公钥加密。 c) 使用约定好的HASH计算握手消息,并使用生成的随机数对消息进行加密。客户端发送报文,并提示服务器,此后的报文通信会采用Pre-master secret密钥加密。最后将之前生成的所有信息以发送Finished报文发送给网站。
- 网站接收浏览器发来的数据之后要做以下的操作: a) 使用自己的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致。 b) 使用密码加密一段握手消息,发送给浏览器。
- 浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
/**********************************************************************
* HTTP权威指南
* https_client.c --- very simple HTTPS client with no error checking
* usage: https_client servername
**********************************************************************/
#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
void main(int argc, char **argv)
{
SSL *ssl;
SSL_CTX *ctx;
SSL_METHOD *client_method;
X509 *server_cert;
int sd,err;
char *str,*hostname,outbuf[4096],inbuf[4096],host_header[512];
struct hostent *host_entry;
struct sockaddr_in server_socket_address;
struct in_addr ip;
/*========================================*/
/* (1) initialize SSL library */
/*========================================*/
SSLeay_add_ssl_algorithms( );
client_method = SSLv2_client_method( );
SSL_load_error_strings( );
ctx = SSL_CTX_new(client_method);
printf("(1) SSL context initialized\n\n");
/*=============================================*/
/* (2) convert server hostname into IP address */
/*=============================================*/
hostname = argv[1];
host_entry = gethostbyname(hostname);
bcopy(host_entry->h_addr, &(ip.s_addr), host_entry->h_length);
printf("(2) '%s' has IP address '%s'\n\n", hostname, inet_ntoa(ip));
/*=================================================*/
/* (3) open a TCP connection to port 443 on server */
/*=================================================*/
sd = socket (AF_INET, SOCK_STREAM, 0);
memset(&server_socket_address, '\0', sizeof(server_socket_address));
server_socket_address.sin_family = AF_INET;
server_socket_address.sin_port = htons(443);
memcpy(&(server_socket_address.sin_addr.s_addr),
host_entry->h_addr, host_entry->h_length);
err = connect(sd, (struct sockaddr*) &server_socket_address,
sizeof(server_socket_address));
if (err < 0) { perror("can't connect to server port"); exit(1); }
printf("(3) TCP connection open to host '%s', port %d\n\n",
hostname, server_socket_address.sin_port);
/*========================================================*/
/* (4) initiate the SSL handshake over the TCP connection */
/*========================================================*/
ssl = SSL_new(ctx); /* create SSL stack endpoint */
SSL_set_fd(ssl, sd); /* attach SSL stack to socket */
err = SSL_connect(ssl); /* initiate SSL handshake */
printf("(4) SSL endpoint created & handshake completed\n\n");
/*============================================*/
/* (5) print out the negotiated cipher chosen */
/*============================================*/
printf("(5) SSL connected with cipher: %s\n\n", SSL_get_cipher(ssl));
/*========================================*/
/* (6) print out the server's certificate */
/*========================================*/
server_cert = SSL_get_peer_certificate(ssl);
printf("(6) server's certificate was received:\n\n");
str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
printf(" subject: %s\n", str);
str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
printf(" issuer: %s\n\n", str);
/* certificate verification would happen here */
X509_free(server_cert);
/*********************************************************/
/* (7) handshake complete --- send HTTP request over SSL */
/*********************************************************/
sprintf(host_header,"Host: %s:443\r\n",hostname);
strcpy(outbuf,"GET / HTTP/1.0\r\n");
strcat(outbuf,host_header);
strcat(outbuf,"Connection: close\r\n");
strcat(outbuf,"\r\n");
err = SSL_write(ssl, outbuf, strlen(outbuf));
shutdown (sd, 1); /* send EOF to server */
printf("(7) sent HTTP request over encrypted channel:\n\n%s\n",outbuf);
/**************************************************/
/* (8) read back HTTP response from the SSL stack */
/**************************************************/
err = SSL_read(ssl, inbuf, sizeof(inbuf) - 1);
inbuf[err] = '\0';
printf ("(8) got back %d bytes of HTTP response:\n\n%s\n",err,inbuf);
/************************************************/
/* (9) all done, so close connection & clean up */
/************************************************/
SSL_shutdown(ssl);
close (sd);
SSL_free (ssl);
SSL_CTX_free (ctx);
printf("(9) all done, cleaned up and closed connection\n\n");
}
If you have any questions, feel free to contact me
My email address is zhouyi1023@tju.edu.cn