HTTPS

2021/04/16 计算机网络

详细记录一下HTTPS

1、HTTPS简介

  • HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面。 ————百度百科

HTTPS协议的主要功能基本都依赖于TLS/SSL协议,TLS/SSL的功能实现除妖依赖于三类基本算法。

  • 散列函数 散列函数验证信息的完整性 MD5/SHA
  • 对称加密 对称加密算法采用协商的秘钥对数据加密 AES/DES/RC4
  • 非对称加密 非对称加密实现身份认证和秘钥协商 RSA/ECC/DH

2、加密

加密就是研究如何安全通信的,对数据加密保证数据在传输过程中不会被窃听

2.1 对称加密

对称加密是最快速最简单的一种加密方式,加密和解密的秘钥是相同的,主要有AES/DES

简单实现一下凯撒加密,秘钥是3,把字母往后挪3位。

let secret = 3;
let message = 'hello motor'; // 要加密的数据

function encrypt(message) {
  // Buffer是一个字节数组
  let buffer = Buffer.from(message);
  for (let i = 0; i < buffer.length; i++) {
    buffer[i] = buffer[i] + secret;
  }
  return buffer.toString();
}

function decrypt(message) {
  let buffer = Buffer.from(message);
  for (let i = 0; i < buffer.length; i++) {
    buffer[i] = buffer[i] - secret;
  }
  return buffer.toString();
}

let encryptMessage = encrypt(message);
console.log('加密后的结果========', encryptMessage);
let decryptMessage = decrypt(encryptMessage)
console.log('解密后的结果========', decryptMessage);

// 运行如下
// 加密后的结果======== khoor#prwru
// 解密后的结果======== hello motor
//  hijklmn  h + 3 = k

加密的流程

  1. 加密需要制定加密算法,如aes-128-ecbaes是加密算法的类型,128是加密的长度,ecb是加密的模式
  2. 加密的秘钥 key 就是自定义随意的key,如果长度是128,key就是16位,如果是256则对应的是32位
  3. 加密的向量比如加密方式 iv 用于指定加密时所用的向量,相当于加盐
  • 加盐加密是一种对系统登录口令的加密方式,它实现的方式是将每一个口令跟一个n位随机数相关联,这个n位随机数叫做”盐“(salt)。

使用node里的crypto加密模块进行演示

let crypto = require('crypto');

function encrypt(data, key, iv) {
  let cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
  cipher.update(data);
  // hex: 16进制,把结果输出成16进制的字符串
  return cipher.final('hex');
}

function decrypt(data, key, iv) {
  let decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
  decipher.update(data, 'hex');
  // hex: 16进制,把结果输出成16进制的字符串
  return decipher.final('utf8');
}

let key = '1234567890abcdef';
let iv = '1234567890abcdef';
let data = 'hello world';
let encryptedData = encrypt(data, key, iv);
console.log(encryptedData)
let decryptData = decrypt(encryptedData, key, iv);
console.log(decryptData);

// 运行后的结果如下
// b0442aa419e0cd2c384623526b3cfcd6
// hello world

以上就实现了一次对称加密加密解密的流程,key在加密解密的过程中是同一个。对称加密的问题也出现在这个key上,key的传输没办法搞,被拿到key之后这个加密就毫无意义了,这就需要非对称加密了。

2.2 非对称加密

互联网没办法安全的交换秘钥,就需要非对称加密了。

非对称加密有两种算法:RSA/ECC

公钥加密私钥解,私钥加密公钥解。

RSA算法,加密用的秘钥和解密的秘钥不一样,但是他们有关系,不能通过公钥算出秘钥,是两个质数(只能被自己和1整除的数)相乘得到的一个结果,只能拿到这个结果,很难反推出来是哪两个数相乘。

let p = 3;
let q = 11;
let N = p * q; // 33
let e = 7; // 随意选的指数
let fN = (p - 1) * (q - 1); // 欧拉函数
// {e,n} 就是我们的公钥  公钥可以给任何人
// 公钥和私钥是一对,公钥加密的数据可以用私钥解密,私钥加密的数据可以用公钥解密
// 可以用公钥推算私钥,需要知道fN的值

/*
  N是给出的
  公钥 e N
Math.pow(m,e)%N = c  
  私钥 d N
Math.pow(c,d)%N = m

别人可以通过公钥 e和N 加密数据M,来得到加密后的数据c
但是如果想反算出来m就需要使用 私钥 d和N 和 数据C来反推m,但是对方并没有d,因为d的产生是需要知道fN的值,但是别人不知道,所以很难反推出来m
想要知道fN,需要知道 p和q的值, 对方只知道N的值,虽然知道N是p和q乘出来的,但是数学上无法从N上求出p和q,无法通过积推出因子
q和p实际中都是很多位的数,也没法枚举出来。 
*/ 

for (var d = 1; e * d % fN !== 1; d++) {}
console.log(d); // 3 

// 使用算法进行加密
let data = 5;
let c = Math.pow(data, e) % N;
let original = Math.pow(c, d) % N;
console.log('original ----' +  original);

