magic 发布的文章

作为一个程序员,想要学习物联网控制,并将学习过程记录下来,方便他人查阅。

  1. 准备硬件:选择ESP8266 12F,它内置WiFi,适合入门。
  2. 安装工具:使用Arduino IDE进行代码编写和上传。
  3. 安装驱动与库:使用提供的一键安装包,简化ESP8266驱动和MQTT库的安装。
  4. 获取Bmob云服务信息:注册并获取MQTT服务的必要信息。
  5. 编写与上传代码:配置WiFi和MQTT连接,控制ESP8266内置灯。
  6. 远程控制灯光:通过Bmob云实现远程开关灯。

首先我们看最终效果

输入on 开灯

输入off 关灯

这是是最终效果的录制视频

https://www.ixigua.com/7403595674341605942?utm_source=iframe_share

  1. 准备硬件:选择ESP8266 12F,它内置WiFi,适合入门。

    ESP8266-12F 是一个经济实惠的 WiFi 模块,广泛应用于物联网(IoT)开发。它自带 WiFi 功能,支持 2.4GHz 无线网络连接,适合需要无线通信的小型电子项目。模块体积小巧,拥有多个 GPIO 引脚,可轻松集成到各种硬件项目中。由于其低功耗和强大的处理能力,ESP8266-12F 在远程控制、智能家居、传感器网络等领域得到了广泛应用,成为了物联网开发的首选硬件之一。

主要是他便宜,国产,并且最新手友好,他长这样,价格就十几块,网上随便找个店铺即可

image.png

下单,我这因为购买了一些其他材料,所有价格需要30多

image.png

  1. 安装工具:使用Arduino IDE进行代码编写和上传。

    这里选择Arduino IDE,下载地址:www.arduino.cc/en/software

    image.png

  2. 安装驱动与库:使用提供的一键安装包,简化ESP8266驱动和MQTT库的安装。

    1. 下载安装后,安装esp8266模块

    image.png

    1. 开发工具安装mqtt链接库,由于github 被墙,这里我传个国内代码镜像,封装为bat命令,安装时关闭开发工具

      https://link.juejin.cn/?target=https%3A%2F%2Fbmob-cdn-31082.bmobpay.com%2Fiot%2Fesp8266_install.zip

      [图片上传失败...(image-72868c-1725876245397)]

    2. 我们把代码上次的时候,需要选择我们上传的端口

      image.png

      这样我们就可以把代码烧录到esp8266

  3. 获取Bmob云服务信息:注册并获取MQTT服务的必要信息。

登录控制台

[图片上传失败...(image-5d830f-1725876245397)]

左侧IOT栏目,拿到链接参数

image.png

  1. 编写与上传代码:配置WiFi和MQTT连接,控制ESP8266内置灯。

代码直接复制使用,把里面几个参数跟Bmob后端云一致即可

// 加载WIFI头文件
#include <ESP8266WiFi.h>
// 加载MQTT库文件
#include <PubSubClient.h>

// 你的WIFI名称,需要修改
const char* WIFI_SSID = "WiFi名称";
// 你的WIFI密码,需要修改
const char* WIFI_PASSWORD = "WiFi密码";
// Bmob云的物联网地址
const char* MQTT_SERVER = "broker.codenow.cn";
// Bmob云的物联网端口
const int MQTT_PORT = 1883;
// 灯光引脚
const int LED = 2;
// 用户名,到Bmob云->创建的应用-> IOT -> 连接信息 中获取
#define APPID  "603b85d874d1b5ea"
// 密码,到Bmob云->创建的应用-> IOT -> 连接信息 中获取
#define APPPASSWORD "19a66167a0eadaca"
// 你自己定义的设备类型,方便记忆就好,这里的LINE表示灯光的意思
#define TYPE  "LINE"

WiFiClient espClient;
PubSubClient client(espClient);

// 打开灯泡
void turnOnLed() {
  Serial.println("打开灯光");
  digitalWrite(LED, LOW);
}
// 关闭灯泡
void turnOffLed() {
  Serial.println("关闭灯光");
  digitalWrite(LED, HIGH);
}

