警惕 Spring Boot Actuator 引發(fā)的安全問(wèn)題

前言
一年一度的 HW 行動(dòng)開始了,最近也是被各種安全漏洞搞的特別鬧心,一周能收到幾十封安全團(tuán)隊(duì)掃描出來(lái)的漏洞郵件,這其中有一類漏洞很容易被人忽視,但影響面卻極廣,危害也極大,我說(shuō)出它的名字你應(yīng)該也不會(huì)感到陌生,正是 Spring Boot Actuator 。
寫這篇文章前,我跟我的朋友做了一個(gè)小調(diào)查,問(wèn)他們對(duì) Spring Boot Actuator 的了解,結(jié)果驚人的一致,大家都知道 Spring Boot 提供了 spring-boot-starter-actuator 的自動(dòng)配置,但卻很少有人真正用到它相關(guān)的特性。在繼續(xù)往下面看這篇文章時(shí),大家也可以先思考下幾個(gè)問(wèn)題:
檢查下你開發(fā)的項(xiàng)目中有引入 spring-boot-starter-actuator依賴嗎?你在項(xiàng)目中有真正用到 spring-boot-starter-actuator的有關(guān)功能嗎?你知道 spring-boot-starter-actuator的安全風(fēng)險(xiǎn)和正確配置方式嗎?
Spring Boot Actuator 是什么?
好久沒翻過(guò) spring 的文檔了,為了解釋這個(gè)還算陌生的名詞 Actutor [??ktju?e?t?r],我特地去翻了下它的文檔,找到了官方的定義
Definition of Actuator
An actuator is a manufacturing term that refers to a mechanical device for moving or controlling something. Actuators can generate a large amount of motion from a small change.
好家伙,看了等于白看,以我 CET-6 的水平,理解這段話著實(shí)有點(diǎn)難度,希望能有英語(yǔ)比較好的同學(xué)幫我翻譯下。只能按照我個(gè)人對(duì) Spring Boot Actuator 功能的理解來(lái)意譯下了:我們可以借助于 Spring Boot Actuator 來(lái)對(duì) Spring Boot 應(yīng)用的健康狀態(tài)、環(huán)境配置、Metrics、Trace、Spring 上下文等信息進(jìn)行查看,除了一系列查看功能之外,它還實(shí)現(xiàn)了 Spring Boot 應(yīng)用的上下線和內(nèi)存 dump 功能。
Quick Start
第一步 引入依賴
tips:spring-boot-starter-actuator 在不同版本 Spring Boot 中有一定的配置差異,本文采用的是目前最新的 2.4.4 版本
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.4.4</version>
</dependency>
第二步 了解 endpoint
endpoint 是我們使用 Spring Boot Actuator 最需要關(guān)心的對(duì)象,列舉一些你可能感興趣的 endpoint
| ID | Description |
|---|---|
| beans | 查看 Spring 容器中的所有對(duì)象 |
| configprops | 查看被 @ConfigurationProperties 修飾的對(duì)象列表 |
| env | 查看 application.yaml 配置的環(huán)境配置信息 |
| health | 健康檢查端點(diǎn) |
| info | 應(yīng)用信息 |
| metrics | 統(tǒng)計(jì)信息 |
| mappings | 服務(wù)契約 @RequestMapping 相關(guān)的端點(diǎn) |
| shutdown | 優(yōu)雅下線 |
例如 health,只需要訪問(wèn)如下 endpoint 即可獲取應(yīng)用的狀態(tài)
curl "localhost:8080/actuator/health"
第三步 了解 endpoint 的 enable 和 exposure 狀態(tài)
Spring Boot Actuator 針對(duì)于所有 endpoint 都提供了兩種狀態(tài)的配置
enabled 啟用狀態(tài)。默認(rèn)情況下除了 shutdown之外,其他 endpoint 都是啟用狀態(tài)。這也很好理解,其他 endpoint 基本都是查看行為,shutdown 卻會(huì)影響應(yīng)用的運(yùn)行狀態(tài)。exposure 暴露狀態(tài)。endpoint 的 enabled 設(shè)置為 true 后,還需要暴露一次,才能夠被訪問(wèn),默認(rèn)情況下只有 health 和 info 是暴露的。
enabled 不啟用時(shí),相關(guān)的 endpoint 的代碼完全不會(huì)被 Spring 上下文加載,所以 enabled 為 false 時(shí),exposure 配置了也無(wú)濟(jì)于事。
幾個(gè)典型的配置示例如下
啟用并暴露所有 endpoint
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
shutdown:
enabled: true
只啟用并暴露指定 endpoint
management:
endpoints:
enabled-by-default: false
endpoint:
info:
enabled: true
endpoints:
web:
exposure:
include: "info"
禁用所有 endpoint
management:
endpoints:
enabled-by-default: false
或者,去除掉 spring-boot-starter-actuator 依賴!
了解 Spring Boot Actuator 的安全風(fēng)險(xiǎn)
從上文的介紹可知,有一些 Spring Boot Actuator 提供的 endpoint 是會(huì)將應(yīng)用重要的信息暴露出去的,以 env 為例來(lái)感受下一個(gè)典型的 application.yaml 的示例。
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://testDbHost:3306/kirito
username: kirito
password: 123456
kirito:
ak: kirito@xxx_ak
sk: kirito@xxx_sk
management:
endpoints:
web:
exposure:
include: "*"
上面的配置再經(jīng)典不過(guò),我們看看訪問(wèn) localhost:8080/actuator/env 之后的返回值
{
"activeProfiles": [],
"propertySources": [
{
"name": "server.ports",
"properties": {
"local.server.port": {
"value": 8080
}
}
},
{
"name": "Config resource 'class path resource [application.yaml]' via location 'optional:classpath:/'",
"properties": {
"server.port": {
"value": 8080,
"origin": "class path resource [application.yaml] - 2:9"
},
"spring.datasource.url": {
"value": "jdbc:mysql://testDbHost:3306/kirito",
"origin": "class path resource [application.yaml] - 5:44"
},
"spring.datasource.username": {
"value": "kirito",
"origin": "class path resource [application.yaml] - 6:15"
},
"spring.datasource.password": {
"value": "******",
"origin": "class path resource [application.yaml] - 7:15"
},
"kirito.ak": {
"value": "kirito@xxx_ak",
"origin": "class path resource [application.yaml] - 10:7"
},
"kirito.sk": {
"value": "kirito@xxx_sk",
"origin": "class path resource [application.yaml] - 11:7"
},
"management.endpoints.web.exposure.include": {
"value": "*",
"origin": "class path resource [application.yaml] - 17:18"
}
}
}
]
}
可以發(fā)現(xiàn),對(duì)于內(nèi)置的敏感配置信息 spring.datasource.password,Spring Boot Actuator 是進(jìn)行了脫敏的,但是對(duì)于自定義的一些敏感配置,如 kirito.ak 和 kirito.sk 卻被暴露出來(lái)了。
可能有的讀者會(huì)立馬提出質(zhì)疑:我們的機(jī)器都部署內(nèi)網(wǎng),并且一般都是通過(guò)反向代理對(duì)外暴露的服務(wù),這類 endpoint 是不會(huì)被外部用戶訪問(wèn)到的。那我只能說(shuō)太天真了,例如以下情況都是導(dǎo)致安全漏洞的真實(shí) case:
反向代理誤配置了根節(jié)點(diǎn),將 actuator 的 endpoint 和 web 服務(wù)一起暴露了出去 線上配置沒問(wèn)題,測(cè)試環(huán)境部署時(shí)開通了公網(wǎng) SLB,導(dǎo)致 actuator 的 endpoint 暴露了出去 同一環(huán)境中某臺(tái)機(jī)器被攻陷,導(dǎo)致應(yīng)用配置信息泄露
安全建議
針對(duì) Spring Boot Actuator 提供的 endpoint,采取以下幾種措施,可以盡可能降低被安全攻擊的風(fēng)險(xiǎn)
最小粒度暴露 endpoint。只開啟并暴露真正用到的 endpoint,而不是配置: management.endpoints.web.exposure.include=*。為 endpoint 配置獨(dú)立的訪問(wèn)端口,從而和 web 服務(wù)的端口分離開,避免暴露 web 服務(wù)時(shí),誤將 actuator 的 endpoint 也暴露出去。例: management.port=8099。引入 spring-boot-starter-security依賴,為 actuator 的 endpoint 配置訪問(wèn)控制。慎重評(píng)估是否需要引入 spring-boot-stater-actuator。以我個(gè)人的經(jīng)驗(yàn),我至今還沒有遇到什么需求是一定需要引入spring-boot-stater-actuator才能解決,如果你并不了解上文所述的安全風(fēng)險(xiǎn),我建議你先去除掉該依賴。
今天,你使用 Spring Boot Actuator 了嗎?
- END -
「技術(shù)分享」某種程度上,是讓作者和讀者,不那么孤獨(dú)的東西。歡迎關(guān)注我的微信公眾號(hào):「Kirito的技術(shù)分享」
