前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【测试平台系列】第一章 手撸压力机(4)- http证书认证的实现

【测试平台系列】第一章 手撸压力机(4)- http证书认证的实现

作者头像
被测试耽误的大厨
发布2023-11-22 16:00:50
910
发布2023-11-22 16:00:50
举报
文章被收录于专栏:测试平台系列测试平台系列

上一篇对http请求进行了封装,本章咱们接着往下进行,讲解可配置项高级选项,假如一个http接口需要进行验证,我们应该如何处理。

我们知道通常https接口是通过ssl/tsl进行加密的,有时候我们的请求https接口需要进行验证,需要在客户端发送请求时,带上密钥对通过摘要算法计算出的摘要及明文进行加密,而服务端则通过密钥进行解密。

而https在认证,又分为单向认证和双向认证:

单向认证:

  1. 客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
  2. 服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书
  3. 客户端使用服务端返回的信息验证服务器的合法性,包括:
  4. 证书是否过期
  5. 发行服务器证书的CA是否可靠
  6. 返回的公钥是否能正确解开返回证书中的数字签名
  7. 服务器证书上的域名是否和服务器的实际域名相匹配
  8. 验证通过后,将继续进行通信,否则,终止通信
  9. 客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
  10. 服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
  11. 服务器将选择好的加密方案通过明文方式返回给客户端
  12. 客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器
  13. 服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。

双向认证:

  1. 客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
  2. 服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书
  3. 客户端使用服务端返回的信息验证服务器的合法性,包括:
  4. 证书是否过期
  5. 发行服务器证书的CA是否可靠
  6. 返回的公钥是否能正确解开返回证书中的数字签名
  7. 服务器证书上的域名是否和服务器的实际域名相匹配
  8. 验证通过后,将继续进行通信,否则,终止通信
  9. 服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端
  10. 验证客户端的证书,通过验证后,会获得客户端的公钥
  11. 客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
  12. 服务器端在客户端提供的加密方案中选择加密程度最高的加密方式
  13. 将加密方案通过使用之前获取到的公钥进行加密,返回给客户端
  14. 客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端
  15. 服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。

这样,我们就能明白我们需要如何去设计自己的高级选项结构了,我们首先需要选择是单向认证还是双向认证。下面我们在http_model.go文件中新增:

代码语言:javascript
复制
// AdvancedOptions 高级选项
type AdvancedOptions struct {
  Tls Tls // 验证设置
}

// Tls tls认证结构体
type Tls struct {
  IsVerify   bool   // 是否开启验证,默认不开启,开启后需要上传密钥文件
  VerifyType int32  // 认证类型:0表示双向认证;1表示单向认证;默认为0
  CaCert     string // 密钥文件
}

同时我们修改http_model.go文件中HttpClientSettings结构体,修改后如下:

代码语言:javascript
复制
// HttpClientSettings http客户端设置
type HttpClientSettings struct {
  //  客户端的名称,在header中的user-agent使用,通常我们默认就好
  Name string

  // 默认为flase,表示User-Agent使用fasthttp的默认值
  NoDefaultUserAgentHeader bool

  // 每台主机可以建立的最大连接数。如果没有设置,则使用DefaultMaxConnsPerHost。
  MaxConnsPerHost int

  // 空闲的保持连接在此持续时间之后关闭。默认情况下,在DefaultMaxIdleConnDuration之后关闭空闲连接。
  // 该连接如果空闲的话,在此时间后断开。
  MaxIdleConnDuration int64

  // Keep-alive连接在此持续时间后关闭。默认情况下,连接时间是不限制的。
  MaxConnDuration int

  // 默认情况下,响应读取超时时间是不限制的。
  ReadTimeout int64
  // 默认情况下,请求写超时时间不受限制。
  WriteTimeout int64

  // 请求头是否按标准格式传输
  DisableHeaderNamesNormalizing bool
  // url路径是按照原样输出,还是按照规范化输出。默认按照规范化输出
  DisablePathNormalizing bool
  AdvancedOptions        AdvancedOptions   // 高级选项
}

这样我们就完成了对http客户端认证相关的高级设置选项结构完成了改造,那我们如何去使用这些设置呢,下面我们对新建http客户端的代码,进行优化,修改http_client.go文件中的newHttpClient()方法:

代码语言:javascript
复制
// 新建一个http客户端
func newHttpClient(httpClientSettings model.HttpClientSettings) (httpClient *fasthttp.Client) {
  // tls验证,关闭验证
  tr := &tls.Config{
    InsecureSkipVerify: true,
  }
  // 新建指针类型的客户端
  httpClient = &fasthttp.Client{}

  if httpClientSettings.Name != "" {
    httpClient.Name = httpClientSettings.Name
  }

  if httpClientSettings.NoDefaultUserAgentHeader == true {
    httpClient.NoDefaultUserAgentHeader = true
  }

  // 如果最大连接数不为0,将设置此数
  if httpClientSettings.MaxConnsPerHost != 0 {
    httpClient.MaxConnsPerHost = httpClientSettings.MaxConnsPerHost
  }

  // url不按照标准输出,按照原样输出
  if httpClientSettings.DisablePathNormalizing == true {
    httpClient.DisablePathNormalizing = true
  }
  // 请求头不按标准格式传输
  if httpClientSettings.DisableHeaderNamesNormalizing == true {
    httpClient.DisableHeaderNamesNormalizing = true
  }

  // 如果此时间不为0,那么将设置此时间。keep-alive维持此时长后将关闭。时间单位为毫秒
  if httpClientSettings.MaxConnDuration != 0 {
    httpClient.MaxConnDuration = time.Duration(httpClientSettings.MaxConnDuration) * time.Millisecond
  }

  if httpClientSettings.ReadTimeout != 0 {
    httpClient.ReadTimeout = time.Duration(httpClientSettings.ReadTimeout) * time.Millisecond
  }

  if httpClientSettings.WriteTimeout != 0 {
    httpClient.WriteTimeout = time.Duration(httpClientSettings.WriteTimeout) * time.Millisecond
  }

  // 该连接如果空闲的话,在此时间后断开。
  if httpClientSettings.MaxIdleConnDuration != 0 {
    httpClient.MaxIdleConnDuration = time.Duration(httpClientSettings.MaxIdleConnDuration) * time.Millisecond
  }
  
  // 
  httpsTls := httpClientSettings.AdvancedOptions.Tls
  
  // 如果开启认证
  if httpsTls.IsVerify {
    // switch条件选择语句,如果认证类型为0:则表示双向认证,如果是1:则表示为单向认证
    switch httpsTls.VerifyType {
    case 0: // 开启双向验证
      tr.InsecureSkipVerify = false
      // 如果密钥文件为空则跳出switch语句
      if httpsTls.CaCert == "" {
        break
      }
      // 生成一个cert对象池
      caCertPool := x509.NewCertPool()
      if caCertPool == nil {
        fmt.Println("生成CertPool失败!")
        break
      }
      
      // 读取认证文件,读出后为字节数组
      key, err := ioutil.ReadFile(httpsTls.CaCert)
      // 如果读取错误,则跳出switch语句
      if err != nil {
        fmt.Println("打开密钥文件失败:", err.Error())
        break
      }
      // 将认证文件添加到cert池中
      ok := caCertPool.AppendCertsFromPEM(key)
      // 如果添加失败则跳出switch语句
      if !ok {
        fmt.Println("密钥文件错误,生成失败!!!")
        break
      }
      // 将认证信息添加到客户端认证结构体
      tr.ClientCAs = caCertPool
    case 1: // 开启单向验证,客户端验证服务端密钥
      tr.InsecureSkipVerify = false
    }
  }

  // 客户端认证配置项
  httpClient.TLSConfig = tr
  return
}

下面我们验证一下,我们的修改是否成功。由于没有https接口,大家可自行实验。

修改main.go文件,如下:

代码语言:javascript
复制
package main

import (
  "kitchen-engine/client"
  "kitchen-engine/model"
)

func main() {

  // 一个类型中的字段,可以重置,也可以使用默认值,在go中,所有的类型的初始值,都是字段类型的0值,比如string的初始值是""空字符串,int类型的初始值是0等等
  httpClientSettings := model.HttpClientSettings{
    Name:                     "测试厨房",
    NoDefaultUserAgentHeader: true,
    MaxConnDuration:          1000,
    AdvancedOptions: model.AdvancedOptions{
      Tls: model.Tls{
        IsVerify:   false,
        VerifyType: 1,
      },
    },
  }

  headers := []model.Header{
    model.Header{
      Field: "name",
      Value: "你好",
    },
  }

  httpRequest := model.HttpRequest{
    Name:               "planet",
    Url:                "https://www.baidu.com",
    Method:             "GET",
    HttpClientSettings: httpClientSettings,
    Headers:            headers,
  }

  client.RequestHttp(httpRequest)
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈测试开发之路 微信公众号,前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云服务器利旧
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档