以上就是算法的大概原理,下面使用crypto来加密一段数据

let { generateKeyPairSync, privateEncrypt, publicDecrypt } = require('crypto');

// generateKeyPairSync 生成秘钥对
// privateEncrypt 私钥加密
// publicDecrypt 公钥解密

// 生成秘钥对
let rsa = generateKeyPairSync('rsa', {
  // 设置长度
  modulusLength: 1024,
  // 设置公钥
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem' //base64
  },
  // 设置私钥
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-128-cbc',
    passphrase: 'passphrase'
  }
});

let message = 'hello crypto';

// 私钥加密
let encryptedMessage = privateEncrypt({
    key: rsa.privateKey,
    passphrase: 'passphrase'
  },
  Buffer.from(message, 'utf8')
)
console.log('加密后的数据:', encryptedMessage)

// 公钥解密
let decryptedMessage = publicDecrypt(rsa.publicKey, encryptedMessage)

console.log('解密后的数据:', decryptedMessage.toString())

// 输出
// 加密后的数据: <Buffer 64 4f 55 a5 5f 81 49 b8 1f 18 10 11 ad 36 0f 76 89 25 d9 2c 5e 83 2a a6 d5 f6 6f 1a 7c 9a 0c 61 bb 36 a3 6e 76 59 21 95 99 d0 5c 18 59 5d 01 94 c4 c9 ... 78 more bytes>
// 解密后的数据: hello crypto

2.3 hash

哈希函数:

  • 哈希函数的作用是给一个任意长度的数据生成一个固定长度的数据
  • 安全性 可以从给定的蜀西湖x计算出哈希值y,但不能从Y计算出数据X
  • 独一无二 的不同的数据一定会产生出不同的哈希值
  • 长度固定 不管输入多大的数据,输出的长度都是固定的

哈希碰撞:哈希的数据是根据内容而生成的,是固定的,一样的数据生成的哈希值是一样的,可以通过哈希碰撞来得到元数据,数据越大越不容易碰撞出来结果。

哈希分类:

  • 哈希还可以叫摘要校验值指纹
  • 如果两端数据完全一样,就可以证明数据是一样的
  • 哈希有两种:普通哈希用来做完整性校验,流行的是MD5,加密哈希用来做加密,目前最流行的加密算法是SHA256

哈希的使用:

let crypto = require('crypto');
let content = '123456';
let md5Hash = crypto.createHash('md5').update(content).digest('hex');
console.log(md5Hash) // 32位

// sha256 加盐
let crypto = require('crypto');
let content = '123456';
let salt = 21312321;
let shaHash = crypto.createHash('sha256', salt).update(content).digest('hex');
console.log(md5Hash) // 64位

2.4 数字签名

数字签名的基本原理是用私钥去签名,用公钥去验证签名。

  • 加密通信:公钥加密,私钥解密,用来传输输出
  • 数字签名:私钥加密,公钥解密,用来验证身份
let { generateKeyPairSync, createSign, createVerify } = require('crypto');

/*
  数字签名和数据证书的实现过程
*/

// 创建秘钥对
let rsa = generateKeyPairSync('rsa', {
  modulusLength: 1024,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem' //base64
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-128-cbc',
    passphrase: 'passphrase' // 私钥的密码
  }
});

let file = 'file';
// 先创建签名
let signObj = createSign('RSA-SHA256');
// 放入文件内容
signObj.update(file);
// 进行前面,  使用私钥,输出一个16进制字符串
let signInfo = signObj.sign({
  key: rsa.privateKey,
  format: 'pem',
  passphrase: 'passphrase',
}, 'hex');

console.log(signInfo); // 这个就是签名 16进制的字符串

// 前面是私钥加密,下面需要公钥解密验证签名

// 创建验证签名对象
let verifyObj = createVerify('RSA-SHA256');
// 放入文件内容
verifyObj.update(file);
// 验证签名是否合法  需要公钥和文件
let isValid = verifyObj.verify(rsa.publicKey, signInfo, 'hex' );
console.log(isValid); // 查看签名是否匹配  
// 输出true

验证签名原理:验证方拿到文件file,然后根据对方提供的公钥rsa.publicKey去计算一个自己生成的签名,然后去和对方提供的签名signInfo对比,如果一样就验证通过。

2.5 数字证书

数字证书是一个由可信的第三方发出的,用来证明所有人身份以及所有人拥有某个公钥的电子文件。

数字证书的认证流程:

  1. 客户端发送请求到服务端
  2. 服务端生成自己的私钥和公钥,然后服务端把自己的公钥发给CA机构
  3. CA机构用自己的私钥加密服务端的公钥
  4. CA的公钥会存在浏览器或重装系统中,可以直接通过公钥去解密出来CA发过来的服务端公钥
  5. 客户端使用服务端的公钥加密数据,传给服务端,服务端用自己的私钥解密客户端传过来的数据,完成一次安全的加密传输。

Search

    Table of Contents