【玩转 Postman 接口测试与开发2_018】第14章:利用 Postman 初探 API 安全测试

news2025/2/8 15:05:53

book cover for the 2nd version

《API Testing and Development with Postman》最新第二版封面

文章目录

  • 第十四章 API 安全测试
    • 1 OWASP API 安全清单
      • 1.1 相关背景
      • 1.2 OWASP API 安全清单
      • 1.3 认证与授权
      • 1.4 破防的对象级授权(Broken object-level authorization)
      • 1.5 破防的属性级授权(Broken property-level authorization)
      • 1.6 不受控制的资源消耗(Unrestricted resource consumption)
      • 1.7 不受限制地访问业务流(Unrestricted access to business workflows)
      • 1.8 不安全地使用 API 接口(Unsafe consumption of APIs)
    • 2 模糊测试(Fuzzy)
      • 2.1 相关概念
      • 2.2 实战:在 Postman 中执行模糊测试
      • 2.3 绕开 Collection Runner 的测试方案
    • 3 利用 Postman 内置随机变量实现模糊测试
    • 4 小结

写在前面
本章为全书的倒数第二章,作者简要介绍了 API 安全测试的相关概念,并对 OWASP API 安全清单和模糊测试(Fuzzy Testing)进行了重点讲解;后半部分作者利用数据驱动测试演示了模糊测试在 Postman 中的具体应用,只可惜在实现方案和叙述的条理性上较为敷衍,导致我在实测过程中又踩了不少坑。特此梳理出来,既是对自己创新方案的复盘,也能让更多后来者少走弯路。

第十四章 API 安全测试

本章概要

  • OWASP API 安全清单
  • Postman 进行模糊测试(Fuzz testing)的方法

1 OWASP API 安全清单

1.1 相关背景

  • OWASP(Open Web Application Security Project)是一个非营利组织,专注于提高软件安全性;
  • 提供免费、开放的资源,如工具、文档、论坛等,帮助开发者和安全人员构建安全的应用程序;
  • 知名项目包括 OWASP Top 10(十大 Web 应用安全风险)和 API Security Top 10(API安全十大风险);
  • 相关资源:
    • 网站门户:https://owasp.org/;
    • 2023 最新版 API 安全清单:https://owasp.org/www-project-api-security/;

1.2 OWASP API 安全清单

  • API Security Top 10 是 OWASP 针对 API 安全的核心文档,罗列了 API 面临的十大安全风险。
  • 适用于开发者、安全工程师和架构师,帮助识别和缓解API安全威胁。

1.3 认证与授权

黑客最先尝试的攻击方式是身份验证,即通过用户名密码攻击。

最简单的方式是暴力破解(brute-force attack),因此 API 接口应采取在一定时间段内 限制登录次数 的防护措施。

具体实现:以 GitPod 演示项目为例,可利用 Postman 内置的随机数据变量高频多次调用登录接口(多次手动点击或 Collection Runner 设置迭代次数):

测试脚本:

for (let i = 0, len = 50; i < len; i++) {
  pm.sendRequest(
    {
      url: pm.variables.replaceIn('{{base_url}}/token'),
      method: 'POST',
      header: { 
        'Content-Type': 'multipart/form-data'
      },
      body: {
        mode: "formdata",
        formdata: [
          { key: 'username', value: pm.variables.replaceIn('{{$randomUserName}}') },
          { key: 'password', value: pm.variables.replaceIn('{{$randomPassword}}') }
        ]
      }
    },
    function (err, resp) {
      if (err) {
        console.error(JSON.parse(err));
        return;
      }
      pm.test(`${i + 1}: Response JSON have detail attribute`, function () {
        pm.expect(resp.json()).to.eql({ "detail": "Incorrect user name or password" });
      });
    }
  )
}

实测结果(鉴权接口疑似不具备限制登录次数功能):

图 14.1 构造不同的用户名和密码,多次高频调用登录接口,模拟暴力破解过程

【图 14.1 构造不同的用户名和密码,多次高频调用登录接口,模拟暴力破解过程】

1.4 破防的对象级授权(Broken object-level authorization)

这是 2023 年十大安全清单排名第一的高风险议题:

  • 问题描述:未正确验证用户对对象的访问权限,导致越权访问。
  • 应对措施:实施严格的权限验证,确保用户只能访问授权资源。
  • 示例:用登录普通用户(user1/12345)的登录令牌去访问管理员帐号,看看示例项目是否会响应 403 错误。

