前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[模块化配置]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
Javascript
...ECMAScript模块)的新一代构建工具。用它来开发,速度嗖嗖的,感觉就像是开了挂一样!但是,当这两者相遇时,有时候会出现一些让人头疼的问题。今天我们就来解决这个难题! 二、Snap.svg的基本概念与重要性 首先,让我们简单回顾一下Snap.svg。Snap.svg的主要特点包括: - 易于使用:提供了简洁的API,让开发者可以轻松地创建、修改和控制SVG元素。 - 功能强大:支持复杂的SVG图形操作,如动画、渐变、滤镜等。 - 兼容性好:几乎可以在所有现代浏览器上运行。 使用Snap.svg可以帮助我们更高效地处理SVG内容,尤其是在需要动态生成或修改SVG图形的情况下。不过嘛,当我们想把它用在Vite项目里的时候,可能会碰到一些意料之外的难题。 三、遇到的问题 Snap.svg在Vite环境下报错 在实际开发过程中,我遇到了这样一个问题:当我尝试在Vite项目中引入Snap.svg时,会遇到各种错误提示,比如找不到模块、类型定义不匹配等等。这确实让人有些沮丧,因为原本期待的是一个流畅的开发过程。 具体来说,错误信息可能是这样的: Cannot find module 'snapsvg' or its corresponding type declarations. 或者: Module build failed (from ./node_modules/@dcloudio/vue-cli-plugin-uni/packages/webpack/lib/loaders/svgo-loader.js): Error: SVG not found 这些问题往往会让新手感到困惑,甚至对于有一定经验的开发者来说也会觉得棘手。但别担心,接下来我会分享几个解决方案。 四、解决方案 正确引入Snap.svg 解决方案1:安装Snap.svg 首先,确保你的项目中已经安装了Snap.svg。可以通过npm或yarn进行安装: bash npm install snapsvg 或者 yarn add snapsvg 解决方案2:配置Vite的别名或路径映射 有时候,Vite可能无法直接识别到Snap.svg的路径。这时,你可以通过配置Vite的别名或者路径映射来解决这个问题。打开vite.config.ts文件(如果没有这个文件,则需要创建),添加如下配置: typescript import { defineConfig } from 'vite'; export default defineConfig({ resolve: { alias: { 'snapsvg': 'snapsvg/dist/snapsvg.js', }, }, }); 这样做的目的是告诉Vite,当你引用snapsvg时,实际上是引用snapsvg/dist/snapsvg.js这个文件。 解决方案3:手动导入 如果上述方法仍然无法解决问题,你可以尝试直接在需要使用Snap.svg的地方进行手动导入: javascript import Snap from 'snapsvg/dist/snap.svg'; 然后,在你的代码中就可以正常使用Snap对象了。 解决方案4:检查TypeScript配置 如果你的项目使用了TypeScript,并且遇到了类型定义的问题,确保你的tsconfig.json文件中包含了正确的类型声明路径: json { "compilerOptions": { "types": ["snapsvg"] } } 五、实践案例 动手试试看 现在,让我们通过一个小案例来看看这些解决方案的实际应用效果吧! 假设我们要创建一个简单的SVG圆形,并为其添加动画效果: html Snap.svg Example javascript // main.js import Snap from 'snapsvg/dist/snap.svg'; const s = Snap('svg-container'); // 创建一个圆形 const circle = s.circle(100, 100, 50); circle.attr({ fill: 'f06', }); // 添加动画效果 circle.animate({ r: 70 }, 1000); 在这个例子中,我们首先通过Snap('svg-container')选择了SVG容器,然后创建了一个圆形,并为其添加了一个简单的动画效果。 六、总结与展望 通过今天的讨论,相信你已经对如何在Vite环境中正确引入Snap.svg有了更深的理解。虽然路上可能会碰到些难题,但只要找到对的方法,事情就会变得轻松许多。未来的日子里,随着技术不断进步,我打心眼里觉得,咱们一定能找到更多又高效又方便的新方法来搞定这些问题。 希望这篇教程对你有所帮助!如果你有任何疑问或更好的建议,欢迎随时交流。编程路上,我们一起进步! --- 希望这篇文章能够满足您的需求,如果有任何进一步的要求或想要调整的部分,请随时告诉我!
2024-11-28 15:42:34
101
清风徐来_
Superset
...易懂,就像搭积木一样模块化,让用户能够像探照灯一样迅速找到自己需要的功能,再也不用在层层叠叠的菜单迷宫里晕头转向了。这样一来,大伙儿使用起来就能更加得心应手,效率自然蹭蹭往上涨! python 这里以伪代码表示导航栏逻辑 if user_selected == 'Dashboard': navigate_to_dashboard() elif user_selected == 'Charts': navigate_to_charts() else: navigate_to_sql_lab() (2) 工作区划分:Superset的界面右侧主要为工作区,左侧为资源列表或者查询编辑器,符合大多数用户从左到右,自上而下的阅读习惯。这种分栏式设计,就像是给用户在同一个窗口里搭了个高效操作台,让他们能够一站式完成数据查询、分析和可视化所有步骤,这样一来,不仅让用户感觉操作一气呵成,流畅得飞起,还大大提升了整体使用体验,仿佛像是给界面抹上了润滑剂,用起来更加顺手、舒心。 2. 可定制化的仪表盘 Superset允许用户自由创建和配置个性化仪表盘,每个组件(如各种图表)都可以拖拽调整大小和位置,如同拼图一样灵活构建数据故事。以下是一个创建新仪表盘的例子: python 伪代码示例,实际操作是通过UI完成 create_new_dashboard('My Custom Dashboard') add_chart_to_dashboard(chart_id='sales_trend', position={'x': 0, 'y': 0, 'width': 12, 'height': 6}) 通过这种方式,用户可以根据自己的需求和喜好对仪表盘进行深度定制,使数据更加贴近业务场景,提高了数据理解和决策效率。 3. 强大的交互元素 (1) 动态过滤器:Superset支持全局过滤器,用户在一个地方设定筛选条件后,整个仪表盘上的所有关联图表都会实时响应变化。例如: javascript // 伪代码,仅表达逻辑 apply_global_filter(field='date', operator='>', value='2022-01-01') (2) 联动交互:点击图表中的某一数据点,关联图表会自动聚焦于该点所代表的数据范围,这种联动效果能有效引导用户深入挖掘数据细节,增强数据探索的趣味性和有效性。 4. 易用性与可访问性 Superset在色彩搭配、字体选择、图标设计等方面注重易读性和一致性,降低用户认知负担。同时呢,我们也有考虑到无障碍设计这一点,就比如说,为了让视力不同的用户都能舒舒服服地使用,我们会提供足够丰富的对比度设置选项,让大家可以根据自身需求来调整,真正做到贴心实用。 总结来说,Superset通过直观清晰的界面布局、高度自由的定制化设计、丰富的交互元素以及关注易用性和可访问性的细节处理,成功地优化了用户体验,使其成为一款既专业又友好的数据分析工具。在此过程中,我们不断思考和探索如何更好地平衡功能与形式,让冰冷的数据在人性化的设计中焕发出生动的活力。
2023-09-02 09:45:15
150
蝶舞花间
Beego
...o是一个开源、高效、模块化的Go语言Web开发框架,由国内开发者开发并维护。它集成了MVC设计模式、路由控制、模板渲染、ORM(对象关系映射)等功能于一体,为Go语言开发者提供了一站式的Web应用解决方案,简化了Web项目的开发流程,提升了开发效率。 最大开放连接数 , 在数据库连接池的配置参数中,最大开放连接数是指数据库允许同时打开并使用的最大活跃连接数。这个数值过高可能导致数据库服务器资源消耗过大,影响整体性能;而设置过低,则可能无法满足高并发场景下的连接需求,造成请求排队等待,降低响应速度。因此,根据实际业务负载情况合理设置最大开放连接数是优化数据库连接池性能的关键因素之一。 最大空闲连接数 , 同样作为数据库连接池的一个重要配置项,最大空闲连接数指在没有数据库操作时,连接池中保持的最大空闲连接数量。这些空闲连接能够在新的数据库请求到达时立即投入使用,从而减少建立新连接的时间成本。然而,如果空闲连接过多,也可能导致资源浪费。因此,在保证系统响应速度的前提下,适当限制最大空闲连接数,既能有效利用资源,又能防止过度占用数据库连接资源。
2023-12-11 18:28:55
528
岁月静好-t
转载文章
...万的源文件,并实现了模块化编译,这对于深入理解Makefile的应用场景具有很高的参考价值。 进一步了解,可以关注以下资源: 1. "GitHub Actions: Extending Workflows with Custom Runners and Functions" - 这篇文章详细解读了如何在GitHub Actions中创建自定义工作流并利用其功能实现复杂的构建逻辑。 2. "An In-depth Look at the Linux Kernel Build System (Kbuild)" - 这篇深度分析文章揭示了Linux内核编译系统的设计理念和实现细节,包括其对Makefile强大特性的运用。 3. "Modern C++ Project Automation with Makefiles" - 该教程结合现代C++项目实践,展示了如何与时俱进地使用Makefile进行项目自动化构建,同时探讨了与其他构建工具如CMake、Meson等的对比和融合。 通过延伸阅读以上内容,您可以更好地将理论知识应用于实际项目开发,优化构建过程,提高项目的可维护性和迭代速度。
2023-03-28 09:49:23
282
转载
转载文章
...杂服务栈的自动化安装配置。 此外,随着开源生态的发展,一些Linux发行版开始提供更全面的离线包管理方案,比如Fedora Silverblue项目就引入了模块化操作系统理念,使得离线安装大量软件变得更加方便和快捷。未来,离线安装技术将更加智能化和便捷化,为企业级应用部署提供更多可能。
2023-06-23 08:28:14
107
转载
Go-Spring
...构允许开发者构建高度模块化的应用程序,每个服务可以独立部署、扩展和维护,从而提高了系统的灵活性和可维护性。 名词 , 配置管理。 解释 , 配置管理是指对系统配置信息的规划、控制和维护过程,确保系统配置的一致性、可靠性和安全性。在GoSpring框架中,配置管理通过支持环境变量和配置文件的集成,提供了动态调整应用行为的能力,使得开发者可以根据不同的运行环境或需求,灵活地调整应用配置,而无需修改源代码。 名词 , 容器化。 解释 , 容器化是一种软件交付方法,它通过将应用及其依赖打包到轻量级、可移植的容器中,实现了应用的隔离执行。在现代软件开发实践中,容器化使得应用能够在任何环境下一致地运行,降低了环境依赖性,提高了部署效率。虽然本文重点讨论的是GoSpring框架的配置管理机制,但容器化作为一种常见的应用部署方式,与配置管理紧密相关,共同促进着应用的快速迭代和高效部署。
2024-09-09 15:51:14
75
彩虹之上
Dubbo
... 参数优化 - 调优配置:合理设置Dubbo的相关参数,如超时时间、重试次数、序列化方式等,以适应不同的业务需求。 - 并发控制:通过合理的线程池配置和异步调用机制,有效管理并发请求,避免资源瓶颈。 四、实战案例 案例一:服务缓存实现 java // 配置本地缓存 @Reference private MyService myService; public void doSomething() { // 获取缓存,若无则从远程调用获取并缓存 String result = cache.get("myKey", () -> myService.doSomething()); System.out.println("Cache hit/miss: " + (result != null ? "hit" : "miss")); } 案例二:动态负载均衡 java // 创建负载均衡器实例 LoadBalance loadBalance = new RoundRobinLoadBalance(); // 配置服务列表 List serviceUrls = Arrays.asList("service1://localhost:8080", "service2://localhost:8081"); // 动态选择服务实例 String targetUrl = loadBalance.choose(serviceUrls); MyService myService = new RpcReference(targetUrl); 五、总结与展望 通过上述的实践分享,我们可以看到,Dubbo的性能优化并非一蹴而就,而是需要在实际项目中不断探索和调整。哎呀,兄弟,这事儿啊,关键就是得会玩转Dubbo的各种酷炫功能,然后结合你手头的业务场景,好好打磨打磨那些参数,让它发挥出最佳状态。就像是调酒师调鸡尾酒,得看人下菜,看场景定参数,这样才能让产品既符合大众口味,又能彰显个性特色。哎呀,你猜怎么着?Dubbo这个大宝贝儿,它一直在努力学习新技能,提升自己呢!就像咱们人一样,技术更新换代快,它得跟上节奏,对吧?所以,未来的它呀,肯定能给咱们带来更多简单好用,性能超棒的功能!这不就是咱们开发小能手的梦想嘛——搭建一个既稳当又高效的分布式系统?想想都让人激动呢! 结语 在分布式系统构建的过程中,性能优化是一个持续的过程,需要开发者具备深入的理解和技术敏感度。嘿!小伙伴们,如果你是Dubbo的忠实用户或者是打算加入Dubbo大家庭的新手,这篇文章可是为你量身打造的!我们在这里分享了一些实用的技巧和深刻的理解,希望能激发你的灵感,让你在使用Dubbo的过程中更得心应手,共同创造分布式系统那片美丽的天空。快来一起探索,一起成长吧!
2024-07-25 00:34:28
410
百转千回
转载文章
...,包括pom.xml配置文件、源代码目录结构以及相关的构建流程等。当用户使用Maven创建Web应用时,会遵循一定的目录布局和依赖管理规范,使得项目更加模块化、可维护,并且方便进行自动化构建和部署。 Servlet版本 , Servlet是Java平台下用于扩展Web服务器功能的一种技术接口,它是Java EE规范的一部分,允许开发者为Web应用创建动态内容。文中提及的Servlet版本是指在web.xml或相关Maven依赖中定义的Servlet API版本号,如2.3、2.5或更高版本。不同版本的Servlet提供了不同的功能集和API接口,因此在Eclipse等IDE中创建或修改Web项目时,需要确保项目的Servlet版本与目标运行环境(如Tomcat服务器)兼容。 Project Facets , Project Facets是Eclipse IDE中的一个概念,用来描述特定类型的项目所具有的特性或属性,这些特性通常与某种框架或技术规范相关联。例如,在Eclipse Web项目中,Dynamic Web Module就是一种Facet,它表示该项目是一个符合Java Web标准的应用程序,具有Web模块的所有特性。通过Project Facets界面,开发者可以指定项目采用何种技术规格(如Servlet版本),以便Eclipse能够提供相应的编译支持、部署配置及验证等功能,确保项目能在相应的服务器环境下正确运行。
2024-02-23 12:52:12
489
转载
Maven
...项目依赖、构建目标、配置等信息。为了开始使用Maven,你需要下载并安装Maven软件,通常可以通过官方网站下载最新版本的Maven,并将其添加到系统的PATH环境变量中,以便通过命令行进行操作。 二、项目构建与依赖管理 Maven的构建过程分为多个阶段,包括清理、编译、测试、打包、部署等,通过配置pom.xml文件中的生命周期(profiles),开发者可以定制构建流程以适应不同的开发需求。依赖管理是Maven的一大亮点,通过定义依赖范围(如compile、test、provided、runtime等),Maven能够智能地管理项目间的依赖关系,避免重复依赖和版本冲突。此外,Maven Central仓库提供了丰富的开源组件,通过标签轻松引入所需的库。 三、高级用法与最佳实践 随着项目规模的增长,合理组织项目结构、高效管理依赖、优化构建性能成为提高开发效率的关键。利用Maven的特性,开发者可以创建自定义的构建脚本、生命周期、插件,实现个性化的构建流程。例如,使用maven-antrun-plugin执行外部脚本,使用maven-source-plugin生成源码文档等。同时,遵循一些最佳实践,如保持pom.xml文件简洁、使用版本控制工具管理项目依赖、定期清理和整理构建记录,可以显著提升开发效率和项目的可维护性。 四、未来趋势与展望 展望未来,Maven将继续在自动化构建、依赖管理、多模块项目支持等方面进行创新,以满足日益增长的软件开发需求。随着DevOps文化的普及,Maven有望与持续集成/持续部署(CI/CD)工具更紧密地集成,实现自动化测试、构建、部署的无缝衔接。此外,随着微服务架构的兴起,Maven将发挥更大的作用,通过支持多模块项目,促进模块化开发和团队协作。 结语 从基础概念到高级用法,Maven为开发者提供了全方位的支持,使其在项目构建、依赖管理、自动化测试等方面具备强大的能力。通过不断学习和实践,开发者能够充分利用Maven的优势,提升项目开发效率,应对复杂的软件工程挑战。随着技术的发展,Maven的未来充满无限可能,期待更多开发者在这一领域探索创新,共同推动软件开发的进步。
2024-08-09 16:06:13
93
初心未变
Material UI
...以及它有哪些参数可以配置。说实话,刚开始接触的时候,我也是懵圈的,不过慢慢琢磨就明白了。 首先,ChipGroup是一个容器,里面可以放一堆Chip(也就是那些小标签)。它的核心属性主要有以下几个: - children: 这个就是你要显示的Chip列表啦,每个Chip都是一个单独的小标签。 - value: 如果你设置了这个属性,表示当前选中的Chip是哪些。要是单选的话,就只能选一个值,不能多选;但如果是多选模式呢,那就可以传一串数组,想选几个选几个,自由得很! - onValueChange: 这个属性很重要,它是一个回调函数,每当用户选择了一个新的Chip时,都会触发这个函数,你可以在这里处理业务逻辑。 - variant: 可以设置Chip的样式,比如“filled”(填充型)或者“outlined”(边框型),具体看你喜欢哪种风格。 - color: 设置Chip的颜色,比如“primary”、“secondary”之类的,挺简单的。 让我举个例子吧,比如你想做一个音乐类型的筛选器,代码可以这样写: jsx import React from 'react'; import { Chip, ChipGroup } from '@mui/material'; export default function MusicTypeFilter() { const [selectedTypes, setSelectedTypes] = React.useState([]); const handleTypeChange = (event, newValues) => { setSelectedTypes(newValues); console.log('Selected types:', newValues); }; return ( value={selectedTypes} onChange={handleTypeChange} variant="outlined" color="primary" aria-label="music type filter" > ); } 这段代码创建了一个音乐类型筛选器,用户可以选择多个类型。每次选择后,handleTypeChange函数会被调用,并且打印出当前选中的类型。是不是超简单? --- 3. 单选模式 vs 多选模式 说到ChipGroup,肯定要提到它的两种模式——单选模式和多选模式。这就跟点菜一样啊!单选模式就像你只能从菜单上挑一道菜,不能多点;多选模式呢,就好比你想吃啥就点啥,爱点几个点几个,随便你开心!这听起来很基础对吧?但其实这里面有很多细节需要注意。 比如说,如果你用的是单选模式,那么每次点击一个新的Chip时,其他所有Chip的状态都会自动取消掉。这是Material UI默认的行为,但有时候你可能不想要这种效果。比如你做的是一个问卷调查,用户可以选择“非常同意”、“同意”、“中立”等选项,但你希望他们能同时勾选多个答案怎么办呢? 解决办法也很简单,只需要给ChipGroup设置multiple属性为true就行啦!比如下面这段代码: jsx multiple value={['同意', '中立']} onChange={(event, newValues) => { console.log('Selected values:', newValues); } } > 在这个例子中,用户可以同时选择“同意”和“中立”,而不是只能选一个。是不是感觉特别灵活? --- 4. ChipGroup的高级玩法 最后,咱们来说点更酷的东西!你知道吗,ChipGroup其实还有很多隐藏技能,只要你稍微动点脑筋,就能让它变得更强大。 比如说,你想让某些Chip一开始就被选中,该怎么办?很简单,只要在初始化的时候把它们的值放到value属性里就行啦!比如: jsx const [selectedTypes, setSelectedTypes] = React.useState(['摇滚', '流行']); 再比如,你想给某个Chip加上特殊的图标或者颜色,也可以通过自定义Chip来实现。比如: jsx label="摇滚" icon={} color="error" /> 还有哦,有时候你可能会遇到一些动态数据,比如从后台获取的一组选项。这种情况下,你可以用循环来生成ChipGroup的内容,代码如下: jsx const musicTypes = ['摇滚', '爵士', '流行', '古典']; return ( value={selectedTypes} onChange={handleTypeChange} > {musicTypes.map((type) => ( ))} ); 看到没?是不是特别方便?这种灵活性真的让人爱不释手! --- 5. 总结与反思 好了,到这里咱们就差不多聊完了ChipGroup的所有知识点啦!其实吧,我觉得这个组件真的挺实用的,无论是做前端还是后端,都能帮我们省去很多麻烦事。对啊,刚开始接触的时候确实会有点迷糊,感觉云里雾里的。不过别担心,多试着上手操作个几次,慢慢你就明白了,其实一点都不难! 话说回来,我觉得学习任何技术都得抱着一种探索的心态,不能死记硬背。嘿嘿,说到ChipGroup,我当初也是被它折腾了好一阵子呢!各种属性啊、方法啊,全都得自己动手试一遍,慢慢摸索才知道咋用。就像吃 unfamiliar 的菜一样,一开始啥都不懂,只能一个劲儿地尝,最后才找到门道!所以说啊,大家要是用的时候碰到啥难题,别急着抓头发,先去瞅瞅官方文档呗,说不定就有答案了。实在不行,就自己动手试试,有时候动手一做,豁然开朗的感觉就来了! 总之呢,希望大家都能用好这个组件,把它变成自己的得力助手!如果有啥疑问或者更好的玩法,欢迎随时交流哦~ 😊
2025-05-09 16:08:24
89
月下独酌
Java
... JSP 无效——多模块、Web 启动项与 view.suffix 配置解析 一、引言 作为Java开发者,我们时常需要处理前后端分离的项目架构,其中Spring Boot以其简洁易用性和高度自动化的特点,成为了构建现代Web应用的理想选择。然而,在实际做开发的时候,特别是在捣鼓那些老派的JSP视图渲染,还有跨模块配置这些事儿,咱们有时会遇到一些让人挠头的问题。就比如这次提到的,你设置了spring.mvc.view.suffix这个参数却没见生效的情况,是不是挺让人头疼的?接下来,我们将深入剖析这个现象,并给出针对性的解决方案。 二、背景与问题描述 假设我们正在使用Spring Boot构建一个多模块的应用,其中一个模块专门负责Web服务提供,使用了Spring MVC作为控制器及其视图层的框架。为了让HTML模板与Java逻辑更加清晰地分隔,我们在项目的布局中采用了如下结构: 1. module-core: 应用的核心业务逻辑和服务模块 2. module-web: 启动项,主要包含Web相关的配置与控制层逻辑,依赖于module-core 3. module-views: 存放JSP视图文件,用于前端展示 在此场景下,为确保正确识别并加载JSP视图,我们需要在module-web的配置文件中指定JSP后缀名(spring.mvc.view.suffix),例如: properties spring: mvc: view: prefix: /WEB-INF/views/ suffix: .jsp 然而,当运行程序并尝试访问Controller中带有相关视图名称的方法(如@GetMapping("/home")映射到WEB-INF/views/homePage.jsp)时,浏览器却无法显示出预期的JSP页面内容,且并未抛出任何异常,而是默认返回了空响应或者错误状态码。 三、问题分析与排查 面对这一看似简单的配置失效问题,我们首先需要进行如下几个方面的排查: 1. 检查视图解析器配置 确保视图解析器org.springframework.web.servlet.view.InternalResourceViewResolver已被正确注册并设置了prefix与suffix属性。检查Spring Boot启动类(如WebMvcConfig.java或Application.java中的WebMvcConfigurer实现): java @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); registry.viewResolver(resolver); } } 2. 模块间依赖与资源路径映射 确认module-web是否正确引入了module-views的相关JSP文件,并指定了正确的资源路径。查看module-web的pom.xml或build.gradle文件中对视图资源模块的依赖路径: xml com.example module-views 1.0.0 war runtime classes // Gradle dependencies { runtimeOnly 'com.example:module-views:1.0.0' } 以及主启动类(如Application.java)中的静态资源映射配置: java @SpringBootApplication public class Application { @Bean TomcatServletWebServerFactory tomcat() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.addContextCustomizer((TomcatWebServerContext context) -> { // 将模块视图目录映射到根URL下 context.addWelcomeFile("index.jsp"); WebResourceRoot resourceRoot = new TomcatWebResourceRoot(context, "static", "/"); resourceRoot.addDirectory(new File("src/main/resources/static")); context.setResources(resourceRoot); }); return factory; } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 3. 检查JSP引擎配置 确保Tomcat服务器配置已启用JSP支持。在module-web对应的application.properties或application.yml文件中配置JSP引擎: properties server.tomcat.jsp-enabled=true server.tomcat.jsp.version=2.3 或者在module-web的pom.xml或build.gradle文件中为Tomcat添加Jasper依赖: xml org.apache.tomcat.embed tomcat-embed-jasper provided // Gradle dependencies { implementation 'org.apache.tomcat.embed:tomcat-embed-jasper:9.0.54' } 4. 控制器与视图名称匹配验证 在完成上述配置后,请务必核实Controller中返回的视图名称与其实际路径是否一致。如果存在命名冲突或者拼写错误,将会导致Spring MVC无法找到预期的JSP视图: java @GetMapping("/home") public String home(Model model) { return "homePage"; // 视图名称应更改为"WEB-INF/views/homePage.jsp" } 四、总结与解决办法 综上所述,Spring Boot返回JSP无效的问题可能源于多个因素的叠加效应,包括但不限于视图解析器配置不完整、模块间依赖关系未正确处理、JSP引擎支持未开启、或Controller与视图名称之间的不对应等。要解决这个问题,需从以上几个方面进行逐一排查和修正。 切记,在面对这类问题时,要保持冷静并耐心地定位问题所在,仔细分析配置文件、源代码和日志输出,才能准确找出症结所在,进而成功解决问题。这不仅让我们实实在在地磨炼了编程功夫,更是让咱们对Spring Boot这家伙的工作内幕有了更深的洞察。这样一来,我们在实际项目中遇到问题时,调试和应对的能力都像坐火箭一样嗖嗖提升啦!
2024-02-17 11:18:11
271
半夏微凉_t
RocketMQ
...失风险的策略 1. 配置优化 合理设置RocketMQ的配置参数,如消息重试次数、消费超时时间等,确保在异常情况下,消息可以被正确处理或重试。 java // 示例代码:设置消息重试次数 Properties props = new Properties(); props.setProperty("producer.transactionCheckEnabled", "false"); props.setProperty("producer.transactionTimeout", "60000"); props.setProperty("producer.maxReconsumeTimes", "5"); // 设置最大重试次数为5次 RMQSender sender = new RMQSender("localhost:18831", "myQueue", props); 2. 监控与报警 建立一套完善的监控系统,实时监测RocketMQ的运行状态,一旦出现异常,立即触发报警机制。 bash 假设使用Prometheus进行监控 prometheus: - job_name: 'rocketmq' metrics_path: '/actuator/metrics' static_configs: - targets: ['localhost:8080'] labels: application: 'rocketmq' 3. 备份与恢复策略 定期对RocketMQ的元数据和消息进行备份,以便在发生灾难性事件时快速恢复服务。 bash 使用HDFS作为存储时,可以利用HDFS的备份功能 hdfs dfs -copyToLocal /path/to/backup /local/path/ 4. 容错与高可用架构设计 在应用层面考虑容错机制,如使用负载均衡、故障转移等策略,确保在单点故障时,系统仍能正常运行。 java // 使用Nacos进行服务发现和配置中心管理 @Value("${service.provider}") private String serviceProvider; @Bean public ProviderConfig providerConfig() { return new ProviderConfig(serviceProvider); } 四、结论 通过上述策略的实施,我们可以显著降低使用RocketMQ时数据丢失的风险。关键在于合理配置、有效监控、备份恢复以及高可用架构的设计。在实际应用中,还需要根据业务的具体需求和场景,灵活调整策略,以达到最佳的数据持久化效果。哎呀,兄弟!技术这东西,得不停琢磨,多实践,别老是原地踏步。咱们得时不时调整一下系统这架机器的零件,让它跑得既快又稳当。这样,咱们的应用服务才不会卡壳,用户们用起来也舒心。这可是保证业务顺畅运行的关键!
2024-10-02 15:46:59
573
蝶舞花间
Netty
...的数据传输。通过合理配置EventLoopGroup,可以有效地分配和管理资源,避免资源争抢的情况发生,从而提高系统的并发处理能力和稳定性。 ChannelPipeline , Netty框架中用于灵活处理网络请求的管道机制。它允许将多个处理器(如编解码器、业务逻辑处理器等)串联起来,按顺序处理网络请求。这种方式非常适合需要执行复杂业务逻辑的应用场景,使得开发者可以方便地扩展或修改请求处理逻辑,而无需改动底层的网络通信代码。通过ChannelPipeline,可以实现高度模块化和可维护的网络请求处理流程。
2024-12-05 15:57:43
102
晚秋落叶
转载文章
...源全部打包压成一个个模块,就像酱紫滴: 我们这节课重点讲一下css的打包。 有同学就犯嘀咕了: 你说js打包我还能理解,而css打包是个什么卵?css还用打包?开什么国际玩笑? 这种质疑不无道理。 因为从传统观点来看,css生下来就是个二等公民。js开始也是个二流货色,但经过这几年的努力,人家已经洗白白成了白富美;而css呢,好容易折腾到css3,虽然整了容,变的漂亮了些,但仍不登大雅之堂,不受人待见。 大家都是二等公民出身,为啥你js能起来,我就不行?css心中一万头草泥马奔过,难道这就是命运的安排? 人贵在有自知之明。当人生遇到低谷,最重要的是反思自己,而不是跟个怨妇一样抱怨。 css为啥无法成为白富美? 首先,可能是因其语法简单,没有什么挑战性;其次,大家也不怎么重视css的规范性。在传统模式下,css都是一股脑写在一个大文件里,然后加载到网页的,这样就直接导致了管理上的混乱: 在css增量开发时,要时刻注意命名空间问题;到了调试阶段,又不得不依赖谷歌控制台或firebug的元素定位,有时父类的某个属性影响了子类,导致修改子类样式无法达到预期。。。。 自从有了react和vue,css的灵魂得到了救赎。这两种框架均提出组件化编程的思想,也就是将html,css,js均凝聚成一个不可分割的小部件,留出对外通信的接口,然后灵活组合使用,譬如下图所示: 这样一来,css就有了打包的可能性。打包的好处是: css也有了模块化,可以不用再关心命名空间问题,只需专心将这个部件渲染好,出了问题也更容易定位追踪。 知其然知其所以然,我们搞懂了为啥css要打包的道理,下面就可以愉快而主动的学习了。 仔细权衡了一下,这里我并不打算引入react或vue讲解,因为这样会增加大家理解上的负担。学习新东西,最忌讳的就是学了这个又牵扯到那个,结果精力分散重点转移,到最后很可能一个都没搞懂,还增加了自己的挫败感。 为了简单起见,我们仍旧沿用前面那个案例做讲解,先把这个webpack玩转再说。 咱们看一下具体玩法。首先还是安装插件,这里我们需要两个工具: npm install style-loadernpm install css-loader 原料有了,我们做一下测试文件做测试。我们首先新建一个style.css文件,目录结构如下: style.css: .content {color: red;} 很简单,就是一个样式类。然后我们改一下helloworld.js文件。 helloworld.js: // 引入css模块var styles = require('../style.css');// 输出模块module.exports = () => {// 这里使用了箭头函数,还有let和const关键字哦~~let content = "Hello ";const NAME = "ES6";var div = document.createElement('div');div.setAttribute('class', styles.content); // 使用样式类div.innerHTML = content + NAME;return div;}; 注意,这里跟我们平时写的有点不一样。 我们在建一个dom节点时,指定了一个样式类。但是这个样式类,是以包的形式存在的,也就是一个模块。 综合起来看我们这个helloworld.js模块,是不是把html,css和js凝聚成了一个小整体了呢? 我知道你已经迫不及待的想看结果了,好吧,咱们赶紧写一下配置文件跑起来吧~~ webpack.config.js: var path = require('path');module.exports = {entry: './src/index.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'bundle.js'},module: {rules: [{test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader',options: {presets: ['env']} }, {test: /\.css$/,loader: 'style-loader!css-loader?modules'}]} }; 说明: style-loader和css-loader是工具名称。 !感叹号是分割符,表示两个工具都参与处理。 ?问号,其实跟url的问号一样,就是后面要跟参数的意思。 而modules这个参数呢,就是将css打包成模块。跟js打包是一样的,你不必再担心不同模块具有相同类名时造成的问题了。 我们运行一下:(我这次特地没在局部安装webpack-cli,发现可以运行,因为我昨天在全局安装了webpack-cli,之所以要在全局安装而单独局部安装不行,可能跟package.json有关,因为这里都没有用到package.json)。 如果不报错,我们打开浏览器,看一下index.html: 我们看到,样式已然生效了,但是我们打开控制台,看到class的名称并非是我们写的样式类.content,而是生成了新名称,这就说明webpack的编译生效了。 我们打开bundle.js看一下,css其实已经被打包编译到了bundle.js文件里:(太长,截了一部分) 我们看到,css打包后,存在形态已经变成了js。这没有什么可奇怪的,只有这样才能使用包的形式做管理,css本身,是无法达到这样的目的的,所以,它还是二等公民。。。。 本篇文章为转载内容。原文链接:https://blog.csdn.net/DreamFJ/article/details/81700004。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-13 11:42:35
72
转载
Golang
...lang生态下的现代配置管理实践 随着云计算和微服务架构的兴起,现代应用程序的复杂度显著提升,配置管理成为确保系统稳定性和灵活性的关键环节。Golang,作为一门简洁高效的语言,因其强大的并发处理能力和模块化的特性,被广泛应用于构建高性能、可扩展的系统。然而,在快速迭代的开发环境中,传统的配置管理方式面临诸多挑战,比如配置文件的频繁变更、版本控制的困难、以及多环境部署的复杂性。本文将探讨在Golang生态下,如何采用现代配置管理实践,以适应快速发展的技术趋势和业务需求。 一、动态配置与云原生应用 在云原生时代,动态配置管理变得至关重要。云平台提供了丰富的服务,如配置管理、密钥管理、服务发现等,这些服务支持在运行时更新配置,无需重启服务即可生效。Golang生态系统中,可以通过集成这些云服务来实现动态配置管理。例如,使用Kubernetes的ConfigMap或Secrets功能,可以在不修改代码的情况下,轻松调整服务配置,满足不同环境和阶段的需求。 二、微服务间的配置协调 在微服务架构中,服务间依赖的配置往往需要统一管理和协调。传统的方法可能涉及硬编码配置或通过共享数据库存储配置,这不仅增加了维护成本,还可能导致数据同步问题。借助现代配置管理工具,如Consul、Etcd或Vault,可以实现服务之间的配置共享和安全存储。这些工具提供了强大的API和丰富的客户端库,使得在Golang项目中集成配置管理变得更加便捷和高效。 三、DevOps与自动化测试 DevOps实践强调自动化和持续交付,这对配置管理提出了更高要求。在Golang项目中,可以结合CI/CD工具链,如Jenkins、GitLab CI或GitHub Actions,实现配置文件的自动化管理。通过编写脚本或使用特定的配置管理工具,可以在每次代码提交后自动触发配置更新过程,确保生产环境与开发环境的配置一致性。此外,引入自动化测试,特别是针对配置文件的测试,可以帮助检测配置错误,提前发现潜在问题,减少上线风险。 四、未来展望 随着技术的不断演进,Golang生态下的配置管理实践也将不断发展。未来,我们可以期待更智能的配置管理系统,能够自动检测配置冲突、预测配置变更影响,甚至通过机器学习算法优化配置性能。同时,跨平台和跨语言的配置管理工具将进一步增强Golang与其他技术栈的互操作性,促进更广泛的生态系统集成和协作。 总之,Golang生态下的现代配置管理实践不仅关乎技术细节,更是企业级应用架构设计和运维策略的重要组成部分。通过采用先进的配置管理工具和技术,可以有效提升应用的可维护性、可靠性和响应速度,助力企业在竞争激烈的市场环境中保持竞争优势。
2024-08-22 15:58:15
168
落叶归根
Ruby
...使用中,很多人会因为配置不当而导致性能下降甚至崩溃。 问题出现: 假设你创建了一个线程池,但线程池的大小设置得不合理。哎呀,这就好比做饭时锅不够大,菜都堆在那儿煮不熟,菜要是放太多呢,锅又会冒烟、潽得到处都是,最后饭也没做好。线程池也一样,太小了任务堆成山,程序半天没反应;太大了吧,电脑资源直接被榨干,啥事也干不成,还得收拾烂摊子! 代码示例: ruby 线程池的错误用法 require 'thread' pool = Concurrent::FixedThreadPool.new(2) 20.times do |i| pool.post do sleep(1) puts "Task {i} completed" end end pool.shutdown pool.wait_for_termination 分析: 在这个例子中,线程池的大小被设置为2,但有20个任务需要执行。哎呀,这就好比你请了个帮手,但他一次只能干两件事,其他事儿就得排队等着,得等前面那两件事儿干完了,才能轮到下一件呢!这种情况下,整个程序的执行时间会显著延长。 解决方案: 为了优化线程池的性能,我们需要根据系统的负载情况动态调整线程池的大小。可以使用Concurrent::CachedThreadPool,它会根据当前的任务数量自动调整线程的数量。 修正后的代码: ruby 使用缓存线程池 require 'concurrent' pool = Concurrent::CachedThreadPool.new 20.times do |i| pool.post do sleep(1) puts "Task {i} completed" end end sleep(10) 给线程池足够的时间完成任务 pool.shutdown pool.wait_for_termination 总结: 线程池就像一把双刃剑,用得好可以提升效率,用不好则会成为负担。记住,线程池的大小要根据实际情况灵活调整。 --- 6. 示例四 忽略异常的代价 场景描述: 并发编程的一个常见问题是,线程中的异常不容易被察觉。如果你没有妥善处理这些异常,程序可能会因为一个小错误而崩溃。 问题出现: 假设你有一个线程在执行某个操作时抛出了异常,但你没有捕获它,那么整个线程池可能会因此停止工作。 代码示例: ruby 忽略异常的代码 threads = [] 5.times do |i| threads << Thread.new do raise "Error in thread {i}" if i == 2 puts "Thread {i} completed" end end threads.each(&:join) 分析: 在这个例子中,当i == 2时,线程会抛出一个异常。哎呀糟糕!因为我们没抓住这个异常,程序直接就挂掉了,别的线程啥的也别想再跑了。 解决方案: 为了防止这种情况发生,我们应该在每个线程中添加异常捕获机制。比如,可以用begin-rescue-end结构来捕获异常并进行处理。 修正后的代码: ruby 捕获异常的代码 threads = [] 5.times do |i| threads << Thread.new do begin raise "Error in thread {i}" if i == 2 puts "Thread {i} completed" rescue => e puts "Thread {i} encountered an error: {e.message}" end end end threads.each(&:join) 总结: 异常就像隐藏在暗处的敌人,稍不注意就会让你措手不及。学会捕获和处理异常,是成为一个优秀的并发编程者的关键。 --- 7. 结语 好了,今天的分享就到这里啦!并发编程确实是一项强大的技能,但也需要谨慎对待。大家看看今天这个例子,是不是觉得有点隐患啊?希望能引起大家的注意,也学着怎么避开这些坑,别踩雷了! 最后,我想说的是,编程是一门艺术,也是一场冒险。每次遇到新挑战,我都觉得像打开一个神秘的盲盒,既兴奋又紧张。不过呢,光有好奇心还不够,还得有点儿耐心,就像种花一样,得一点点浇水施肥,不能急着看结果。相信只要我们不断学习、不断反思,就一定能写出更加优雅、高效的代码! 祝大家编码愉快!
2025-04-25 16:14:17
32
凌波微步
转载文章
...处理方式因人而异,有模块化开发经验的同学可使用类似的 px2rem 的插件去转化,也可以完全手动处理) (2017/9/9更新)然而真实情况往往更为复杂,比如,你引入了百度地图(N个样式需要处理转换);或者你引入了一个 framework;又或者你使用了 video 标签,上面默认的尺寸样式很难处理。等等这些棘手问题 面对这些情况,此时我们的高清方案如果不再压缩页面,那么以上问题将迎刃而解。 基于这样的思路,笔者对高清方案的源码做了如下修改,即添加一个叫做 normal 的参数,由它来控制页面是否压缩。 在文章顶部代码的最后,你会看到 flex(false, 100, 1),默认情况下页面是开启压缩的。 如果你需要禁止压缩,由于我们的源码执行后,直接将flex函数挂载到全局变量window上了,此时你直接在需要禁止压缩的页面执行 window.flex(true) 就可以了,而rem的用法保持不变。 有一点美中不足的是,如果禁止了页面压缩,高清屏的1像素就不能实现了,如果你必须要实现1像素,那么自行谷歌:css 0.5像素,有N多的解决方案,这里不再赘述。 5.问:有时候字体会不受控制的变大,怎么办? 答:在X5新内核Blink中,在排版页面的时候,会主动对字体进行放大,会检测页面中的主字体,当某一块字体在我们的判定规则中,认为字号较小,并且是页面中的主要字体,就会采取主动放大的操作。然而这不是我们想要的,可以采取给最大高度解决 解决方案: , :before, :after { max-height: 100000px } 补充:有同学反映,在一些情况下 textarea 标签内的字体大小即便加上上面的方案,字体也会变大,无法控制。此时你需要给 textarea 的 display 设为 table 或者 inline-table 即可恢复正常。(感谢 程序媛喵喵 对此的补充!2017/7/7) 6.问:我在底部导航用的flex感觉更合适一些,请问这样子混着用可以吗? 答:咱们的rem适合写固定尺寸。其余的根据需要换成flex或者百分比。源码示例中就有这三种的综合运用。 7.问:在高清方案下,一个标准的,较为理想的宽度为640的页面效果图应该是怎样的? 点击浏览:一个标准的640手机页面设计稿参考(没错,在此方案中,你可以完全按照这张设计稿的尺寸写布局了。就是这么简单!) 8.问:用了这个方案如何使用媒体查询呢? 一般来讲,使用了这个方案是没必要用媒体查询了,如果你必须要用,假设你要对 iphone5 (css像素宽度320px, 这里需要取其物理像素,也就是640)宽度下的类名做处理,你可以这样 @media screen and (max-width: 640px) {.yourLayout {width:100%;} } 9.问:可以提供下这个高清方案的源码吗? 'use strict';/ @param {Boolean} [normal = false] - 默认开启页面压缩以使页面高清; @param {Number} [baseFontSize = 100] - 基础fontSize, 默认100px; @param {Number} [fontscale = 1] - 有的业务希望能放大一定比例的字体;/const win = window;export default win.flex = (normal, baseFontSize, fontscale) => {const _baseFontSize = baseFontSize || 100;const _fontscale = fontscale || 1;const doc = win.document;const ua = navigator.userAgent;const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);let dpr = win.devicePixelRatio || 1;if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {// 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;dpr = 1;}const scale = normal ? 1 : 1 / dpr;let metaEl = doc.querySelector('meta[name="viewport"]');if (!metaEl) {metaEl = doc.createElement('meta');metaEl.setAttribute('name', 'viewport');doc.head.appendChild(metaEl);}metaEl.setAttribute('content', width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale});doc.documentElement.style.fontSize = normal ? '50px' : ${_baseFontSize / 2 dpr _fontscale}px;}; 10.问:我在使用 rem 布局进阶方案的时候遇到了XXX的问题,如何解决? 此方案久经考验,具有普遍适用性,自身出致命问题的情况很少,至少笔者是没遇到过。 绝大多数你遇到的问题,都是由于对rem布局理解不到位导致的。本文对rem布局做了大量的解释说明,配置了若干 demo,你可以把你遇到的问题放到demo里测试。遇到问题时,首先问自己,为什么这明显的错误大家没遇到就我遇到了?? 如果你真的经过充分验证,比对,确实是rem布局自身出了问题,那么请私信我,把还原问题场景的 demo 或者文件发给我。谢谢! 本篇文章为转载内容。原文链接:https://blog.csdn.net/hjhfreshman/article/details/88864894。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-23 12:01:53
133
转载
转载文章
...功能可以让您的应用以模块化、富交互的形式插入到多个使用场景中,比如 Google Search 和 Assistant。Slices 支持的交互包括 actions、开关、滑动条、滑动内容等等。 Slices 是让内容与用户联系的极佳方式,所以我们希望它可以在更多的场景中出现。除了在 Android P 上对这个功能进行了平台级别的整合外, Slices 的 API 和模板也加入到了 Android Jetpack 里。Android Jetpack 是我们全新打造的一套创建优秀应用的工具和库,通过 Android Jetpack,您制作的 Slices 能在 Kitkat (API 等级 19) 及更高版本上使用 —— 这覆盖了 95% 的已激活 Android 设备。我们也会定期更新 Slices 的模板来支持更多类型的场景和交互 (比如文本输入)。 请查阅上手指南以了解如何制作 Slices,使用 SliceViewer 工具查看您做好的 Slices。接下来,我们计划进一步拓展其使用场景,包括在其他 app 中展现您的 Slices。 · 通知智能回复 (Smart reply in notifications) 机器智能可以为用户体验带来非常积极的进化,Gmail 和 Inbox 里的智能回复功能已经成功地证明了这一点。在 Android P 中,通知消息也加入了智能回复功能,而且我们准备了 API 让您可以为用户带来更度身的使用感受。用来帮助您更轻松地在通知中生成回复的 ML Kit 很快就会到来,请 点击访问此网站 了解详情。 · 文本识别 (Text Classifier) 在 Android P 中,我们将识别文本的机器学习模型进行了扩展,使得它可以识别出诸如日期或航班号这样的信息,并通过 TextClassifier API 来让开发者使用到这些改进。我们还更新了 Linkify API 来利用文本识别的结果生成链接,并为用户提供了更多点击后的选项,从而让他们得以更快地进行下一步操作。当然,开发者也可以在给文本识别出来的信息添加链接时拥有更多的选项。智能 Linkify 在识别精准度以及速度上都有明显的提升。 这个模型现在正在通过 Google Play 进行更新,所以您的应用使用现有的 API 就可以享受到本次更新所带来的变化。在安装更新完的模型后,设备即可直接在本地识别文本里的各种信息,而且这些识别出来的信息只保存在您的手机上而不会通过网络流传出去。 请点击蓝色字体前往 “Android Developers 官方文档”查看详细说明 简洁 (Simplicity) 在 Android P,我们格外强调简洁,并据此改进 Android 的 UI 从而帮助用户们更流畅、更高效地完成操作。对开发者来说,简洁的系统则会帮助用户更容易查找、使用和管理您的应用。 · 全新系统导航 (New system navigation) 我们为 Android P 设计了全新的系统导航,只需使用下图中这个在所有界面中都能看到的小按钮,即可更轻松地访问手机主屏、概览页以及 Assistant。新导航系统也使多任务切换及发现关联应用变得更加简单。在概览页,用户可以拥有更大的视野来查看他们之前中断的操作,这自然也会让他们更容易找到并回到之前的应用中。概览页也提供了搜索、预测推荐应用以及上文提到的 App Actions,而且只需再多划一次即可进入所有应用的列表。 · 文字放大镜 (Text Magnifier) 在 Android P 中,我们加入了新的放大镜工具 (Magnifier widget),使选择文本和调整光标位置变得更加轻松。默认情况下,所有继承自 TextView 的类都会自动支持放大镜,但您也可以使用放大镜 API 将它添加到任何自定义的视图上,从而打造更多样化的体验。 · 后台限制 (Background restrictions) 用户可以更加简单地找到并管理那些在后台消耗电量的应用。通过 Android Vitals 积累下来的成果,Android 可以识别那些过度消耗电量的行为,如滥用唤醒锁定等。在 Android P 中,电池设置页面直接列出了这些过度消耗电量的应用,用户只需一次点击就可以限制它们在后台的活动。 一旦应用被限制,那么它的后台任务、警报、服务以及网络访问都会受限。想要避免被限制的话,请留意 Play Console 中的Android Vitals 控制面板,帮助您了解如何提高性能表现以及优化电量消耗。 后台限制能有效保护系统资源不被恶意消耗,从而确保开发者的应用在不同制造商的不同设备上也能拥有一个基础的合理的运行环境。虽然制造商可以在限制列表上额外添加限制的应用,但它们也必须在电池设置页面为用户开放这些限制的控制权。 我们添加了一个标准 API 来帮助应用知晓自己是否被限制,以及一个 ADB 命令来帮助开发者手动限制应用,从而进行测试。具体请参阅相关文档。接下来我们计划在 Play Console 的 Android Vitals 控制面板里添加一个统计数据,以展示应用受到限制的情况。 · 使用动态处理增强音频 (Enhanced audio with Dynamics Processing) Android P 在音频框架里加入了动态处理效果 (Dynamic Processing Effect) 来帮助开发者改善声音品质。通过动态处理,您可以分离出特定频率的声音,降低过大的音量,或者增强那些过小的音量。举例来说,即便说话者离麦克风较远,而且身处嘈杂或者被刺耳的各种环境音包围的地方,您的应用依然可以有效分离并增强他/她的细语。 动态处理 API 提供了多声场、多频段的动态处理效果,包括一个预均衡器、一个多频段压缩器,一个后均衡器以及一个串联的音量限制器。这样您就可以根据用户的喜好或者环境的变化来控制 Android 设备输出的声音。频段数量以及各个声场的开关都完全可控,大多数参数都支持实时控制,如增益、信号的压缩/释放 (attack/release) 时长,阈值等等。 请点击蓝色字体前往 “Android Developers 官方文档”查看详细说明 安全 (Security) · 用户识别提示 (Biometric prompt) Android P 为市面上涌现出来的各种用户识别机制在系统层面提供了统一的使用体验,应用们不再需要自行提供用户识别操作界面,而只需要使用统一的 BiometricPrompt API 即可。这套全新的 API 替代了 DP1 版本中的 FingerprintDialog API,且支持包括指纹识别 (包括屏幕下指纹识别)、面部识别以及虹膜识别,而且所有系统支持的用户识别需求都包含在一个 USE_BIOMETRIC 权限里。FingerprintManager 以及对应的 USE_FINGERPRINT 权限已经被废弃,请开发者尽快转用 BiometricPrompt。 · 受保护的确认操作 (Protected Confirmation) Android P 新增了受保护的确认操作 (Android Protected Confirmation),这个功能使用可信执行环境 (Trusted Execution Environment, TEE) 来确保一个显示出来的提示文本被真实用户确认。只有在用户确认之后,TEE 才会放行这个文本并可由应用去验证。 · 对私有密钥的增强保护 (Stronger protection for private keys) 我们添加了一个新的 KeyStore 类型,StrongBox。并提供对应的 API 来支持那些提供了防入侵硬件措施的设备,比如独立的 CPU,内存以及安全存储。您可以在 KeyGenParameterSpec 里决定您的密钥是否该交给 StrongBox 安全芯片来保存。 Android P Beta 为用户带来新版本的 Android 需要 Google、芯片供应商以及设备制造商和运营商的共同努力。这个过程中充满了技术挑战,并非一日之功 —— 为了让这个过程更加顺畅,去年我们启动了 Project Treble,并将其包含在 Android Oreo 中。我们与合作伙伴们一直在努力开发这个项目,也已经看到 Treble 所能带来的机遇。 我们宣布,以下 6 家顶级合作伙伴将和我们一起把 Android P Beta 带给全世界的用户,这些设备包括:索尼 Xperia XZ2, 小米 Mi Mix 2S, 诺基亚 7 Plus, Oppo R15 Pro, Vivo X21UD 和 X21, 以及 Essential PH‑1。此外,再加上 Pixel 2, Pixel 2 XL, Pixel 和 Pixel XL,我们希望来自世界各地的早期体验者以及开发者们都能通过这些设备体验到 Android P Beta。 您可查看今天推送的文章查阅支持 beta 体验的合作伙伴和 Pixel 设备清单,并能看到每款设备的详细配置说明。如果您使用 Pixel 设备,现在就可以加入 Android Beta program,然后自动获得最新的 Android P Beta。 马上开始在您喜欢的设备上体验 Android P Beta 吧,欢迎您向我们反馈意见和建议!并请继续关注 Project Treble 的最新动态。 确保 app 兼容 随着越来越多的用户开始体验 Android P Beta,是时候开始测试您 app 的兼容性,以尽早解决在测试中发现的问题并尽快发布更新。请查看迁移手册了解操作步骤以及 Android P 的时间推进表。 请从 Google Play 下载您的应用,并在运行 Android P Beta 的设备或模拟器上测试用户流程。确保您的应用体验良好,并正确处理 Android P 的行为变更。尤其注意动态电量管理、Wi-Fi 权限变化、后台调用摄像头以及传感器的限制、针对应用数据的 SELinux 政策、默认启用 TLS 的变化,以及 Build.SERIAL 限制。 · 公开 API 的兼容性 (Compatibility through public APIs) 针对非 SDK 接口的测试十分重要。正如我们之前所强调的,在 Android P 中,我们将逐渐收紧一些非 SDK 接口的使用,这也要求广大的开发者们,包括 Google 内部的应用团队,使用公开 API。 如果您的应用正在使用私有 Android API 或者库,您需要改为使用 Android SDK 或 NDK 公开的 API。我们在 DP1 里已经对使用私有接口的开发者发出了警告信息,从 Android P Beta 开始,调用非 SDK 接口将会报错 (部分被豁免的私有 API 除外) —— 也就是说您的应用将会遭遇异常,而不再只是警告了。 为了帮助您定位非 SDK API 的使用情况,我们在 StrictMode 里加入了两个新的方法。您可以使用 detectNonSdkApiUsage() 在应用通过反射或 JNI 调用非 SDK API 的时候收到警报,您还可以使用 permitNonSdkApiUsage() 来阻止 StrictMode 针对这些调用报错。这些方法都可助您了解应用调用非 SDK API 的情况,但请注意,即便调用的 API 暂时得到了豁免,最保险的做法依然是尽快放弃对它们的使用。 如果您确实遇到了公开 API 无法满足需求的情况,请立刻告知我们。更多详细内容请查看相关文档。 · 凹口屏测试 (Test with display cutout) 针对凹口屏测试您的应用也十分重要。现在您可以在运行 Android P Beta 的合作伙伴机型上测试,确保您的应用在凹口屏上表现良好。同时,您也可以在 Android P 设备的开发者选项里打开对凹口屏的模拟,对您的应用做相应测试。 体验 Android P 在准备好开发条件后,请深入了解 Android P 并学习可以在您的应用中使用到的全新功能和 API。为了帮助您更轻松地探索和使用新 API,请查阅 API 变化报告 (API 27->DP2, DP1->DP2) 以及 Android P API 文档。访问开发者预览版网站了解详情。 下载/更新 Android P 开发者预览版 SDK 和工具包至 Android Studio 3.1,或使用最新版本的 Android Studio 3.2。如果您手边没有 Android P Beta 设备 (或查看今天推送的次条文章),请使用 Android P 模拟器来运行和测试您的应用。 您的反馈一直都至关重要,我们欢迎您畅所欲言。如果您在开发或测试过程中遇到了问题,请在文章下方留言给我们。再次感谢大家一路以来的支持。 请点击蓝色字体前往 “Android Developers 官方文档”查看详细说明 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_34258782/article/details/87952581。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-10 18:19:36
338
转载
转载文章
...全相同,仅仅是数据和配置不同的合并为一类,且分析判定确认有恶意代码的,共归纳为 21个各异的恶意OpenSSH家族; ·在21个恶意家族中,有12个家族在10月份时完全没有被公开发现分析过;而剩余的有一部分使用了历史上披露的恶意代码样本,甚至有源代码; ·所有恶意样本的实现,从实现复杂度、代码混淆和自我保护程度到代码特征有很大跨度的不同,但整体看,目的以偷取用户凭证等敏感信息、回连外传到攻击者为主,其中有的攻击者回连地址已经存在并活跃数年之久; ·这些后门的操控者,既有传统恶意软件黑产人员,也有APT组织; ·所有恶意软件或多或少都在被害主机上有未抹除的痕迹。ESET研究者尝试使用蜜罐引诱出攻击者,但仍有许多未解之谜。这场对抗,仍未取胜。 白皮书用了大篇幅做技术分析报告,此处供细节分析,不展开分析,以下为根据恶意程序复杂度描绘的21个家族图谱: 问题思考 问题引入的可能渠道,我在开头进行了一点推测,主要是由人的原因切入的,除此以外,最可能的是恶意攻击者在利用各种方法入侵目标主机后,主动替换了目标OpenSSH为恶意版本,从而达成攻击持久化操作。但是这些都是止血的安全运维人员该考虑的事情;关键问题是,透过表象,这显露了什么威胁形式? 这个问题很好回答,之前也曾经反复说过:基础软件碎片化。 如上一章节简单提到,在开发过程中有各种可能的渠道引入开发者不完全了解和信任的代码;在运维过程中也是如此。二者互相作用,造成了软件碎片化的庞杂现状。在企业内部,同一份基础软件库,可能不同的业务线各自定制一份,放到企业私有软件仓库源中,有些会有人持续更新供自己产品使用,有些由系统软件基础设施维护人员单独维护,有些则可能是开发人员临时想起来上传的,他们自己都不记得;后续用到的这个基础软件的开发和团队,在这个源上搜索到已有的库,很大概率会倾向于直接使用,不管来源、是否有质量背书等。长此以往问题会持续发酵。而我们开最坏的脑洞,是否可能有黑产人员入职到内部,提交个恶意基础库之后就走人的可能?现行企业安全开发流程中审核机制的普遍缺失给这留下了空位。 将源码来源碎片化与二进制使用碎片化并起来考虑,我们不难看到一个远远超过OpenSSH事件威胁程度的图景。但这个问题不是仅仅靠开发阶段规约、运维阶段规范、企业内部管控、行业自查、政府监管就可以根除的,最大的问题归根结底两句话: 不可能用一场战役对抗持续威胁;不可能用有限分析对抗无限未知。 Ⅲ. 从自信到自省:RHEL、CentOS backport版本BIND漏洞 2018年12月20日凌晨,在备战冬至的软件供应链安全大赛决赛时,我注意到漏洞预警平台捕获的一封邮件。但这不是一个漏洞初始披露邮件,而是对一个稍早已披露的BIND在RedHat、CentOS发行版上特定版本的1day漏洞CVE-2018-5742,由BIND的官方开发者进行额外信息澄(shuǎi)清(guō)的邮件。 一些必要背景 关于BIND 互联网的一个古老而基础的设施是DNS,这个概念在读者不应陌生。而BIND“是现今互联网上最常使用的DNS软件,使用BIND作为服务器软件的DNS服务器约占所有DNS服务器的九成。BIND现在由互联网系统协会负责开发与维护参考。”所以BIND的基础地位即是如此,因此也一向被大量白帽黑帽反复测试、挖掘漏洞,其开发者大概也一直处在紧绷着应对的处境。 关于ISC和RedHat 说到开发者,上面提到BIND的官方开发者是互联网系统协会(ISC)。ISC是一个老牌非营利组织,目前主要就是BIND和DHCP基础设施的维护者。而BIND本身如同大多数历史悠久的互联网基础开源软件,是4个UCB在校生在DARPA资助下于1984年的实验室产物,直到2012年由ISC接管。 那么RedHat在此中是什么角色呢?这又要提到我之前提到的Linux发行版和自带软件维护策略。Red Hat Enterprise Linux(RHEL)及其社区版CentOS秉持着稳健的软件策略,每个大的发行版本的软件仓库,都只选用最必要且质量久经时间考验的软件版本,哪怕那些版本实在是老掉牙。这不是一种过分的保守,事实证明这种策略往往给RedHat用户在最新漏洞面前提供了保障——代码总是跑得越少,潜在漏洞越多。 但是这有两个关键问题。一方面,如果开源基础软件被发现一例有历史沿革的代码漏洞,那么官方开发者基本都只为其最新代码负责,在当前代码上推出修复补丁。另一方面,互联网基础设施虽然不像其上的应用那样爆发性迭代,但依然持续有一些新特性涌现,其中一些是必不可少的,但同样只在最新代码中提供。两个刚需推动下,各Linux发行版对长期支持版本系统的软件都采用一致的策略,即保持其基础软件在一个固定的版本,但对于这些版本软件的最新漏洞、必要的最新软件特性,由发行版维护者将官方开发者最新代码改动“向后移植”到旧版本代码中,即backport。这就是基础软件的“官宣”碎片化的源头。 讲道理,Linux发行版维护者与社区具有比较靠谱的开发能力和监督机制,backport又基本就是一些复制粘贴工作,应当是很稳当的……但真是如此吗? CVE-2018-5742漏洞概况 CVE-2018-5742是一个简单的缓冲区溢出类型漏洞,官方评定其漏洞等级moderate,认为危害不大,漏洞修复不积极,披露信息不多,也没有积极给出代码修复patch和新版本rpm包。因为该漏洞仅在设置DEBUG_LEVEL为10以上才会触发,由远程攻击者构造畸形请求造成BIND服务崩溃,在正常的生产环境几乎不可能具有危害,RedHat官方也只是给出了用户自查建议。 这个漏洞只出现在RHEL和CentOS版本7中搭载的BIND 9.9.4-65及之后版本。RedHat同ISC的声明中都证实,这个漏洞的引入原因,是RedHat在尝试将BIND 9.11版本2016年新增的NTA机制向后移植到RedHat 7系中固定搭载的BIND 9.9版本代码时,偶然的代码错误。NTA是DNS安全扩展(DNSSEC)中,用于在特定域关闭DNSSEC校验以避免不必要的校验失败的机制;但这个漏洞不需要对NTA本身有进一步了解。 漏洞具体分析 官方没有给出具体分析,但根据CentOS社区里先前有用户反馈的bug,我得以很容易还原漏洞链路并定位到根本原因。 若干用户共同反馈,其使用的BIND 9.9.4-RedHat-9.9.4-72.el7发生崩溃(coredump),并给出如下的崩溃时调用栈backtrace: 这个调用过程的逻辑为,在9 dns_message_logfmtpacket函数判断当前软件设置是否DEBUG_LEVEL大于10,若是,对用户请求数据包做日志记录,先后调用8 dns_message_totext、7 dns_message_sectiontotext、6 dns_master_rdatasettotext、5 rdataset_totext将请求进行按协议分解分段后写出。 由以上关键调用环节,联动RedHat在9.9.4版本BIND源码包中关于引入NTA特性的源码patch,进行代码分析,很快定位到问题产生的位置,在上述backtrace中的5,masterdump.c文件rdataset_totext函数。漏洞相关代码片段中,RedHat进行backport后,这里引入的代码为: 这里判断对于请求中的注释类型数据,直接通过isc_buffer_putstr宏对缓存进行操作,在BIND工程中自定义维护的缓冲区结构对象target上,附加一字节字符串(一个分号)。而漏洞就是由此产生:isc_buffer_putstr中不做缓冲区边界检查保证,这里在缓冲区已满情况下将造成off-by-one溢出,并触发了缓冲区实现代码中的assertion。 而ISC上游官方版本的代码在这里是怎么写的呢?找到ISC版本BIND 9.11代码,这里是这样的: 这里可以看到,官方代码在做同样的“附加一个分号”这个操作时,审慎的使用了做缓冲区剩余空间校验的str_totext函数,并额外做返回值成功校验。而上述提到的str_totext函数与RETERR宏,在移植版本的masterdump.c中,RedHat开发者也都做了保留。但是,查看代码上下文发现,在RedHat开发者进行代码移植过程中,对官方代码进行了功能上的若干剪裁,包括一些细分数据类型记录的支持;而这里对缓冲区写入一字节,也许开发者完全没想到溢出的可能,所以自作主张地简化了代码调用过程。 问题思考 这个漏洞本身几乎没什么危害,但是背后足以引起思考。 没有人在“借”别人代码时能不出错 不同于之前章节提到的那种场景——将代码文件或片段复制到自己类似的代码上下文借用——backport作为一种官方且成熟的做法,借用的代码来源、粘贴到的代码上下文,是具有同源属性的,而且开发者一般是追求稳定性优先的社区开发人员,似乎质量应该有足够保障。但是这里的关键问题是:代码总要有一手、充分的语义理解,才能有可信的使用保障;因此,只要是处理他人的代码,因为不够理解而错误使用的风险,只可能减小,没办法消除。 如上分析,本次漏洞的产生看似只是做代码移植的开发者“自作主张”之下“改错了”。但是更广泛且可能的情况是,原始开发者在版本迭代中引入或更新大量基础数据结构、API的定义,并用在新的特性实现代码中;而后向移植开发人员仅需要最小规模的功能代码,所以会对增量代码进行一定规模的修改、剪裁、还原,以此适应旧版本基本代码。这些过程同样伴随着第三方开发人员不可避免的“望文生义”,以及随之而来的风险。后向移植操作也同样助长了软件碎片化过程,其中每一个碎片都存在这样的问题;每一个碎片在自身生命周期也将有持续性影响。 多级复制粘贴无异于雪上加霜 这里简单探讨的是企业通行的系统和基础软件建设实践。一些国内外厂商和社区发布的定制化Linux发行版,本身是有其它发行版,如CentOS特定版本渊源的,在基础软件上即便同其上游发行版最新版本间也存在断层滞后。RedHat相对于基础软件开发者之间已经隔了一层backport,而我们则人为制造了二级风险。 在很多基础而关键的软件上,企业系统基础设施的维护者出于与RedHat类似的初衷,往往会决定自行backport一份拷贝;通过早年心脏滴血事件的洗礼,即暴露出来OpenSSL一个例子。无论是需要RHEL还没来得及移植的新版本功能特性,还是出于对特殊使用上下文场景中更高执行效率的追求,企业都可能自行对RHEL上基础软件源码包进行修改定制重打包。这个过程除了将风险幂次放大外,也进一步加深了代码的不可解释性(包括基础软件开发人员流动性带来的不可解释)。 Ⅳ. 从武功到死穴:从systemd-journald信息泄露一窥API误用 1月10日凌晨两点,漏洞预警平台爬收取一封漏洞披露邮件。披露者是Qualys,那就铁定是重型发布了。最后看披露漏洞的目标,systemd?这就非常有意思了。 一些必要背景 systemd是什么,不好简单回答。Linux上面软件命名,习惯以某软件名后带个‘d’表示后台守护管理程序;所以systemd就可以说是整个系统的看守吧。而即便现在描述了systemd是什么,可能也很快会落伍,因为其初始及核心开发者Lennart Poettering(供职于Red Hat)描述它是“永无开发完结完整、始终跟进技术进展的、统一所有发行版无止境的差异”的一种底层软件。笼统讲有三个作用:中央化系统及设置管理;其它软件开发的基础框架;应用程序和系统内核之间的胶水。如今几乎所有Linux发行版已经默认提供systemd,包括RHEL/CentOS 7及后续版本。总之很基础、很底层、很重要就对了。systemd本体是个主要实现init系统的框架,但还有若干关键组件完成其它工作;这次被爆漏洞的是其journald组件,是负责系统事件日志记录的看守程序。 额外地还想简单提一句Qualys这个公司。该公司创立于1999年,官方介绍为信息安全与云安全解决方案企业,to B的安全业务非常全面,有些也是国内企业很少有布局的方面;例如上面提到的涉及碎片化和代码移植过程的历史漏洞移动,也在其漏洞管理解决方案中有所体现。但是我们对这家公司粗浅的了解来源于其安全研究团队近几年的发声,这两年间发布过的,包括有『stack clash』、『sudo get_tty_name提权』、『OpenSSH信息泄露与堆溢出』、『GHOST:glibc gethostbyname缓冲区溢出』等大新闻(仅截至2017年年中)。从中可见,这个研究团队专门啃硬骨头,而且还总能开拓出来新的啃食方式,往往爆出来一些别人没想到的新漏洞类型。从这个角度,再联想之前刷爆朋友圈的《安全研究者的自我修养》所倡导的“通过看历史漏洞、看别人的最新成果去举一反三”的理念,可见差距。 CVE-2018-16866漏洞详情 这次漏洞披露,打包了三个漏洞: ·16864和16865是内存破坏类型 ·16866是信息泄露 ·而16865和16866两个漏洞组和利用可以拿到root shell。 漏洞分析已经在披露中写的很详细了,这里不复述;而针对16866的漏洞成因来龙去脉,Qualys跟踪的结果留下了一点想象和反思空间,我们来看一下。 漏洞相关代码片段是这样的(漏洞修复前): 读者可以先肉眼过一遍这段代码有什么问题。实际上我一开始也没看出来,向下读才恍然大悟。 这段代码中,外部信息输入通过buf传入做记录处理。输入数据一般包含有空白字符间隔,需要分隔开逐个记录,有效的分隔符包括空格、制表符、回车、换行,代码中将其写入常量字符串;在逐字符扫描输入数据字符串时,将当前字符使用strchr在上述间隔符字符串中检索是否匹配,以此判断是否为间隔符;在240行,通过这样的判断,跳过记录单元字符串的头部连续空白字符。 但是问题在于,strchr这个极其基础的字符串处理函数,对于C字符串终止字符'\0'的处理上有个坑:'\0'也被认为是被检索字符串当中的一个有效字符。所以在240行,当当前扫描到的字符为字符串末尾的NULL时,strchr返回的是WHITESPACE常量字符串的终止位置而非NULL,这导致了越界。 看起来,这是一个典型的问题:API误用(API mis-use),只不过这个被误用的库函数有点太基础,让我忍不住想是不是还会有大量的类似漏洞……当然也反思我自己写的代码是不是也有同样情况,然而略一思考就释然了——我那么笨的代码都用for循环加if判断了:) 漏洞引入和消除历史 有意思的是,Qualys研究人员很贴心地替我做了一步漏洞成因溯源,这才是单独提这个漏洞的原因。漏洞的引入是在2015年的一个commit中: 在GitHub中,定位到上述2015年的commit信息,这里commit的备注信息为: journald: do not strip leading whitespace from messages. Keep leading whitespace for compatibility with older syslog implementations. Also useful when piping formatted output to the logger command. Keep removing trailing whitespace. OK,看起来是一个兼容性调整,对记录信息不再跳过开头所有连续空白字符,只不过用strchr的简洁写法比较突出开发者精炼的开发风格(并不),说得过去。 之后在2018年八月的一个当时尚未推正式版的另一次commit中被修复了,先是还原成了ec5ff4那次commit之前的写法,然后改成了加校验的方式: 虽然Qualys研究者认为上述的修改是“无心插柳”的改动,但是在GitHub可以看到,a6aadf这次commit是因为有外部用户反馈了输入数据为单个冒号情况下journald堆溢出崩溃的issue,才由开发者有目的性地修复的;而之后在859510这个commit再次改动回来,理由是待记录的消息都是使用单个空格作为间隔符的,而上一个commit粗暴地去掉了这种协议兼容性特性。 如果没有以上纠结的修改和改回历史,也许我会倾向于怀疑,在最开始漏洞引入的那个commit,既然改动代码没有新增功能特性、没有解决什么问题(毕竟其后三年,这个改动的代码也没有被反映issue),也并非出于代码规范等考虑,那么这么轻描淡写的一次提交,难免有人为蓄意引入漏洞的嫌疑。当然,看到几次修复的原因,这种可能性就不大了,虽然大家仍可以保留意见。但是抛开是否人为这个因素,单纯从代码的漏洞成因看,一个传统但躲不开的问题仍值得探讨:API误用。 API误用:程序员何苦为难程序员 如果之前的章节给读者留下了我反对代码模块化和复用的印象,那么这里需要正名一下,我们认可这是当下开发实践不可避免的趋势,也增进了社会开发速度。而API的设计决定了写代码和用代码的双方“舒适度”的问题,由此而来的API误用问题,也是一直被当做单纯的软件工程课题讨论。在此方面个人并没有什么研究,自然也没办法系统地给出分类和学术方案,只是谈一下自己的经验和想法。 一篇比较新的学术文章总结了API误用的研究,其中一个独立章节专门分析Java密码学组件API误用的实际,当中引述之前论文认为,密码学API是非常容易被误用的,比如对期望输入数据(数据类型,数据来源,编码形式)要求的混淆,API的必需调用次序和依赖缺失(比如缺少或冗余多次调用了初始化函数、主动资源回收函数)等。凑巧在此方面我有一点体会:曾经因为业务方需要,需要使用C++对一个Java的密码基础中间件做移植。Java对密码学组件支持,有原生的JDK模块和权威的BouncyCastle包可用;而C/C++只能使用第三方库,考虑到系统平台最大兼容和最小代码量,使用Linux平台默认自带的OpenSSL的密码套件。但在开发过程中感受到了OpenSSL满满的恶意:其中的API设计不可谓不反人类,很多参数没有明确的说明(比如同样是表示长度的函数参数,可能在不同地方分别以字节/比特/分组数为计数单位);函数的线程安全没有任何解释标注,需要自行试验;不清楚函数执行之后,是其自行做了资源释放还是需要有另外API做gc,不知道资源释放操作时是否规规矩矩地先擦除后释放……此类问题不一而足,导致经过了漫长的测试之后,这份中间件才提供出来供使用。而在业务场景中,还会存在比如其它语言调用的情形,这些又暴露出来OpenSSL API误用的一些完全无从参考的问题。这一切都成为了噩梦;当然这无法为我自己开解是个不称职开发的指责,但仅就OpenSSL而言其API设计之恶劣也是始终被人诟病的问题,也是之后其他替代者宣称改进的地方。 当然,问题是上下游都脱不了干系的。我们自己作为高速迭代中的开发人员,对于二方、三方提供的中间件、API,又有多少人能自信地说自己仔细、认真地阅读过开发指南和API、规范说明呢?做过通用产品技术运营的朋友可能很容易理解,自己产品的直接用户日常抛出不看文档的愚蠢问题带来的困扰。对于密码学套件,这个问题还好办一些,毕竟如果在没有背景知识的情况下对API望文生义地一通调用,绝大多数情况下都会以抛异常形式告终;但还是有很多情况,API误用埋下的是长期隐患。 不是所有API误用情形最终都有机会发展成为可利用的安全漏洞,但作为一个由人的因素引入的风险,这将长期存在并困扰软件供应链(虽然对安全研究者、黑客与白帽子是很欣慰的事情)。可惜,传统的白盒代码扫描能力,基于对代码语义的理解和构建,但是涉及到API则需要预先的抽象,这一点目前似乎仍然是需要人工干预的事情;或者轻量级一点的方案,可以case by case地分析,为所有可能被误用的API建模并单独扫描,这自然也有很强局限性。在一个很底层可信的开发者还对C标准库API存在误用的现实内,我们需要更多的思考才能说接下来的解法。 Ⅴ. 从规则到陷阱:NASA JIRA误配置致信息泄露血案 软件的定义包括了代码组成的程序,以及相关的配置、文档等。当我们说软件的漏洞、风险时,往往只聚焦在其中的代码中;关于软件供应链安全风险,我们的比赛、前面分析的例子也都聚焦在了代码的问题;但是真正的威胁都来源于不可思议之处,那么代码之外有没有可能存在来源于上游的威胁呢?这里就借助实例来探讨一下,在“配置”当中可能栽倒的坑。 引子:发不到500英里以外的邮件? 让我们先从一个轻松愉快的小例子引入。这个例子初见于Linux中国的一篇译文。 简单说,作者描述了这么一个让人啼笑皆非的问题:单位的邮件服务器发送邮件,发送目标距离本地500英里范围之外的一律失败,邮件就像悠悠球一样只能飞出一定距离。这个问题本身让描述者感到尴尬,就像一个技术人员被老板问到“为什么从家里笔记本上Ctrl-C后不能在公司台式机上Ctrl-V”一样。 经过令人窒息的分析操作后,笔者定位到了问题原因:笔者作为负责的系统管理员,把SunOS默认安装的Senmail从老旧的版本5升级到了成熟的版本8,且对应于新版本诸多的新特性进行了对应配置,写入配置文件sendmail.cf;但第三方服务顾问在对单位系统进行打补丁升级维护时,将系统软件“升级”到了系统提供的最新版本,因此将Sendmail实际回退到了版本5,却为了软件行为一致性,原样保留了高版本使用的配置文件。但Sendmail并没有在大版本间保证配置文件兼容性,这导致很多版本5所需的配置项不存在于保留下来的sendmail.cf文件中,程序按默认值0处理;最终引起问题的就是,邮件服务器与接收端通信的超时时间配置项,当取默认配置值0时,邮件服务器在1个单位时间(约3毫秒)内没有收到网络回包即认为超时,而这3毫秒仅够电信号打来回飞出500英里。 这个“故事”可能会给技术人员一点警醒,错误的配置会导致预期之外的软件行为,但是配置如何会引入软件供应链方向的安全风险呢?这就引出了下一个重磅实例。 JIRA配置错误致NASA敏感信息泄露案例 我们都听过一个事情,马云在带队考察美国公司期间问Google CEO Larry Page自视谁为竞争对手,Larry的回答是NASA,因为最优秀的工程师都被NASA的梦想吸引过去了。由此我们显然能窥见NASA的技术水位之高,这样的人才团队大概至少是不会犯什么低级错误的。 但也许需要重新定义“低级错误”……1月11日一篇技术文章披露,NASA某官网部署使用的缺陷跟踪管理系统JIRA存在错误的配置,可分别泄漏内部员工(JIRA系统用户)的全部用户名和邮件地址,以及内部项目和团队名称到公众,如下: 问题的原因解释起来也非常简单:JIRA系统的过滤器和配置面板中,对于数据可见性的配置选项分别选定为All users和Everyone时,系统管理人员想当然地认为这意味着将数据对所有“系统用户”开放查看,但是JIRA的这两个选项的真实效果逆天,是面向“任意人”开放,即不限于系统登录用户,而是任何查看页面的人员。看到这里,我不厚道地笑了……“All users”并不意味着“All ‘users’”,意不意外,惊不惊喜? 但是这种字面上把戏,为什么没有引起NASA工程师的注意呢,难道这样逆天的配置项没有在产品手册文档中加粗标红提示吗?本着为JIRA产品设计找回尊严的态度,我深入挖掘了一下官方说明,果然在Atlassian官方的一份confluence文档(看起来更像是一份增补的FAQ)中找到了相关说明: 所有未登录访客访问时,系统默认认定他们是匿名anonymous用户,所以各种权限配置中的all users或anyone显然应该将匿名用户包括在内。在7.2及之后版本中,则提供了“所有登录用户”的选项。 可以说是非常严谨且贴心了。比较讽刺的是,在我们的软件供应链安全大赛·C源代码赛季期间,我们设计圈定的恶意代码攻击目标还包括JIRA相关的敏感信息的窃取,但是却想不到有这么简单方便的方式,不动一行代码就可以从JIRA中偷走数据。 软件的使用,你“配”吗? 无论是开放的代码还是成型的产品,我们在使用外部软件的时候,都是处于软件供应链下游的消费者角色,为了要充分理解上游开发和产品的真实细节意图,需要我们付出多大的努力才够“资格”? 上一章节我们讨论过源码使用中必要细节信息缺失造成的“API误用”问题,而软件配置上的“误用”问题则复杂多样得多。从可控程度上讨论,至少有这几种因素定义了这个问题: ·软件用户对必要配置的现有文档缺少了解。这是最简单的场景,但又是完全不可避免的,这一点上我们所有有开发、产品或运营角色经验的应该都曾经体会过向不管不顾用户答疑的痛苦,而所有软件使用者也可以反省一下对所有软件的使用是否都以完整细致的文档阅读作为上手的准备工作,所以不必多说。 ·软件拥有者对配置条目缺少必要明确说明文档。就JIRA的例子而言,将NASA工程师归为上一条错误有些冤枉,而将JIRA归为这条更加合适。在边角但重要问题上的说明通过社区而非官方文档形式发布是一种不负责任的做法,但未引发安全事件的情况下还有多少这样的问题被默默隐藏呢?我们没办法要求在使用软件之前所有用户将软件相关所有文档、社区问答实现全部覆盖。这个问题范围内一个代表性例子是对配置项的默认值以及对应效果的说明缺失。 ·配置文件版本兼容性带来的误配置和安全问题。实际上,上面的SunOS Sendmail案例足以点出这个问题的存在性,但是在真实场景下,很可能不会以这么戏剧性形式出现。在企业的系统运维中,系统的版本迭代常见,但为软件行为一致性,配置的跨版本迁移是不可避免的操作;而且软件的更新迭代也不只会由系统更新推动,还有大量出于业务性能要求而主动进行的定制化升级,对于中小企业基础设施建设似乎是一个没怎么被提及过的问题。 ·配置项组合冲突问题。尽管对于单个配置项可能明确行为与影响,但是特定的配置项搭配可能造成不可预知的效果。这完全有可能是由于开发者与用户在信息不对等的情况下产生:开发者认为用户应该具有必需的背景知识,做了用户应当具备规避配置冲突能力的假设。一个例子是,对称密码算法在使用ECB、CBC分组工作模式时,从密码算法上要求输入数据长度必须是分组大小的整倍数,但如果用户搭配配置了秘钥对数据不做补齐(nopadding),则引入了非确定性行为:如果密码算法库对这种组合配置按某种默认补齐方式操作数据则会引起歧义,但如果在算法库代码层面对这种组合抛出错误则直接影响业务。 ·程序对配置项处理过程的潜在暗箱操作。这区别于简单的未文档化配置项行为,仅特指可能存在的蓄意、恶意行为。从某种意义上,上述“All users”也可以认为是这样的一种陷阱,通过浅层次暗示,引导用户做出错误且可能引起问题的配置。另一种情况是特定配置组合情况下触发恶意代码的行为,这种触发条件将使恶意代码具有规避检测的能力,且在用户基数上具有一定概率的用户命中率。当然这种情况由官方开发者直接引入的可能性很低,但是在众包开发的情况下如果存在,那么扫描方案是很难检测的。 Ⅵ. 从逆流到暗流:恶意代码溯源后的挑战 如果说前面所说的种种威胁都是面向关键目标和核心系统应该思考的问题,那么最后要抛出一个会把所有人拉进赛场的理由。除了前面所有那些在软件供应链下游被动污染受害的情况,还有一种情形:你有迹可循的代码,也许在不经意间会“反哺”到黑色产业链甚至特殊武器中;而现在研究用于对程序进行分析和溯源的技术,则会让你陷入百口莫辩的境地。 案例:黑产代码模块溯源疑云 1月29日,猎豹安全团队发布技术分析通报文章《电信、百度客户端源码疑遭泄漏,驱魔家族窃取隐私再起波澜》,矛头直指黑产上游的恶意信息窃取代码模块,认定其代码与两方产品存在微妙的关联:中国电信旗下“桌面3D动态天气”等多款软件,以及百度旗下“百度杀毒”等软件(已不可访问)。 文章中举证有三个关键点。 首先最直观的,是三者使用了相同的特征字符串、私有文件路径、自定义内部数据字段格式; 其次,在关键代码位置,三者在二进制程序汇编代码层面具有高度相似性; 最终,在一定范围的非通用程序逻辑上,三者在经过反汇编后的代码语义上显示出明显的雷同,并提供了如下两图佐证(图片来源): 文章指出的涉事相关软件已经下线,对于上述样本文件的相似度试验暂不做复现,且无法求证存在相似、疑似同源的代码在三者中占比数据。对于上述指出的代码雷同现象,猎豹安全团队认为: 我们怀疑该病毒模块的作者通过某种渠道(比如“曾经就职”),掌握有中国电信旗下部分客户端/服务端源码,并加以改造用于制作窃取用户隐私的病毒,另外在该病毒模块的代码中,我们还发现“百度”旗下部分客户端的基础调试日志函数库代码痕迹,整个“驱魔”病毒家族疑点重重,其制作传播背景愈发扑朔迷离。 这样的推断,固然有过于直接的依据(例如三款代码中均使用含有“baidu”字样的特征注册表项);但更进一步地,需要注意到,三个样本在所指出的代码位置,具有直观可见的二进制汇编代码结构的相同,考虑到如果仅仅是恶意代码开发者先逆向另外两份代码后借鉴了代码逻辑,那么在面临反编译、代码上下文适配重构、跨编译器和选项的编译结果差异等诸多不确定环节,仍能保持二进制代码的雷同,似乎确实是只有从根本上的源代码泄漏(抄袭)且保持相同的开发编译环境才能成立。 但是我们却又无法做出更明确的推断。这一方面当然是出于严谨避免过度解读;而从另一方面考虑,黑产代码的一个关键出发点就是“隐藏自己”,而这里居然如此堂而皇之地照搬了代码,不但没有进行任何代码混淆、变形,甚至没有抹除疑似来源的关键字符串,如果将黑产视为智商在线的对手,那这里背后是否有其它考量,就值得琢磨了。 代码的比对、分析、溯源技术水准 上文中的安全团队基于大量样本和粗粒度比对方法,给出了一个初步的判断和疑点。那么是否有可能获得更确凿的分析结果,来证实或证伪同源猜想呢? 无论是源代码还是二进制,代码比对技术作为一种基础手段,在软件供应链安全分析上都注定仍然有效。在我们的软件供应链安全大赛期间,针对PE二进制程序类型的题目,参赛队伍就纷纷采用了相关技术手段用于目标分析,包括:同源性分析,用于判定与目标软件相似度最高的同软件官方版本;细粒度的差异分析,用于尝试在忽略编译差异和特意引入的混淆之外,定位特意引入的恶意代码位置。当然,作为比赛中针对性的应对方案,受目标和环境引导约束,这些方法证明了可行性,却难以保证集成有最新技术方案。那么做一下预言,在不计入情报辅助条件下,下一代的代码比对将能够到达什么水准? 这里结合近一年和今年内,已发表和未发表的学术领域顶级会议的相关文章来简单展望: ·针对海量甚至全量已知源码,将可以实现准确精细化的“作者归属”判定。在ACM CCS‘18会议上曾发表的一篇文章《Large-Scale and Language-Oblivious Code Authorship Identification》,描述了使用RNN进行大规模代码识别的方案,在圈定目标开发者,并预先提供每个开发者的5-7份已知的代码文件后,该技术方案可以很有效地识别大规模匿名代码仓库中隶属于每个开发者的代码:针对1600个Google Code Jam开发者8年间的所有代码可以实现96%的成功识别率,而针对745个C代码开发者于1987年之后在GitHub上面的全部公开代码仓库,识别率也高达94.38%。这样的结果在当下的场景中,已经足以实现对特定人的代码识别和跟踪(例如,考虑到特定开发人员可能由于编码习惯和规范意识,在时间和项目跨度上犯同样的错误);可以预见,在该技术方向上,完全可以期望摆脱特定已知目标人的现有数据集学习的过程,并实现更细粒度的归属分析,例如代码段、代码行、提交历史。 ·针对二进制代码,更准确、更大规模、更快速的代码主程序分析和同源性匹配。近年来作为一项程序分析基础技术研究,二进制代码相似性分析又重新获得了学术界和工业界的关注。在2018年和2019(已录用)的安全领域四大顶级会议上,每次都会有该方向最新成果的展示,如S&P‘2019上录用的《Asm2Vec: Boosting Static Representation Robustness for Binary Clone Search against Code Obfuscation and Compiler Optimization》,实现无先验知识的条件下的最优汇编代码级别克隆检测,针对漏洞库的漏洞代码检测可实现0误报、100%召回。而2018年北京HITB会议上,Google Project Zero成员、二进制比对工具BinDiff原始作者Thomas Dullien,探讨了他借用改造Google自家SimHash算法思想,用于针对二进制代码控制流图做相似性检测的尝试和阶段结果;这种引入规模数据处理的思路,也可期望能够在目前其他技术方案大多精细化而低效的情况下,为高效、快速、大规模甚至全量代码克隆检测勾出未来方案。 ·代码比对方案对编辑、优化、变形、混淆的对抗。近年所有技术方案都以对代码“变种”的检测有效性作为关键衡量标准,并一定程度上予以保证。上文CCS‘18论文工作,针对典型源代码混淆(如Tigress)处理后的代码,大规模数据集上可有93.42%的准确识别率;S&P‘19论文针对跨编译器和编译选项、业界常用的OLLVM编译时混淆方案进行试验,在全部可用的混淆方案保护之下的代码仍然可以完成81%以上的克隆检测。值得注意的是以上方案都并非针对特定混淆方案单独优化的,方法具有通用价值;而除此以外还有很多针对性的的反混淆研究成果可用;因此,可以认为在采用常规商用代码混淆方案下,即便存在隐藏内部业务逻辑不被逆向的能力,但仍然可以被有效定位代码复用和开发者自然人。 代码溯源技术面前的“挑战” 作为软件供应链安全的独立分析方,健壮的代码比对技术是决定性的基石;而当脑洞大开,考虑到行业的发展,也许以下两种假设的情景,将把每一个“正当”的产品、开发者置于尴尬的境地。 代码仿制 在本章节引述的“驱魔家族”代码疑云案例中,黑产方面通过某种方式获得了正常代码中,功能逻辑可以被自身复用的片段,并以某种方法将其在保持原样的情况下拼接形成了恶意程序。即便在此例中并非如此,但这却暴露了隐忧:将来是不是有这种可能,我的正常代码被泄漏或逆向后出现在恶意软件中,被溯源后扣上黑锅? 这种担忧可能以多种渠道和形式成为现实。 从上游看,内部源码被人为泄漏是最简单的形式(实际上,考虑到代码的完整生命周期似乎并没有作为企业核心数据资产得到保护,目前实质上有没有这样的代码在野泄漏还是个未知数),而通过程序逆向还原代码逻辑也在一定程度上可获取原始代码关键特征。 从下游看,则可能有多种方式将恶意代码伪造得像正常代码并实现“碰瓷”。最简单地,可以大量复用关键代码特征(如字符串,自定义数据结构,关键分支条件,数据记录和交换私有格式等)。考虑到在进行溯源时,分析者实际上不需要100%的匹配度才会怀疑,因此仅仅是仿造原始程序对于第三方公开库代码的特殊定制改动,也足以将公众的疑点转移。而近年来类似自动补丁代码搜索生成的方案也可能被用来在一份最终代码中包含有二方甚至多方原始代码的特征和片段。 基于开发者溯源的定点渗透 既然在未来可能存在准确将代码与自然人对应的技术,那么这种技术也完全可能被黑色产业利用。可能的忧患包括强针对性的社会工程,结合特定开发者历史代码缺陷的漏洞挖掘利用,联动第三方泄漏人员信息的深层渗透,等等。这方面暂不做联想展开。 〇. 没有总结 作为一场旨在定义“软件供应链安全”威胁的宣言,阿里安全“功守道”大赛将在后续给出详细的分解和总结,其意义价值也许会在一段时间之后才能被挖掘。 但是威胁的现状不容乐观,威胁的发展不会静待;这一篇随笔仅仅挑选六个侧面做摘录分析,可即将到来的趋势一定只会进入更加发散的境地,因此这里,没有总结。 本篇文章为转载内容。原文链接:https://blog.csdn.net/systemino/article/details/90114743。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-05 13:33:43
300
转载
建站模板下载
...管理、用户管理等功能模块,适用于各类网站后台管理场景。该模板采用清晰的布局与直观的操作界面,方便用户进行内容编辑、系统配置等操作,实现对网站的全方位、便捷化管理。 点我下载 文件大小:5.06 MB 您将下载一个资源包,该资源包内部文件的目录结构如下: 本网站提供模板下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2023-01-08 15:58:46
52
本站
建站模板下载
...务介绍。该模板简约且模块化,可灵活展示多元业务模块,实现动态响应。它以其高效解决业务展示需求的特点,助力企业构建专业且全面的在线品牌形象,便捷下载即可快速搭建专属的企业级网站。 点我下载 文件大小:2.16 MB 您将下载一个资源包,该资源包内部文件的目录结构如下: 本网站提供模板下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2023-07-17 10:22:50
91
本站
建站模板下载
...统,具备高度定制化和模块化的特点。该模板基于CMS系统开发,提供丰富的商务网站素材,便于快速构建和管理财经网模板,实现高效便捷的后台运营管理体验。 点我下载 文件大小:192.00 KB 您将下载一个资源包,该资源包内部文件的目录结构如下: 本网站提供模板下载功能,旨在帮助广大用户在工作学习中提升效率、节约时间。 本网站的下载内容来自于互联网。如您发现任何侵犯您权益的内容,请立即告知我们,我们将迅速响应并删除相关内容。 免责声明:站内所有资源仅供个人学习研究及参考之用,严禁将这些资源应用于商业场景。 若擅自商用导致的一切后果,由使用者承担责任。
2023-01-16 15:11:11
280
本站
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
head -n 10 file.txt
- 显示文件开头的10行内容。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"