前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入浅出NodeJS随记 (三)

深入浅出NodeJS随记 (三)

原创
作者头像
邱邱邱邱yf
发布2021-12-10 16:37:54
3980
发布2021-12-10 16:37:54
举报
文章被收录于专栏:邱邱邱邱yf的读书笔记

最近在研读书籍 深入浅出nodejs , 随手写下的一些笔记, 和大家分享~ 如有错误,欢迎指正~

理解Buffer

由于应用场景与前端有所不同,在Node中,应用需要处理网络协议、操作数据库、处理图片、接受上传的文件等,在网络流和文件的操作中,还需要处理大量的二进制数据,js自带的字符串操作远远不能满足这些需求,所以Buffer对象应运而生。

1. Buffer结构

Buffer是一个很像Array的对象,但它主要用于操作字节。

  1. 模块结构:Buffer是一个典型的JS和C++结合的模块,它将性能相关部分用C++实现,非性能相关的用JS实现由于Buffer太过常见,Node在进程启动时就已经加载,放在全局,所以不需要require就可以使用。
  2. 对象结构:Buffer对象类似于数组,它的元素为16进制的两位数。Buffer受Array影响很大,可以访问length属性得到长度,也可以通过下标访问元素,初始化时也可以传入长度。(给Buffer元素赋值要是不在0-255区间内时,会强制转换到0-255中,比如负数加上256,大于255则减去256,小数则舍弃小数部分)
  3. Buffer内存分配: 分配不通过V8,是通过Node的C++层面实现内存申请的。(不能需要一点就申请一点,可能会造成大量的内存申请的系统调用,对操作系统有一定的压力) 为了高效的使用申请来的内存,Node采用了slab分配机制。slab是一种动态内存管理机制,具有以下三种状态:
    1. full: 完全分配状态
    2. partial: 部分分配状态
    3. empty: 没有被分配状态

    分配指定大小的Buffer对象: new Buffer(size)(已经被淘汰,现在更多使用Buffer.from(),Buffer.alloc()来创建) Node以8KB的界限来区分大对象和小对象, 8KB也就是每个slab的大小值,js层面以它作为单位单元进行内存分配 分配小Buffer对象: 指定buffer大小 小于8K,node就会按照小对象方式分配。 首次创建Buffer会先去检查一个叫做pool的中间变量(是一个对象,含有used的属性记录使用了多少),没有则新建一个slab(创建一个slowBuffer, 大小为8K,used为0)然后指向它。同时当前Buffer对象的parernt指向这个slab(pool),也同时记录offset(就是used属性的值)然后再更新used的值(加上当前buffer的size),修改状态为partial(部分分配)。当再次创建buffer对象会先判断这个slab(pool)的剩余空间是否足够,足够就继续使用,并更新slab。如果不够就会创建新的slab,原来slab空间就会浪费。 由于同一个slab被分配给多个buffer使用,只有所有的buffer作用域都释放,slab才可以被回收。 分配大buffer对象 指定buffer大小 大于8K,将会直接分配一个slowBuffer对象(buffer的parent属性)作为slab,大小为所需要的指定size。这个slab被这个大对象独占。 Buffer是JS层面的,能够被V8垃圾回收标记回收。但是内部的parent属性slowBuffer是c++层面上的Buffer对象,所用内存不在V8堆中。 不论是小 Buffer 对象还是大 Buffer 对象,内存分配是在 C++ 层面完成,内存管理在 JavaScript 层面,最终还是可以被 V8 的垃圾回收标记所回收,回收的是 Buffer 对象本身,堆外内存的那些部分只能交给 C++。 Buffer所占的内存不是V8堆内存,是独立于V8堆内存之外的内存,通过C++层面实现内存申请(可以说真正的内存是C++层面提供的)、javascript 分配内存(可以说JavaScript层面只是使用它)。 网络中传输的一般都是buffer二进制数据(乱码 的由来一般就是 二进制在被转换为宽字符时被截断,从而导致了乱码的生成)可以预先转换静态内容为Buffer对象,可以有效地减少CPU的重复使用,节省服务器资源。

网络服务与安全

在网络中,数据在服务器端和客户端之间传递,由于是明文传递内容,一旦在网络中被人监听,数据就可能被窃取。为此我们需要将数据加密再进行网络传输,这样即使数据被截取,窃听者也无法知道数据的真实内容。(但是我们希望数据,对于应用层而言是透明的,数据在传输到应用层之前就已经完成了加密和解密的过程。这就是SSL,在传输层提供对网络连接加密功能,TLS是SSL的标准化)

Node在网络安全上提供了3个模块,分别为crypto, tls, https。其中crypto主要用于加密解密,SHA1、 MD5等加密算法都有对应的实现。真正用于网络的是其他两个模块, tls提供类似net模块的功能,区别在于他建立在TLS/SSL加密的tcp连接上。https则与http模块类似,区别仅在它建立在安全的连接上。

1. 密钥

TLS/SSL是一个公钥/私钥的结构,它是一个非对称的结构,每个服务器端和客户端都各自保存自己的公私钥。公钥用来加密要传输的数据,私钥用来解密收到的数据。公钥和私钥适配对的,通过公钥加密的数据只能用配对的私钥才能来解密。所以在建立安全传输之前,客户端和服务端之间要互换公钥。客户端发送数据前要用服务端的公钥进行加密,服务端发送数据前要用客户端的公钥进行加密,如此才能完成加密解密过程。

公私钥的非对称加密虽好,但是网络中仍然可能存在被窃听的情况,典型的例子就是中间人攻击。客户端和服务端在交换公钥的过程中,中间人对客户端扮演服务端的角色,对服务端扮演客户端的角色,因此客户端和服务端基本感受不到中间人的存在,为了解决这个问题,数据传输过程中还需要对得到的公钥进行认证,以确认得到的公钥是出自目标服务器的。为了解决这个问题,TLS/SSL引入了数字证书来进行认证。与直接用公钥不同,数字证书中包含了服务器的名称和主机名、服务器的公钥、签名颁发机构的信息、签名颁发机构的签名。在建立连接前会通过证书中的签名确认收到的公钥是来自目标服务器的,从而确认信任关系。

2.数字证书

为了确保我们的数据安全,现在我们引入了一个第三方: CA(Certificate Authority, 数字证书认证中心)。CA的作用是为站点颁发证书,且这个证书中具有CA通过自己的公私钥实现的签名。

为了得到CA的签名证书,服务器端需要通过自己的私钥生成CSR(证书签名请求)文件。CA机构将通过这个文件颁发属于服务器端的签名证书。这个证书通过CA机构就能验证是否合法。

客户端在发起安全连接前回去获取服务器端的证书,并通过CA的证书来验证服务器端证书的真伪。除了验证真伪,通常还含有对服务器名称、IP地址等进行验证的过程。

CA机构将证书颁发给服务器端后,证书在请求的过程中会被发送给客户端,客户端需要通过CA的证书验证真伪。如果是知名的CA机构,他的证书一般预安装在浏览器中。

(来自: https://www.zhihu.com/question/37370216

CA 签发证书的过程,如上图左边部分:

  • 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
  • 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
  • 最后将 Certificate Signature 添加在文件证书上,形成数字证书;

客户端校验服务端的数字证书的过程,如上图右边部分:

  • 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
  • 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密Certificate Signature 内容,得到一个 Hash 值 H2 ;
  • 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解Buffer
    • 1. Buffer结构
    • 网络服务与安全
      • 1. 密钥
        • 2.数字证书
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档