实测结果:

图 14.2 用 user1 的登录令牌访问管理员 admin 的帐号信息,后台报 403 错误(符合预期)

【图 14.2 用 user1 的登录令牌访问管理员 admin 的帐号信息,后台报 403 错误(符合预期)】

1.5 破防的属性级授权(Broken property-level authorization)

示例:用 user1/12345 登录,先用 "user1" 为创建人(即 create_by 字段)添加一个正常的待办项,然后看看是否可以通过 PUT 请求篡改该创建人信息(例如改为 "user2")。

测试脚本:

// PUT request's Post-response
pm.collectionVariables.set('reqPut', pm.request);

// Pre-request
pm.sendRequest(
  pm.collectionVariables.get('reqPut'),
  function(err, resp) {
    if(err) {
      console.error('Updated failure:', err);
      return;
    }
    pm.test('PUT req: status code should be 200', () => {
      console.log(resp)
      pm.expect(resp.code).to.eq(200);
    });
  }
)

// Post-response
pm.test('The creator should not be updated (user1) after running PUT req',
  () => {
    const [{ created_by: creator }] = pm.response.json();
    pm.expect(creator).to.eql('user1')
  });

实测结果:

图 14.3 实测属性级授权漏洞(篡改失败,符合预期)

【图 14.3 实测属性级授权漏洞(篡改失败,符合预期)】

但实测发现,在创建待办项时人为设置创建人为 非当前登录用户(如 "user2"),最后仍然创建成功了,说明该接口还是有问题的:

图 14.4 创建任务时篡改创建人信息,最终任务创建成功,说明该接口仍然支持篡改信息

【图 14.4 创建任务时篡改创建人信息,最终任务创建成功,说明该接口仍然支持篡改信息】

1.6 不受控制的资源消耗(Unrestricted resource consumption)

方式一:通过耗尽所有系统资源来损害系统,导致系统瘫痪(denial-of-service attacks,拒绝服务攻击);

方式二:由于未对接口调用次数进行限制,大量请求将拖慢响应速度;如果接口调用了第三方付费资源,还会产生大量费用。

1.7 不受限制地访问业务流(Unrestricted access to business workflows)

攻击者可能会利用抓包、监控请求数据等方式获取系统内部通信 API,从而获悉内部工作流结构,给系统带来严重威胁(例如恶意逃票等)。

应对措施:仔细考虑暴露了哪些接口;严格控制接口访问权限。

1.8 不安全地使用 API 接口(Unsafe consumption of APIs)

典型案例:引用了被黑客攻击的第三方 API。

这类测试较为棘手,可能需要搭建一个模拟服务器,让从第三方 API 响应的数据在该模拟器上先行缓冲,或者模拟危险数据进行测试,看看本地后台是否能够鉴别该类数据。

2 模糊测试(Fuzzy)

2.1 相关概念

定义:模糊测试(Fuzzy) 是一种通过向程序提供无效、随机或意外的输入来发现漏洞和错误的测试技术。

主要特征:

  • 非通用测试技术
  • 有助于发现未考虑到、或未测试到的问题

具体的运行方式:

  • 手动执行:通过在 UI 中输入伪随机数据来完成(极少);
  • 编程执行:以程序的形式运行(绝大多数)。工具如 PeachFuzzer 或自定义输入集。

输入的生成:

  • 生成大量随机或半随机数据,可能包含格式错误或危险字符(如转义字符、引号等)。
  • 输入通常是随机的,但有一些边界限制(例如,字节 vs ASCII/Unicode 字符串)。
  • 输入可以偏向已知的“危险”字符(例如转义字符、引号等)。

输入内容的具体方式:

  • 通过命令行参数注入
  • 通过文件输入
  • 通过网络协议
  • 通过 API 输入(特别适合模糊测试,易于用程序控制)

模糊查询的应用场景:

  • 安全测试场景:揭示未能预见的攻击方向,发现错误处理机制中的薄弱环节等;
  • API 测试场景:具有易于访问且数量巨大的测试输入,尤其适合 API 测试。

2.2 实战:在 Postman 中执行模糊测试

GitHub 开源项目 Big List of Naughty StringsJSON 文件为数据源,利用 Collection RunnerGitPod 演示项目 ToDo List App 进行基于数据驱动的模糊测试,看看 POST /tasks 接口在大量随机输入下的响应情况。

