当前位置: 首页 > news >正文

trivy os软件包扫描原理分析

具体可以基于之前的博客来做

基于trivy获取基础镜像

参数修改一下:

cliOpt.ListAllPkgs = true

结果中会带有如下格式的结果:

   "Results":[{"Target":"192.168.1.94:443/test22/centos:7 (centos 7.9.2009)","Class":"os-pkgs","Type":"centos","Packages":[{"ID":"acl@2.2.51-15.el7.x86_64","Name":"acl","Version":"2.2.51","Release":"15.el7","Arch":"x86_64","SrcName":"acl","SrcVersion":"2.2.51","SrcRelease":"15.el7","Licenses":["GPLv2+"],"Maintainer":"CentOS","DependsOn":["glibc@2.17-317.el7.x86_64","libacl@2.2.51-15.el7.x86_64","libattr@2.4.46-13.el7.x86_64"],"Layer":{"DiffID":"sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02"},"Type":"rpm"},{"ID":"audit-libs@2.8.5-4.el7.x86_64","Name":"audit-libs","Version":"2.8.5","Release":"4.el7","Arch":"x86_64","SrcName":"audit","SrcVersion":"2.8.5","SrcRelease":"4.el7","Licenses":["LGPLv2+"],"Maintainer":"CentOS","DependsOn":["glibc@2.17-317.el7.x86_64","libcap-ng@0.7.5-4.el7.x86_64"],"Layer":{"DiffID":"sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02"},"Type":"rpm"},
......

其中的原理就是根据对应的软件包信息文件来读取。前面的调用路径与基于trivy获取基础镜像一致。都是通过analyzer.RegisterAnalyzer函数将自己注册进analyzers的map中。最后就可以去获取镜像的软件包列表。

os的软件包代码都在pkg/fanal/analyzer/pkg/中。这里面有三个目录apk、dpkg、rpm。它们分别对应于alpine、ubuntu(debian)、centos操作系统。

我们以ubuntu为例来分析。系统启动时,会将dpkg分析器注册进来。代码如下:

func init() {analyzer.RegisterAnalyzer(&dpkgAnalyzer{})
}

根据前面关于基础镜像的博客,我们知道,只有Required返回成功才会进行分析。所以我们先看这个函数的代码:

const (analyzerVersion = 3statusFile = "var/lib/dpkg/status"statusDir  = "var/lib/dpkg/status.d/"infoDir    = "var/lib/dpkg/info/"
)
......func (a dpkgAnalyzer) Required(filePath string, _ os.FileInfo) bool {dir, fileName := filepath.Split(filePath)if a.isListFile(dir, fileName) || filePath == statusFile {return true}if dir == statusDir {return true}return false
}

主要逻辑就是通过检查当前文件是否是var/lib/dpkg/status或者当前为目录的话,就判定是否是var/lib/dpkg/status.d。很明显,这里考虑了一个问题,镜像中的文件是占大多数的,所以先检查文件名是否相同,对性能会好点。匹配成功返回true。

如果成功,就会进入Analyze函数。源码如下:

func (a dpkgAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {scanner := bufio.NewScanner(input.Content)if a.isListFile(filepath.Split(input.FilePath)) {return a.parseDpkgInfoList(scanner)}return a.parseDpkgStatus(input.FilePath, scanner)
}

如果是文件,则调用parseDpkgInfoList函数去解析软件包,如果是目录,则调用parseDpkgStatus,具体代码我们往下看。

parseDpkgInfoList函数:

// parseDpkgStatus parses /var/lib/dpkg/info/*.list
func (a dpkgAnalyzer) parseDpkgInfoList(scanner *bufio.Scanner) (*analyzer.AnalysisResult, error) {var installedFiles []stringvar previous stringfor scanner.Scan() {//一行一行的读取current := scanner.Text()if current == "/." {continue}// Add the file if it is not directory.// e.g.//  /usr/sbin//  /usr/sbin/tarcat//// In the above case, we should take only /usr/sbin/tarcat since /usr/sbin is a directoryif !strings.HasPrefix(current, previous+"/") {//这里去除了目录信息,将所有文件都加入到切片中installedFiles = append(installedFiles, previous)}previous = current}// Add the last fileinstalledFiles = append(installedFiles, previous)if err := scanner.Err(); err != nil {return nil, xerrors.Errorf("scan error: %w", err)}return &analyzer.AnalysisResult{SystemInstalledFiles: installedFiles,}, nil
}
parseDpkgStatus函数:

// parseDpkgStatus parses /var/lib/dpkg/status or /var/lib/dpkg/status/*
//这里注释说明数据来源,我们以/var/lib/dpkg/status为例,来分析下面的代码,数据格式在下方有展示
func (a dpkgAnalyzer) parseDpkgStatus(filePath string, scanner *bufio.Scanner) (*analyzer.AnalysisResult, error) {var pkg *types.Packagepkgs := map[string]*types.Package{}//创建一个临时的package map,key为通过软件名和版本构成的IDpkgIDs := map[string]string{}//以软件名为key,ID为value的mapfor scanner.Scan() {line := strings.TrimSpace(scanner.Text())if line == "" {//软件包的信息以空行结束,如果遇到空行说明当前软件包的解析结束,跳过,为下一个解析做好准备continue}pkg = a.parseDpkgPkg(scanner)//重点在这个函数中,开始解析软件包if pkg != nil {pkgs[pkg.ID] = pkgpkgIDs[pkg.Name] = pkg.ID}}if err := scanner.Err(); err != nil {return nil, xerrors.Errorf("scan error: %w", err)}a.consolidateDependencies(pkgs, pkgIDs)//依赖处理return &analyzer.AnalysisResult{PackageInfos: []types.PackageInfo{{FilePath: filePath,Packages: lo.MapToSlice(pkgs, func(_ string, p *types.Package) types.Package {return *p}),//将结果格式化成切片返回},},}, nil
}

/var/lib/dpkg/status的部分内容

Package: accountsservice
Status: install ok installed
Priority: optional
Section: admin
Installed-Size: 452
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Version: 0.6.55-0ubuntu12~20.04.5
Depends: dbus, libaccountsservice0 (= 0.6.55-0ubuntu12~20.04.5), libc6 (>= 2.4), libglib2.0-0 (>= 2.44), libpolkit-gobject-1-0 (>= 0.99)
Suggests: gnome-control-center
Conffiles:/etc/dbus-1/system.d/org.freedesktop.Accounts.conf 06247d62052029ead7d9ec1ef9457f42
Description: query and manipulate user account informationThe AccountService project provides a set of D-Businterfaces for querying and manipulating user accountinformation and an implementation of these interfaces,based on the useradd, usermod and userdel commands.
Homepage: https://www.freedesktop.org/wiki/Software/AccountsService/
Original-Maintainer: Debian freedesktop.org maintainers <pkg-freedesktop-maintainers@lists.alioth.debian.org>Package: accountsservice-ubuntu-schemas
Status: install ok installed
Priority: optional
Section: gnome
Installed-Size: 44
Maintainer: Ubuntu Desktop Team <ubuntu-desktop@lists.ubuntu.com>
Architecture: all
Multi-Arch: foreign
Source: gsettings-ubuntu-touch-schemas
Version: 0.0.7+17.10.20170922-0ubuntu1
Replaces: accountsservice-ubuntu-touch-schemas (<= 0.0.1+14.04.20140130.1-0ubuntu1), ubuntu-system-settings (<= 0.1+14.04.20140130-0ubuntu1)
Depends: accountsservice
Breaks: accountsservice-ubuntu-touch-schemas (<= 0.0.1+14.04.20140130.1-0ubuntu1), ubuntu-system-settings (<= 0.1+14.04.20140130-0ubuntu1)
Description: AccountsService schemas for Ubuntuaccountsservice-ubuntu-schemas contains a collection of AccountsService vendorextension schemas used by various components of an Ubuntu environment.
Homepage: https://launchpad.net/gsettings-ubuntu-touch-schemasPackage: acl
Status: install ok installed
Priority: optional
Section: utils
Installed-Size: 192
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Multi-Arch: foreign
Version: 2.2.53-6
Depends: libacl1 (= 2.2.53-6), libc6 (>= 2.14)
Description: access control list - utilitiesThis package contains the getfacl and setfacl utilities needed for
......
parseDpkgPkg函数:
func (a dpkgAnalyzer) parseDpkgPkg(scanner *bufio.Scanner) (pkg *types.Package) {var (name          stringversion       stringsourceName    stringdependencies  []stringisInstalled   boolsourceVersion stringmaintainer    string)isInstalled = truefor {line := strings.TrimSpace(scanner.Text())if line == "" {break}switch {case strings.HasPrefix(line, "Package: ")://对照上面的例子,这里就是软件名name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))case strings.HasPrefix(line, "Source: "):// Source line (Optional)// Gives the name of the source package// May also specifies a versionsrcCapture := dpkgSrcCaptureRegexp.FindAllStringSubmatch(line, -1)[0]md := map[string]string{}for i, n := range srcCapture {md[dpkgSrcCaptureRegexpNames[i]] = strings.TrimSpace(n)}sourceName = md["name"]if md["version"] != "" {sourceVersion = md["version"]}case strings.HasPrefix(line, "Version: ")://版本version = strings.TrimPrefix(line, "Version: ")case strings.HasPrefix(line, "Status: "):isInstalled = a.parseStatus(line)case strings.HasPrefix(line, "Depends: ")://依赖dependencies = a.parseDepends(line)case strings.HasPrefix(line, "Maintainer: ")://维护者maintainer = strings.TrimSpace(strings.TrimPrefix(line, "Maintainer: "))}if !scanner.Scan() {break}}if name == "" || version == "" || !isInstalled {return nil} else if !debVersion.Valid(version) {log.Logger.Warnf("Invalid Version Found : OS %s, Package %s, Version %s", "debian", name, version)return nil}pkg = &types.Package{ID:         a.pkgID(name, version),Name:       name,Version:    version,DependsOn:  dependencies, // Will be consolidated laterMaintainer: maintainer,}//将解析结果保存到pkg中,// Source version and names are computed from binary package names and versions// in dpkg.// Source package name:// https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n338// Source package version:// https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n355if sourceName == "" {sourceName = name}if sourceVersion == "" {sourceVersion = version}if !debVersion.Valid(sourceVersion) {log.Logger.Warnf("Invalid Version Found : OS %s, Package %s, Version %s", "debian", sourceName, sourceVersion)return pkg}pkg.SrcName = sourceNamepkg.SrcVersion = sourceVersionreturn pkg
}

然后调用AnalysisResult的Merge函数将PackageInfos合并,继而调用其Sort函数进行排序。然后将结果保存在缓存中,这里是本地缓存。最后在Scanner的ScanArtifact中通过调用s.driver.Scan将结果格式化成types.Results,这里的driver会是local scanner,具体代码如下:


// Scan scans the artifact and return results.
func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys []string, options types.ScanOptions) (types.Results, ftypes.OS, error) {artifactDetail, err := s.applier.ApplyLayers(artifactKey, blobKeys)switch {case errors.Is(err, analyzer.ErrUnknownOS):log.Logger.Debug("OS is not detected.")// Packages may contain OS-independent binary information even though OS is not detected.if len(artifactDetail.Packages) != 0 {artifactDetail.OS = ftypes.OS{Family: "none"}}// If OS is not detected and repositories are detected, we'll try to use repositories as OS.if artifactDetail.Repository != nil {log.Logger.Debugf("Package repository: %s %s", artifactDetail.Repository.Family, artifactDetail.Repository.Release)log.Logger.Debugf("Assuming OS is %s %s.", artifactDetail.Repository.Family, artifactDetail.Repository.Release)artifactDetail.OS = ftypes.OS{Family: artifactDetail.Repository.Family,Name:   artifactDetail.Repository.Release,}}case errors.Is(err, analyzer.ErrNoPkgsDetected):log.Logger.Warn("No OS package is detected. Make sure you haven't deleted any files that contain information about the installed packages.")log.Logger.Warn(`e.g. files under "/lib/apk/db/", "/var/lib/dpkg/" and "/var/lib/rpm"`)case err != nil:return nil, ftypes.OS{}, xerrors.Errorf("failed to apply layers: %w", err)}var eosl boolvar results, pkgResults types.Results// Fill OS packages and language-specific packagesif options.ListAllPackages {//这里就是我们刚开始说的那个标志,如果为true,进行整合if res := s.osPkgsToResult(target, artifactDetail, options); res != nil {pkgResults = append(pkgResults, *res)}pkgResults = append(pkgResults, s.langPkgsToResult(artifactDetail)...)}// Scan packages for vulnerabilitiesif options.Scanners.Enabled(types.VulnerabilityScanner) {var vulnResults types.ResultsvulnResults, eosl, err = s.scanVulnerabilities(target, artifactDetail, options)if err != nil {return nil, ftypes.OS{}, xerrors.Errorf("failed to detect vulnerabilities: %w", err)}artifactDetail.OS.Eosl = eosl// Merge package results into vulnerability resultsmergedResults := s.fillPkgsInVulns(pkgResults, vulnResults)results = append(results, mergedResults...)} else {// If vulnerability scanning is not enabled, it just adds package results.results = append(results, pkgResults...)}// Scan IaC config filesif ShouldScanMisconfigOrRbac(options.Scanners) {configResults := s.MisconfsToResults(artifactDetail.Misconfigurations)results = append(results, configResults...)}// Scan secretsif options.Scanners.Enabled(types.SecretScanner) {secretResults := s.secretsToResults(artifactDetail.Secrets)results = append(results, secretResults...)}// Scan licensesif options.Scanners.Enabled(types.LicenseScanner) {licenseResults := s.scanLicenses(artifactDetail, options.LicenseCategories)results = append(results, licenseResults...)}// Scan misconfigurations on container image configif options.ImageConfigScanners.Enabled(types.MisconfigScanner) {if im := artifactDetail.ImageConfig.Misconfiguration; im != nil {im.FilePath = target // Set the target name to the file path as container image config is not a real file.results = append(results, s.MisconfsToResults([]ftypes.Misconfiguration{*im})...)}}// Scan secrets on container image configif options.ImageConfigScanners.Enabled(types.SecretScanner) {if is := artifactDetail.ImageConfig.Secret; is != nil {is.FilePath = target // Set the target name to the file path as container image config is not a real file.results = append(results, s.secretsToResults([]ftypes.Secret{*is})...)}}// For WASM plugins and custom analyzersif len(artifactDetail.CustomResources) != 0 {results = append(results, types.Result{Class:           types.ClassCustom,CustomResources: artifactDetail.CustomResources,})}for i := range results {// Fill vulnerability detailss.vulnClient.FillInfo(results[i].Vulnerabilities)}// Post scanningresults, err = post.Scan(ctx, results)if err != nil {return nil, ftypes.OS{}, xerrors.Errorf("post scan error: %w", err)}return results, artifactDetail.OS, nil
}
osPkgsToResult代码:
func (s Scanner) osPkgsToResult(target string, detail ftypes.ArtifactDetail, options types.ScanOptions) *types.Result {if len(detail.Packages) == 0 || !detail.OS.Detected() {return nil}pkgs := detail.Packagesif options.ScanRemovedPackages {pkgs = mergePkgs(pkgs, detail.ImageConfig.Packages)//主要是去重}sort.Sort(pkgs)return &types.Result{Target:   fmt.Sprintf("%s (%s %s)", target, detail.OS.Family, detail.OS.Name),Class:    types.ClassOSPkg,//标识为os的软件包Type:     detail.OS.Family,//os namePackages: pkgs,}
}

至此,代码逻辑基本讲解完了。

相关文章:

trivy os软件包扫描原理分析

具体可以基于之前的博客来做 基于trivy获取基础镜像 参数修改一下&#xff1a; cliOpt.ListAllPkgs true 结果中会带有如下格式的结果&#xff1a; "Results":[{"Target":"192.168.1.94:443/test22/centos:7 (centos 7.9.2009)","Clas…...

算法训练营 day48 动态规划 完全背包 零钱兑换 II 组合总和 Ⅳ

算法训练营 day48 动态规划 完全背包 零钱兑换 II 组合总和 Ⅳ 完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物…...

Java 基础(1)—泛型简单使用

一、泛型定义及作用 泛型是一种编程机制&#xff0c;允许在编写代码时使用参数化类型&#xff0c;以在编译时实现类型安全。 以下是泛型作用&#xff1a; 增强代码可读性和可维护性&#xff1a;通过在代码中使用泛型参数&#xff0c;可以使代码更清晰、更具有可读性和可维护性…...

内存卡损坏了怎么恢复?

内存卡损坏了怎么恢复?现在我们身边有不少电子设备都是用存储卡来存储数据的。一旦需要方便我们直接导出使用。但这存储的数据也不是一定安全的&#xff0c;当我们将内存卡连接到电脑时&#xff0c;难免会碰到病毒、格式化等提示&#xff0c;在这些情况下&#xff0c;可能会导…...

Mysql使用规范(纯技术和实战建议)

1、事务隔级别: &#xff08;强制&#xff09;&#xff1a;Repeatable-Read&#xff08;重复读&#xff09;&#xff0c;且不能在会话操作时临时开启隔离级别。 注&#xff1a; Repeatable-Read&#xff08;重复读&#xff09;隔离级别解决不了幻读。 可用 show variables l…...

Netty源码解读-EventLoop(二)

一、简介 NioEventLoop的重要组成&#xff1a;Selector、线程、任务队列&#xff0c;他既会处理io事件&#xff0c;也会处理普通任务和定时任务. 1.下面是Selector&#xff0c;注意有两个哦后面会讲 2.下面的爷爷类提供的Thread变量&#xff0c;其实下面发excutor用的就是这个…...

OSI模型详解

今天&#xff0c;我们详解OSI&#xff08;Open System Inter-connection Reference Model&#xff09;模型&#xff0c;来看看工业物联网的网络互联和数据互通。 OSI模型 1984年&#xff0c;国际标准化组织&#xff08;International Organization for Standardization&#…...

Share Creators完成500万美元融资,以工具化手段帮助企业从数字资产管理中解放

近日&#xff0c;总部位于旧金山湾区的初创公司Share Creators宣布完成了新一轮500万美元的融资&#xff0c;投资方为五源资本和福昕PDF。本轮融资主要用于扩大客户基础&#xff0c;并加速在美国、欧洲和亚洲的业务发展。近几年&#xff0c;企业内容及数字资产管理全球市场正在…...

几个Base64编码工具,也有蹊跷

起因 需求&#xff1a;对一段内容进行base64加密&#xff0c;然后通过url的get请求进行发送到后台&#xff0c;由于加密的内容比较少&#xff0c;base64串也不是很长&#xff0c;我认为此方案可行。 于是找了三个base64编码的在线工具&#xff0c;分别是&#xff1a; 平台1&…...

Python|每日一练|排序|递归|字符串|数组|动态规划|单选记录:以特殊格式处理连续增加的数字|正则表达式匹配|地下城游戏

1、以特殊格式处理连续增加的数字&#xff08;排序&#xff09; 贡献者&#xff1a;EricLao 给出一串数字&#xff0c; 程序要把数字按照这样的格式输出&#xff0c;把连续增加的数字用 [x-y] 的形式表示&#xff0c;只显示这一组顺序数字的首位两个数字&#xff0c;不连续增…...

Spring Cloud微服务网关Gateway组件

目录 网关简介 什么是Spring Cloud Gateway Spring Cloud Gateway 功能特征 核心概念 工作原理 Spring Cloud Gateway快速开始 环境搭建 集成Nacos 路由断言工厂&#xff08;Route Predicate Factories&#xff09;配置 自定义路由断言工厂 过滤器工厂&#xff08; …...

cluster nodes(集群节点)

CLUSTER NODES 复制 自3.0.0起可用。 时间复杂度&#xff1a; O&#xff08;N&#xff09;其中N是 Cluster 节点的总数 Redis 集群中的每个节点都有其当前集群配置的视图&#xff0c;由已知节点的集合给出&#xff0c;我们与这些节点的连接状态&#xff0c;它们的标志&…...

【Android学习】下载jar慢和gradle慢的情况

目录 问题出现的原因 解决方法 解决Gradle下载问题&#xff1a;手动安装 解决jar包下载慢问题&#xff1a;更改下载源 问题出现的原因 国内访问谷歌被墙导致访问速度慢或者干脆无法下载 解决方法 解决Gradle下载问题&#xff1a;手动安装 访问官网Gradle | Release Candi…...

下一个排列-力扣31-java

一、题目描述整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。例如&#xff0c;arr [1,2,3] &#xff0c;以下这些都可以视作 arr 的排列&#xff1a;[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地&…...

前端面试题

1.HTTP request报文结构是怎样的 1.首行是Request-Line包括&#xff1a;请求方法&#xff0c;请求URI&#xff0c;协议版本&#xff0c;CRLF&#xff08;换行符&#xff09; 2.首行之后是若干行请求头&#xff0c;包括general-header&#xff0c;request-header或者entity-hea…...

jsp游戏门户网站系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 游戏门户网站系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql&#xff0c;使…...

Git与IDEA强强联合(HTTPS协议连接)

最近在写项目的时候&#xff0c;在台式机和笔记本之间频繁切换&#xff0c;竟然还是用qq传压缩包&#xff0c;我自己都感觉无语&#xff0c;有git这样强大的版本管理工具&#xff0c;我竟然没想起来。然后也没有相关的博文就想来更新一篇。 那么如何使idea和git强强联合呢&…...

leetcode 第二题:两数相加-C语言实现

题目地址 备注&#xff1a; 不要忘记最后一个进位的可能。可以使用typedef&#xff0c;来简化struct的书写 代码实现&#xff1a; #include<stdio.h> #include<stdlib.h>struct listNode {int val;struct listNode* next; };// 使用typedef typedef struct lis…...

【人工智能】PTP网络时钟服务器在智能驾驶里的重要性

【人工智能】PTP网络时钟服务器在智能驾驶里的重要性 【人工智能】PTP网络时钟服务器在智能驾驶里的重要性 一辆宣称具备L4/L5自动驾驶功能的车辆&#xff0c;如果多个激光雷达之间的时间同步不够精确&#xff1f;如果传感器感知数据通过以太网传输到智驾域控制器的延迟不可控…...

【蓝桥杯集训3】二分专题(3 / 5)

目录 二分模板 1460. 我在哪&#xff1f; - 二分答案 哈希表 1221. 四平方和 - 哈希表 / 二分 1、哈希表 2、二分 自定义排序 1227. 分巧克力 - 113. 特殊排序 - 二分模板 l r >> 1 —— 先 r mid 后 l mid1 —— 寻找左边界 —— 找大于某个数的最小值lr…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...