// 配置esp8266的WIFI账号和密码
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WIFI_SSID);
  // 设置WIFI的账号和密码
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  // 检测WIFI是否联通
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi已连接");
}

// MQTT服务的回调
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print(topic);
  Serial.print(" 主题收到消息");
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[I];
  }
  Serial.print(message);
  Serial.println();

  if (message == "on") {
    //如果接收到on字符串,调用开灯方法
    turnOnLed();//开灯函数

  } else if (message == "off") {
    //如果接收到off字符串,调用关灯方法
    turnOffLed();
  }
  message = "";
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("正在尝试MQTT连接...");

    String client_id = "esp8266client";
    client_id += String(WiFi.macAddress());
    if (client.connect(client_id.c_str(), APPID, APPPASSWORD)) {
      Serial.println("正常连接");

      //这是你的主题名称
      String topic = "devices/" + String(TYPE) + "/" + String(APPID) + "/" + client_id;
      client.subscribe(topic.c_str());
    } else {
      Serial.print("连接异常,rc=");
      Serial.print(client.state());
      Serial.println(" 5秒后重试");
      // 5秒重试
      delay(5000);
    }
  }
}

void setup() {
  pinMode(LED, OUTPUT);
  // 设置波特率
  Serial.begin(115200);
  // 配置WIFI并连接上网
  setup_wifi();
  // 连接MQTT服务
  client.setServer(MQTT_SERVER, MQTT_PORT);
  // 设置MQTT消息回掉
  client.setCallback(callback);
  digitalWrite(LED, HIGH);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

image.png

查看日志

查看串口输出的时候,记得选择波特率位115200(代码中设置的)。

[图片上传失败...(image-5ebe06-1725876245397)]

这样esp8266 就已经链接上mqtt服务。 只要远程下指令,就可以实现开与关

开关核心代码

if (message == "on") {
    //如果接收到on字符串,调用开灯方法
    turnOnLed();//开灯函数

  } else if (message == "off") {
    //如果接收到off字符串,调用关灯方法
    turnOffLed();
  }
  1. 远程控制灯光:通过Bmob云实现远程开关灯。

image.png
image.png

这样就实现了服务器控制远程开关灯, 后面我们把这个开关操作,使用小程序实现。

XCode15, XCode16版本使用Cocoapods报错解决

Xcode版本 Version 16.0 (16A242d)

新建一个项目bmob202407

1.界面加入一个按钮

Xnip2024-10-23_10-06-19.jpg

2.新增一个podfile文件

platform :ios, '11.0'  # Specify the platform and deployment target

target 'bmob202407' do
  pod 'BmobSDK'
end

3.安装pod

 pod install
Analyzing dependencies

――― MARKDOWN TEMPLATE ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

### Command

```
/Users/magic/.rbenv/versions/3.2.5/bin/pod install
```

### Report

* What did you do?

* What did you expect to happen?

* What happened instead?


### Stack

```
   CocoaPods : 1.15.2
        Ruby : ruby 3.2.5 (2024-07-26 revision 31d0f1a2e7) [arm64-darwin24]
    RubyGems : 3.5.22
        Host : macOS 15.0.1 (24A348)
       Xcode : 16.0 (16A242d)
         Git : git version 2.39.5 (Apple Git-154)
Ruby lib dir : /Users/magic/.rbenv/versions/3.2.5/lib
Repositories : master - git - git@github.com:CocoaPods/Specs.git @ 3c25b942607c8dc669d5d708aeafaa9067522375

               trunk - CDN - https://cdn.cocoapods.org/
```

### Plugins

```
cocoapods-deintegrate : 1.0.5
cocoapods-plugins     : 1.0.0
cocoapods-search      : 1.0.1
cocoapods-trunk       : 1.6.0
cocoapods-try         : 1.2.0
```

### Podfile

```ruby
platform :ios, '11.0'  # Specify the platform and deployment target

target 'bmob202407' do
  pod 'BmobSDK'
end
```

### Error

```
RuntimeError - `PBXGroup` attempted to initialize an object with unknown ISA `PBXFileSystemSynchronizedRootGroup` from attributes: `{"isa"=>"PBXFileSystemSynchronizedRootGroup", "exceptions"=>["3036C49C2CC74D2A00E71FAF"], "path"=>"bmob202407", "sourceTree"=>"<group>"}`
If this ISA was generated by Xcode please file an issue: https://github.com/CocoaPods/Xcodeproj/issues/new
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:359:in `rescue in object_with_uuid'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:349:in `object_with_uuid'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:300:in `block (2 levels) in configure_with_plist'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:299:in `each'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:299:in `block in configure_with_plist'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:296:in `each'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:296:in `configure_with_plist'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project.rb:272:in `new_from_plist'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:350:in `object_with_uuid'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:290:in `block in configure_with_plist'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:287:in `each'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project/object.rb:287:in `configure_with_plist'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project.rb:272:in `new_from_plist'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project.rb:213:in `initialize_from_file'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/xcodeproj-1.25.1/lib/xcodeproj/project.rb:113:in `open'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:1194:in `block (2 levels) in inspect_targets_to_integrate'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:1193:in `each'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:1193:in `block in inspect_targets_to_integrate'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/user_interface.rb:64:in `section'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:1188:in `inspect_targets_to_integrate'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:107:in `analyze'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:422:in `analyze'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:244:in `block in resolve_dependencies'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/user_interface.rb:64:in `section'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:243:in `resolve_dependencies'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:162:in `install!'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/command/install.rb:52:in `run'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/claide-1.1.0/lib/claide/command.rb:334:in `run'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/lib/cocoapods/command.rb:52:in `run'
/Users/magic/.rbenv/versions/3.2.5/lib/ruby/gems/3.2.0/gems/cocoapods-1.15.2/bin/pod:55:in `<top (required)>'
/Users/magic/.rbenv/versions/3.2.5/bin/pod:25:in `load'
/Users/magic/.rbenv/versions/3.2.5/bin/pod:25:in `<main>'
```

――― TEMPLATE END ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

[!] Oh no, an error occurred.

Search for existing GitHub issues similar to yours:
https://github.com/CocoaPods/CocoaPods/search?q=%60PBXGroup%60+attempted+to+initialize+an+object+with+unknown+ISA+%60PBXFileSystemSynchronizedRootGroup%60+from+attributes%3A+%60%7B%22isa%22%3D%3E%22PBXFileSystemSynchronizedRootGroup%22%2C+%22exceptions%22%3D%3E%5B%223036C49C2CC74D2A00E71FAF%22%5D%2C+%22path%22%3D%3E%22bmob202407%22%2C+%22sourceTree%22%3D%3E%22%3Cgroup%3E%22%7D%60%0AIf+this+ISA+was+generated+by+Xcode+please+file+an+issue%3A+https%3A%2F%2Fgithub.com%2FCocoaPods%2FXcodeproj%2Fissues%2Fnew&type=Issues

If none exists, create a ticket, with the template displayed above, on:
https://github.com/CocoaPods/CocoaPods/issues/new

Be sure to first read the contributing guide for details on how to properly submit a ticket:
https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md

Don't forget to anonymize any private data!

Looking for related issues on cocoapods/cocoapods...
Searching for inspections failed: undefined method `map' for nil:NilClass

这个错误,你把项目转为组即可解决

1.打开你的 Xcode 项目。
2.在左侧的项目导航器中,右键点击项目文件夹(通常是项目名称)。
3.选择“Convert to Group”(转换为组)。

Xnip2024-10-23_09-50-08.jpg

继续pod install

Don't forget to anonymize any private data!

Looking for related issues on cocoapods/cocoapods...
 - Cocoapods not working in Xcode 16 macOS 15.0.1
   https://github.com/CocoaPods/CocoaPods/issues/12625 [open] [12 comments]
   a day ago

 - PBXFileSystemSynchronizedRootGroup causing pod init to fail with CocoaPods 1.15.2a
   https://github.com/CocoaPods/CocoaPods/issues/12627 [closed] [7 comments]
   a week ago

 - pod install has bug
   https://github.com/CocoaPods/CocoaPods/issues/10723 [closed] [33 comments]
   11 Jun 2024

and 2 more at:
https://github.com/cocoapods/cocoapods/search?q=%5BXcodeproj%5D%20Unable%20to%20find%20compatibility%20version%20string%20for%20object%20version%20%6077%60.&type=Issues&utf8=✓

[!] [!] Xcodeproj doesn't know about the following attributes {"preferredProjectObjectVersion"=>"77"} for the 'PBXProject' isa.
If this attribute was generated by Xcode please file an issue: https://github.com/CocoaPods/Xcodeproj/issues/new

[!] [Xcodeproj] Xcode project version (77) is higher than the latest supported by xcodeproj (63).

错误已经发生改变, 提示我们本地Xcode版本77太高, pod最新版本最高支持63

1.找到并打开 `project.pbxproj` 文件,使用文本编辑器(如 sublime之类)。
    2.删除以下两行:
        minimizedProjectReferenceProxies = 1;
        preferredProjectObjectVersion = 77;
    3.更新以下行:
        objectVersion = 77; 
      修改为:
        objectVersion = 63;

提示安装成功

>bmob202407 pod install
Analyzing dependencies
Downloading dependencies
Installing BmobSDK (2.4.21)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `bmob202407.xcworkspace` for this project from now on.
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

安装之后,真机可以,模拟器不行,提示

building for ios simulator but linking in object file built for ios m1

Xnip2024-10-23_10-58-31.jpg

这样设置即可解决,有更多问题也可以留言给我

实现图床项目

新建一个vue3项目

vue create bmob-viewer

Xnip2024-09-23_10-44-50.jpg

安装 element-plus

yarn add element-plus

放一个按钮看下是否引入成功

    <el-card class="bucket-select-card">
      <div>
        <el-button type="primary">按钮</el-button>
        <el-button type="primary" disabled>按钮</el-button>
      </div>

    </el-card>

Xnip2024-09-23_14-18-44.jpg

做一个上传界面,我们使用el-upload 组件

https://s-test.belle.cn/zh-CN/component/upload.html 照片墙代码

<template>
  <el-upload
    v-model:file-list="fileList"
    action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
    list-type="picture-card"
    :on-preview="handlePictureCardPreview"
    :on-remove="handleRemove"
  >
    <el-icon><Plus /></el-icon>
  </el-upload>

  <el-dialog v-model="dialogVisible">
    <img w-full :src="dialogImageUrl" alt="Preview Image" />
  </el-dialog>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { Plus } from '@element-plus/icons-vue'

import type { UploadProps, UploadUserFile } from 'element-plus'

const fileList = ref<UploadUserFile[]>([
  {
    name: 'food.jpeg',
    url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100',
  },
  {
    name: 'plant-1.png',
    url: '/images/plant-1.png',
  }
])

const dialogImageUrl = ref('')
const dialogVisible = ref(false)

const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
  console.log(uploadFile, uploadFiles)
}

const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url!
  dialogVisible.value = true
}
</script>

Xnip2024-09-23_15-38-51.jpg

这个列表数据是写死的,我们从服务器文件记录表取出记录,这里我们使用Bmob后端云

安装sdk

npm install hydrogen-js-sdk

main.ts 初始化sdk

import Bmob from 'hydrogen-js-sdk'

// 初始化
Bmob.initialize("e7cebb69e9ed76e9", "111111");

取出数据

let fileList = ref<UploadUserFile[]>([])

const query = Bmob.Query('pic_list');
query.find().then(res => {
  // 确保 res 是 UploadUserFile[] 类型
  if (Array.isArray(res)) {
    fileList.value = res;
  } else {
    console.error('查询结果类型不匹配');
  }
});

效果

Xnip2024-09-25_16-23-05.jpg

实现删除


const handleRemove: UploadProps['onRemove'] = (uploadFile: ImageInfo, uploadFiles: ImageInfo[]) => {
  console.log(uploadFile);

  const query = Bmob.Query('pic_list');
  const objectId = uploadFile.objectId;

  query.destroy(objectId).then(res => {

    // 传入string是单个文件删除,传入array是批量删除
    const del = Bmob.File("a", "jfdf");
    const val = [uploadFile.url]
    del.destroy(val).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err)
    })
  }).catch(err => {
    console.error('删除文件失败:', err);
  });
};

实现上传

const customUpload = async (options) => {
  const file = Bmob.File(options.file.name, options.file);
  const res = await file.save();
  console.log("File saved successfully:", res);
  // 把URL保存到Bmob pic_list表中
  const query = Bmob.Query('pic_list');
  const data = {
    name: options.file.name,
    url: res[0].url
  };
  query.save(data).then(res => {
    console.log(res)
  }).catch(err => {
    console.log(err)
  })
}

最终效果

Xnip2024-09-30_17-08-02.jpg

项目开源代码地址

https://github.com/magic007/Vue3-image-bed

部署效果地址

http://images-bed.cctvcloud.cn/

在我们的日常网络活动中,HTTPS 协议扮演着至关重要的角色,它确保了数据传输的安全性和隐私性。然而,在某些情况下,如调试网站、分析网络流量或进行安全测试时,我们可能需要捕获并查看 HTTPS 流量的明文内容。这通常涉及到解密 HTTPS 流量,以便我们可以清晰地看到传输的数据。在本文中,我将向您介绍如何使用 Wireshark,这是一款功能强大的网络协议分析工具,来捕获 HTTPS 流量的明文数据。请注意,这一过程仅在您有合法权限对网络流量进行监控的情况下才是正当的,例如在您自己的网络环境中或已获得明确授权的测试环境中。

Fiddler 存在的问题

Fiddler目前还不支持HTTP2协议,无法看到真正的HTTP2报文,这里有些人可能会有疑问,说我明明就用Fiddler抓到了HTTP2协议的报文啊,那是因为Fiddler中间人攻击服务器通过协商把协议降级成了HTTP1协议,所以实际上看到的还是的HTTP1的报文,通过下面两个图片可以直观的感受到:

  • 不通过代理,直接访问支持 HTTP2 的服务

2020-08-10-10-10-24.png

  • 通过代理访问,进行抓包

2020-08-10-10-11-37.png

可以看到在通过代理抓包的时候,协议变成了http/1.1

使用 wireshark 抓取

现在市面上的主流浏览器实现的 HTTP2 都是基于TLS的,也就是说要分析HTTP2报文得先过了TLS这一关,不然只能分析一堆加密的乱码。

wireshark支持两种方式来解密SSL/TLS报文:

  1. 通过网站的私钥
  2. 通过浏览器的将 TLS 对称加密秘保存在外部文件中,以供 wireshark 加解密

下面我来一一进行演示

1. 通过网站的私钥

如果你想抓取的网站是你自己的,那么可以利用这种方式,因为这需要使用网站生成证书使用的私钥进行解密,就是那个 nginx 上ssl_certificate_key配置对应的私钥文件,把它添加到 wireshark 配置中:

2020-08-10-10-41-14.png

然后通过wireshark就可以看到明文了:
2020-08-10-11-10-00.png

通过上图可以看到,我通过curl访问的 https 协议的 URL,在配置了该服务器对应的私钥后可以抓取到对应的 HTTP 明文。

不过缺点也非常明显,只能分析自己持有私钥的网站,如果别人的网站就分析不了了,所幸的是还有第二种方案来支持。

2. 通过浏览器的 SSL 日志功能

目前该方案只支持ChromeFirefox浏览器,通过设置SSLKEYLOGFILE环境变量,可以指定浏览器在访问SSL/TLS网站时将对应的密钥保存到本地文件中,有了这个日志文件之后wireshake就可以将报文进行解密了。

  1. 首先设置SSLKEYLOGFILE环境变量:
    2020-08-10-11-19-37.png
注:这是在 windows 系统上进行操作的,其它操作系统同理
  1. 配置wireshake,首选项->Protocls->TLS:
    2020-08-10-11-23-31.png

    将第一步中指定的文件路径配置好

  2. 重启浏览器,进行抓包:
    2020-08-10-11-30-55.png

同样的可以抓取到 HTTP 明文。

注:不抓包时记得把环境变量删掉,以避免性能浪费和安全性问题

方案二的优点非常明显,可以抓取任意网站的SSL/TLS加密的报文,唯一的缺点就是只能是浏览器支持的情况才行,而方案一可以针对任何 HTTP 客户端进行抓包。

通过 wireshake 抓取 HTTP2 报文

上面都是针对TLS+HTTP1进行的抓包,市面上主流的浏览器的HTTP2都是基于TLS实现的,所以也是一样的,把TLS这层解密了自然看到的就是最原始的明文。

这里以分析https://www.qq.com为例,为什么不是经典htts://www.baidu.com,因为百度首页至今还是HTTP/1.1协议。

  1. 使用上面的第二种方案配置好wiresharke
  2. 通过http2关键字做过滤
  3. 浏览器访问https://www.qq.com
  4. 查看HTTP2报文:
    2020-08-10-11-47-00.png

这样就抓取到了HTTP2报文了,HTTP2 协议非常复杂,我也还在学习阶段,这里就不多说啥了。

后记

wireshake 真的是一款非常强大的网络分析工具,在HTTPSHTTP2日渐成为主流的时候,可以用它来帮助我们加深对这些协议的理解,以便迎接新的机遇与挑战。

博客一年的证书快到期了,准备部署一个ACME来实现自动免费续期,自动部署服务,下面把整个过程记录出来。

https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E

Xnip2024-09-19_09-58-27.jpg

  • ACME(Let's Encrypt)简介

    acme.sh 实现了 acme 协议, 可以从 letsencrypt 生成免费的证书.

    主要步骤:

    1. 安装 acme.sh
    2. 生成证书
    3. copy 证书到 nginx/apache 或者其他服务
    4. 更新证书
    5. 更新 acme.sh

1. 安装 acme.sh

安装很简单, 一个命令:

curl https://get.acme.sh | sh -s email=my@example.com

执行结果

(base) [root@VM-4-5-centos ~]# curl  https://get.acme.sh | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1032    0  1032    0     0    351      0 --:--:--  0:00:02 --:--:--   351
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  219k  100  219k    0     0  47927      0  0:00:04  0:00:04 --:--:-- 58853
[Thu Sep 19 09:50:03 CST 2024] Installing from online archive.
[Thu Sep 19 09:50:03 CST 2024] Downloading https://github.com/acmesh-official/acme.sh/archive/master.tar.gz
[Thu Sep 19 09:50:05 CST 2024] Extracting master.tar.gz
[Thu Sep 19 09:50:05 CST 2024] It is recommended to install socat first.
[Thu Sep 19 09:50:05 CST 2024] We use socat for the standalone server, which is used for standalone mode.
[Thu Sep 19 09:50:05 CST 2024] If you don't want to use standalone mode, you may ignore this warning.
[Thu Sep 19 09:50:05 CST 2024] Installing to /root/.acme.sh
[Thu Sep 19 09:50:05 CST 2024] Installed to /root/.acme.sh/acme.sh
[Thu Sep 19 09:50:05 CST 2024] Installing alias to '/root/.bashrc'
[Thu Sep 19 09:50:05 CST 2024] Close and reopen your terminal to start using acme.sh
[Thu Sep 19 09:50:05 CST 2024] Installing alias to '/root/.cshrc'
[Thu Sep 19 09:50:05 CST 2024] Installing alias to '/root/.tcshrc'
[Thu Sep 19 09:50:05 CST 2024] Installing cron job
[Thu Sep 19 09:50:05 CST 2024] bash has been found. Changing the shebang to use bash as preferred.
[Thu Sep 19 09:50:07 CST 2024] OK
[Thu Sep 19 09:50:07 CST 2024] Install success!

看到Install success 则安装成功

这里直接执行acme.sh 会提示命令不存在

acme.sh --issue -d cctvcloud.cn --nginx
-bash: acme.sh: command not found

需要让环境变量生效

 source /root/.bashrc

2. 生成证书

因为我服务器是nginx,我使用命令

acme.sh --issue -d mydomain.com --nginx

提示

[Thu Sep 19 09:52:50 CST 2024] Using CA: https://acme.zerossl.com/v2/DV90
[Thu Sep 19 09:52:50 CST 2024] Account key creation OK.
[Thu Sep 19 09:52:50 CST 2024] No EAB credentials found for ZeroSSL, let's obtain them
[Thu Sep 19 09:52:50 CST 2024] acme.sh is using ZeroSSL as default CA now.
[Thu Sep 19 09:52:50 CST 2024] Please update your account with an email address first.
[Thu Sep 19 09:52:50 CST 2024] acme.sh --register-account -m my@example.com
[Thu Sep 19 09:52:50 CST 2024] See: https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA
[Thu Sep 19 09:52:50 CST 2024] Please add '--debug' or '--log' to see more information.
[Thu Sep 19 09:52:50 CST 2024] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh

acme.sh 脚本正在使用 ZeroSSL 作为默认的证书颁发机构(CA),并且要求你在继续之前先注册一个账户并提供一个电子邮件地址。以下是解决这个问题的步骤:

  1. 注册账户并提供电子邮件地址
    你需要使用以下命令注册账户并提供一个电子邮件地址:

    执行

    acme.sh --register-account -m your-email@example.com

    your-email@example.com 替换为你自己的电子邮件地址。

提示

(base) [root@VM-4-5-centos ~]# acme.sh --register-account -m xxx@qq.com
[Thu Sep 19 09:55:37 CST 2024] No EAB credentials found for ZeroSSL, let's obtain them
[Thu Sep 19 09:55:38 CST 2024] Registering account: https://acme.zerossl.com/v2/DV90
[Thu Sep 19 09:55:41 CST 2024] Registered
[Thu Sep 19 09:55:41 CST 2024] ACCOUNT_THUMBPRINT='wFp3y1PHfKcEmoUgyezlvb4F_ykEBaOo1-lrVChd-qk'

继续执行

acme.sh --issue -d cctvcloud.cn --nginx

返回

(base) [root@VM-4-5-centos ~]# acme.sh --issue -d cctvcloud.cn --nginx
[Thu Sep 19 10:06:03 CST 2024] Using CA: https://acme.zerossl.com/v2/DV90
[Thu Sep 19 10:06:03 CST 2024] Creating domain key
[Thu Sep 19 10:06:03 CST 2024] The domain key is here: /root/.acme.sh/cctvcloud.cn_ecc/cctvcloud.cn.key
[Thu Sep 19 10:06:03 CST 2024] Single domain='cctvcloud.cn'
[Thu Sep 19 10:06:07 CST 2024] Getting webroot for domain='cctvcloud.cn'
[Thu Sep 19 10:06:07 CST 2024] Verifying: cctvcloud.cn
[Thu Sep 19 10:06:07 CST 2024] Nginx mode for domain: cctvcloud.cn
[Thu Sep 19 10:06:07 CST 2024] Cannot find nginx config.
[Thu Sep 19 10:06:07 CST 2024] Please add '--debug' or '--log' to see more information.
[Thu Sep 19 10:06:07 CST 2024] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh

提示说的是无法找到nginx配置文件

既然无法找到nginx,我们就指定网站目录

(base) [root@VM-4-5-centos ~]# acme.sh --issue -d cctvcloud.cn --webroot /var/www/typecho
[Thu Sep 19 10:20:45 CST 2024] Using CA: https://acme.zerossl.com/v2/DV90
[Thu Sep 19 10:20:45 CST 2024] Single domain='cctvcloud.cn'
[Thu Sep 19 10:20:49 CST 2024] Getting webroot for domain='cctvcloud.cn'
[Thu Sep 19 10:20:49 CST 2024] Verifying: cctvcloud.cn
[Thu Sep 19 10:20:50 CST 2024] Processing. The CA is processing your order, please wait. (1/30)
[Thu Sep 19 10:20:55 CST 2024] Success
[Thu Sep 19 10:20:55 CST 2024] Verification finished, beginning signing.
[Thu Sep 19 10:20:55 CST 2024] Let's finalize the order.
[Thu Sep 19 10:20:55 CST 2024] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/3dV2Srpyf2CunpCNYC7wMA/finalize'
[Thu Sep 19 10:20:57 CST 2024] Order status is 'processing', let's sleep and retry.
[Thu Sep 19 10:20:57 CST 2024] Sleeping for 15 seconds then retrying
[Thu Sep 19 10:21:13 CST 2024] Polling order status: https://acme.zerossl.com/v2/DV90/order/3dV2Srpyf2CunpCNYC7wMA
[Thu Sep 19 10:21:14 CST 2024] Downloading cert.
[Thu Sep 19 10:21:14 CST 2024] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/VuY8VcXb159DjfIlfvif4g'
[Thu Sep 19 10:21:16 CST 2024] Cert success.
-----BEGIN CERTIFICATE-----
xxxxx
-----END CERTIFICATE-----
[Thu Sep 19 10:21:16 CST 2024] Your cert is in: /root/.acme.sh/cctvcloud.cn_ecc/cctvcloud.cn.cer
[Thu Sep 19 10:21:16 CST 2024] Your cert key is in: /root/.acme.sh/cctvcloud.cn_ecc/cctvcloud.cn.key
[Thu Sep 19 10:21:16 CST 2024] The intermediate CA cert is in: /root/.acme.sh/cctvcloud.cn_ecc/ca.cer
[Thu Sep 19 10:21:16 CST 2024] And the full-chain cert is in: /root/.acme.sh/cctvcloud.cn_ecc/fullchain.cer
(base) [root@VM-4-5-centos ~]# client_loop: send disconnect: Broken pipe

提示证书生成成功

copy/安装 证书

前面证书生成以后, 接下来需要把证书 copy 到真正需要用它的地方.

注意, 默认生成的证书都放在安装目录下: ~/.acme.sh/, 请不要直接使用此目录下的文件, 例如: 不要直接让 nginx/apache 的配置文件使用这下面的文件. 这里面的文件都是内部使用, 而且目录结构可能会变化.

正确的使用方法是使用 --install-cert 命令,并指定目标位置, 然后证书文件会被copy到相应的位置, 例如:

acme.sh --install-cert -d example.com \
--key-file       /path/to/keyfile/in/nginx/key.pem  \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd     "service nginx force-reload"

重新访问网站,结果正确,已经换到最近3个月的证书有效期,然后我们设置定时任务来完成自动化。自动化的操作主要2个

  1. 申请下载证书
  2. 复制证书到nginx目录
  3. 重启nginx

这是我的脚本

#!/bin/bash

# 触发 acme.sh 续期任务
/root/.acme.sh/acme.sh --cron --home "/root/.acme.sh"

# 复制证书到网站目录
cp /root/.acme.sh/cctvcloud.cn_ecc/fullchain.cer /usr/nginx/certificates/cctvcloud.cn_bundle.crt
cp /root/.acme.sh/cctvcloud.cn_ecc/cctvcloud.cn.key /usr/nginx/certificates/cctvcloud.cn.key

# 重新加载 Nginx 配置
service nginx force-reload

设置定时任务

0 0 * * * /path/to/renew_cert.sh > /dev/null 2>&1

每天晚上0点执行,并且不输出任何信息。

这样就完成了nginx自动,免费申请部署https证书

网站访问www发现刚刚申请证书的时候,忘记添加www域名了,带www跟不带是2个域名,这里重新申请

acme.sh --issue -d cctvcloud.cn -d www.cctvcloud.cn --nginx

再执行安装重启,完成

acme.sh --install-cert -d example.com \
--key-file       /path/to/keyfile/in/nginx/key.pem  \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd     "service nginx force-reload"

当然这个是自己基于acme.sh 属于偏底层自动申请, 因为申请证书实在太麻烦,有些公司还封装了集成度更高的工具,例如baidu公司的产品Certbot

### 安装Certbot

Certbot支持多种操作系统和Web服务器,你可以在其官方网站上找到适合自己环境的安装指南。例如,对于使用Ubuntu和Nginx的服务器,可以使用以下命令安装Certbot:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

获取证书

sudo certbot certonly --webroot -w /var/www/html

配置nginx 替换证书,然后设置定时申请功能,跟acme.sh 是一个原理。