首先从开源项目下载原始数据文件 blns.base64.json。该原始数据为 Base64 编码的字符串数组:

[
  "", 
  "dW5kZWZpbmVk", 
  "dW5kZWY=", 
  "bnVsbA==", 
  ...
]

使用前需要先处理成如下格式(可使用 vim 宏的批量操作完成):

[
  {"naughtyString":""}, 
  {"naughtyString":"dW5kZWZpbmVk"}, 
  {"naughtyString":"dW5kZWY="}, 
  {"naughtyString":"bnVsbA=="}, 
  ...
]

然后创建测试集合 FuzzyTest 以及 POST 请求 Create a task,其 URL 设置为 {{base_url}}/tasks,其中 base_url 为集合变量,其值为 GitPod 演示项目的基础 URL(启动链接:https://gitpod.io/new/#https://github.com/djwester/todo-list-testing)。

接着,在测试请求的请求体中输入如下内容(这里有个大坑,后面会讲):

{
  "description": "{{naughtyString}}",
  "status": "Draft"
}

上述代码中的 naughtyString 为数据驱动测试启动后、经 Pre-request 脚本处理得到的动态变量:

const atob = require('atob');
const encoded_string = pm.iterationData.get("naughtyString");
pm.collectionVariables.set('naughtyString', atob(encoded_string));

对应的 Post-response 响应后脚本如下:

pm.test("Status code is 201", function() {
    pm.response.to.have.status(201);
});

一切准备就绪后,启动 Collection Runner,加载 JSON 映射文件,执行模糊测试:

图 14.5 利用 Collection Runner,发起基于JSON 文件数据驱动的模糊测试

【图 14.5 利用 Collection Runner,发起基于JSON 文件数据驱动的模糊测试】

由于是分别读取每行数据并调用创建接口,整个过程需要多等些时间,最终得到结果:

图 14.6 Collection Runner 运行结束后的实测截图

【图 14.6 Collection Runner 运行结束后的实测截图】

由于作者演示时用的是本地部署的 ToDo List App,全套数据测完只用了 1'14",和我实测时的 23'56" 真是天壤之别(没办法,Python 基础有限,几次尝试本地部署都失败了)。但奇怪的是,除了 10 个请求因为网络原因发送失败,其余 666 个都成功了,并没有报错。

可高兴不到一分钟,我就知道出问题了。作者并没有交代要用 user2 登录,而我新增任务前压根儿就没登录,导致后续的数据清空全部失败了:

图 14.7 由于新增任务时没有登录,导致后续的批量删除全部失败(神坑)

【图 14.7 由于新增任务时没有登录,导致后续的批量删除全部失败(神坑)】

没办法,只能重置项目,重新来过……

Ctrl + C 中断 GitPod 项目,运行重置数据命令 poetry run python remove_tables.py,然后执行 make run-dev 重新启动。

这次先用 user2/12345 换取登录令牌,再到新增接口中完成鉴权:

图 14.8 用 user2 的登录令牌完成新增接口的鉴权设置

【图 14.8 用 user2 的登录令牌完成新增接口的鉴权设置】

然后只选取新增接口,再次上传 JSON 数据集运行 Collection Runner

图 14.9 重新运行 Collection Runner 的配置界面截图

【图 14.9 重新运行 Collection Runner 的配置界面截图】

也不知道是不是这份死磕精神感动了马克思,第二次运行居然全部成功了:

图 14.10 第二次运行结果截图(676 条数据全部新增成功)

【图 14.10 第二次运行结果截图(676 条数据全部新增成功)】

接着在浏览器查看项目首页,也没有书中说的 alert 注入问题(当真欧皇附体?):

img14.11

借着这波好运,赶紧再跑一遍数据批量清空。在 GET {{base_url}}/task 接口的响应后脚本中输入以下内容(直接用 JS 脚本批量删除,书中方法太过陈旧,还得再消耗一次 Collection Runner 免费额度,不知道作者怎么想的):

const tasks = pm.response.json();
const task_ids = tasks.map(t => t.id);

const base_url = pm.collectionVariables.get('base_url');
const auth = {
  type: 'bearer',
  bearer: [{
    key: 'token',
    value: pm.collectionVariables.replaceIn('{{token}}'),
    type: 'string'
  }]
};
const getCallback = task_id => (err, response) => {
  if(err) {
    console.error(err);
    return;
  }
  pm.test(`Deleting id(${task_id}): Status should be OK`, function() {
    pm.expect(response.status).to.eql('OK');
  });
};

for(const id of task_ids) {
  // Delete the task by id
  pm.sendRequest({
    url: `${base_url}/tasks/${id}`,
    method: 'DELETE',
    auth
  }, getCallback(id));
}

结果还是报错:

img14.12

仔细一想,真相大白了:新增接口必须在请求体中手动指定 created_by 字段,否则 一律按匿名处理(就当是作者故意挖的坑吧)。

只有再重来一遍了:

img14.13

再次执行批量删除,只有一次是后台原因删除失败,五次请求未发送,其余全部删除成功,终于熬出头了:

img14.14

2.3 绕开 Collection Runner 的测试方案

其实只要具备 JavaScript 基础,完全可以跳过 Collection Runner 的限制,在 Pre-request / Post-response 脚本中实现批量新增和删除。

批量新增的纯 JS 脚本实现:

  1. 将原始 JSON 数据集不经任何处理直接放到 Postman 的私有模块中,例如 my-blns

    const data = [
      "", 
      "dW5kZWZpbmVk", 
      "dW5kZWY=", 
      "bnVsbA==", 
      "TlVMTA==", 
      "KG51bGwp", 
      // ...
      "e3sgIiIuX19jbGFzc19fLl9fbXJvX19bMl0uX19zdWJjbGFzc2VzX18oKVs0MF0oIi9ldGMvcGFz",
      "c3dkIikucmVhZCgpIH19"
    ];
    module.exports = {
        data
    };
    
  2. 新建请求 GET {{base_url}}/tasks,用于在批量新增后查询总的待办项列表:

    1. Pre-request 中输入以下脚本:
    const atob = require('atob');
    const { data } = pm.require('your/package/path/to/my-blns');
    // console.log(data.length);
    
    const postRequest = description => ({
      url: pm.collectionVariables.replaceIn('{{base_url}}/tasks'),
      method: 'POST',
      header: { 'Content-Type': 'application/json' },
      body: {
        mode: 'raw',
        raw: JSON.stringify({
          description,
          status: "Draft",
          created_by: "user2"
        })
      }
    });
    
    data.map(d => atob(d))
      .map((description, i) => pm.sendRequest(
        postRequest(description), 
        (err, resp) => {
          if(err) {
            console.error(err);
            return;
          }
          pm.test(`Create task_${i+1} completed: the status code should be 201`,
            () => pm.expect(resp.code).to.eql(201));
        }
      ));
    
    1. Post-response 输入以下脚本:

      pm.test('Task list length should be greater than 0', function () {
           pm.expect(pm.response.json())
               .to.be.an('array')
               .and
               .to.have.lengthOf.at.least(1, "Task list length should be greater than 0");
      });
      
  3. 至于批量删除,刚才实测过程中已经看过脚本了,这里只说明一下实现逻辑。利用列表查询接口 GET {{base_url}}/tasks 获取到任务列表后,批量提取任务列表的 id;然后分别调用 DELETE 接口 POST {{base_url}}/tasks/:id 完成删除(注意:删除待办项时,别忘了在请求中带上鉴权配置对象 auth)。

这样就可以在 Postman 中随意批量新增和删除待办任务了,完全不受 Collection Runner 的制约。

3 利用 Postman 内置随机变量实现模糊测试

其实就是将上传的 JSON 文件内容用 Postman 内置的各种随机变量实现同样的模糊测试效果,例如将新增接口请求体中的 JSON 改为:

{
    "description": "{{$randomLoremSentence}}",
    "status": "Draft",
    "created_by": "user2"
}

或者借助测试脚本,引入 lodash 实现更多模糊测试效果:

const _ = require('lodash');
// _.sample(collection): Gets a random element from collection.
const description = _.sample(["{{$randomAbbreviation}}", "{{$randomAdjective}}"]);
const jsonBody = {
    description,
    "status", "Draft",
    "created_by": "user2"
}

4 小结

本章内容整体感觉较敷衍,上半部分介绍相关概念几乎全是蜻蜓点水式的描述,后半段实战环节的条理性又明显不如前面的章节,漏掉很多关键细节,且在方案选择上过分依赖 Collection Runner,致使我在实测过程中浪费了不少免费额度。不过依次填完这些坑后,我也有机会用纯 JavaScript 脚本的方式实现待办任务的批量创建与删除,顺便学习了用 pm.sendRequest() 发送 POST 请求和 DELETE 请求的写法,也算是因祸得福了吧。

后记
最后再跟大家分享个操作技巧,遇到不会写的 Postman 脚本,可以利用其自带的 AI 机器人 Postbot 直接给答案。本章实测中几种 pm.sendRequest() 的写法就是这么来的,比查官方文档快多了。大家一定要学会使用 AI 工具,千万不要故步自封,成为 AI 时代的 “新文盲”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2294827.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

攻防世界baigeiRSA

打开题目附件 import libnum from Crypto.Util import number from secret import flagsize 128 e 65537 p number.getPrime(size) q number.getPrime(size) n p*qm libnum.s2n(flag) c pow(m, e, n)print(n %d % n) print(c %d % c)n 8850300144784503160345704866…

[NKU]C++安装环境 VScode

bilibili安装教程 vscode 关于C/C的环境配置全站最简单易懂&#xff01;&#xff01;大学生及初学初学C/C进&#xff01;&#xff01;&#xff01;_哔哩哔哩_bilibili 1安装vscode和插件 汉化插件 ​ 2安装插件 2.1 C/C 2.2 C/C Compile run ​ 2.3 better C Syntax ​ 查看已…

Node.js 环境配置

什么是 Node.js Node.js 是一个基于 Chrome V8 JavaScript 引擎的 JavaScript 运行时环境&#xff0c;它允许你在服务器端运行 JavaScript。传统上&#xff0c;JavaScript 主要用于浏览器中的前端开发&#xff0c;而 Node.js 使得 JavaScript 也能够在服务器上执行&#xff0c;…

1Panel应用推荐:WordPress开源博客软件和内容管理系统

1Panel&#xff08;github.com/1Panel-dev/1Panel&#xff09;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;它致力于通过开源的方式&#xff0c;帮助用户简化建站与运维管理流程。为了方便广大用户快捷安装部署相关软件应用&#xff0c;1Panel特别开通应用商店&am…

DMZ区的作用和原则

DMZ&#xff08;Demilitarized Zone&#xff0c;非军事化区&#xff09;是网络安全架构中一个重要的概念&#xff0c;其主要作用和原则如下&#xff1a; DMZ的作用 隔离风险 DMZ作为内外网络之间的缓冲区&#xff0c;能够有效隔离外部网络的攻击风险。将对外提供服务的服务器&…

如何将本地 Node.js 服务部署到宝塔面板:完整的部署指南

文章简介&#xff1a; 将本地开发的 Node.js 项目部署到线上服务器是开发者常见的工作流程之一。在这篇文章中&#xff0c;我将详细介绍如何将本地的 Node.js 服务通过宝塔面板&#xff08;BT 面板&#xff09;上线。宝塔面板是一个强大的服务器管理工具&#xff0c;具有简洁的…

4.3 线性回归的改进-岭回归/4.4分类算法-逻辑回归与二分类/ 4.5 模型保存和加载

4.3.1 带有L2正则化的线性回归-岭回归 岭回归&#xff0c;其实也是一种线性回归&#xff0c;只不过在算法建立回归方程的时候1&#xff0c;加上正则化的限制&#xff0c;从而达到解决过拟合的效果 4.3.1.1 API 4.3.1.2 观察正则化程度的变化&#xff0c;对结果的影响 正则化力…

Mac 部署Ollama + OpenWebUI完全指南

文章目录 &#x1f4bb; 环境说明&#x1f6e0;️ Ollama安装配置1. 安装[Ollama](https://github.com/ollama/ollama)2. 启动Ollama3. 模型存储位置4. 配置 Ollama &#x1f310; OpenWebUI部署1. 安装Docker2. 部署[OpenWebUI](https://www.openwebui.com/)&#xff08;可视化…

工业物联网平台-视频识别视频报警新功能正式上线

前言 视频监控作为中服云工业物联网平台4.0的功能已经上线运行。已为客户服务2年有余&#xff0c;为客户提供多路视频、实时在线监视和控制能力。服务客户实时发现现场、产线、设备出现随机故障、事故等&#xff0c;及时到场处理维修。 视频识别&视频报警新功能当前正式上…

mysql的cpu使用率100%问题排查

背景 线上mysql服务器经常性出现cpu使用率100%的告警&#xff0c; 因此整理一下排查该问题的常规流程。 1. 确认CPU占用来源 检查系统进程 使用 top 或 htop 命令&#xff0c;确认是否是 mysqld 进程导致CPU满载&#xff1a;top -c -p $(pgrep mysqld)2. 实时分析MySQL活动 …

qt6.8安装mysql8.0驱动

qt6.8安装mysql8.0驱动 qt6.8本身是不带mysql驱动。想要在qt里面使用mysql,还是比较麻烦的。需要自己编译驱动 首先下载qt源码&#xff0c;链接Index of /archive/qt/6.8/6.8.1/single 下载mysql对于驱动文件&#xff0c;链接是MySQL :: Download MySQL Connector/C (Archiv…

π0开源了且推出自回归版π0-FAST——打造机器人动作专用的高效Tokenizer:比扩散π0的训练速度快5倍但效果相当

前言 过去的半个多月 对于大模型 deepseek火爆全球&#xff0c;我对其的解读也写成了整整一个系列 详见《火爆全球的DeepSeek系列模型》&#xff0c;涉及对GRPO、MLA、V3、R1的详尽细致深入的解读 某种意义来讲&#xff0c;deepseek 相当于把大模型的热度 又直接拉起来了——…

【算法篇】贪心算法

目录 贪心算法 贪心算法实际应用 一&#xff0c;零钱找回问题 二&#xff0c;活动选择问题 三&#xff0c;分数背包问题 将数组和减半的最小操作次数 最大数 贪心算法 贪心算法&#xff0c;是一种在每一步选择中都采取当前状态下的最优策略&#xff0c;期望得到全局最优…

《金字塔原理》笔记

金字塔原理一书的原理是关于结构化写作的&#xff0c;里面提出一个MECE法则&#xff1a;各个分论点之间要“相互独立、完全穷尽”。 我的总结 写作思路都是总分总。 要凝练最顶部的信息&#xff0c;然后按照三叉树&#xff08;最多四叉树&#xff09;一直分下去。 书中优雅的…

蓝桥杯准备 【入门3】循环结构

素数小算法&#xff08;埃氏筛&&欧拉筛&#xff09; 以下四段代码都是求20以内的所有素数 1.0版求素数 #include<iostream> using namespace std;int main() {int n 20;for(int i2;i<n;i){int j0;for(j2;j<i;j)//遍历i{if(i%j0){break;}}if(ij){cout&l…

MySQL三大日志——binlog、redoLog、undoLog详解

日志是mysql数据库的重要组成部分&#xff0c;记录着数据库运行期间各种状态信息&#xff0c;能帮助我们进行很多容错及分析工作&#xff0c;其中有三大日志与我们这些开发者息息相关&#xff0c;本文将介绍binlog、redoLog、undoLog三种日志&#xff1a; 1. redoLog 1.1 为什么…

SpringAI系列 - 使用LangGPT编写高质量的Prompt

目录 一、LangGPT —— 人人都可编写高质量 Prompt二、快速上手2.1 诗人 三、Role 模板3.1 Role 模板3.2 Role 模板使用步骤3.3 更多例子 四、高级用法4.1 变量4.2 命令4.3 Reminder4.4 条件语句4.5 Json or Yaml 方便程序开发 一、LangGPT —— 人人都可编写高质量 Prompt La…

springboot+vue导入ruoyi项目的框架

一、介绍 RuoYi-Vue版本&#xff0c;采用了前后端分离的单体架构设计软件环境&#xff1a;JDK、Mysql、Redis、Maven、Node技术选型: Spring Boot、Spring Security、MyBatis、Jwt、Vue3、Element-Plus官方地址: https://gitee.com/y_project/RuoYi-Vue 官方推荐的版本如下&a…

Conmi的正确答案——Rider中添加icon作为exe的图标

C#版本&#xff1a;.net 8.0 Rider版本&#xff1a;#RD-243.22562.250&#xff08;非商业使用版&#xff09; 1、添加图标到解决方案下&#xff1a; 2、打开“App.xaml”配置文件&#xff0c;添加配置&#xff1a; <Applicationx:Class"ComTransmit.App"xmlns&q…

360手机刷机 360手机解Bootloader 360手机ROOT

360手机刷机 360手机解Bootloader 360手机ROOT 问&#xff1a;360手机已停产&#xff0c;现在和以后&#xff0c;能刷机吗&#xff1f; 答&#xff1a;360手机&#xff0c;是肯定能刷机的 360手机资源下载网站 360手机-360手机刷机RootTwrp 360os.top 360rom.github.io 一、…