Recently, we have been particularly disturbed by various security vulnerabilities, and we have received dozens of vulnerability emails scanned by the security team in a week, which have a class of vulnerabilities that are easy to ignore, but have an extremely wide impact and are extremely harmful, and you should not be unfamiliar with my name, which is Spring Boot Actuator.

Before writing this article, I did a little survey with my friends asking them about their knowledge of the Spring Boot Actuator and the results were surprisingly consistent, everyone knows that Spring Boot provides automatic configuration of the spring-boot-starter-actuator, but very few people but few people actually use its related features. As you continue to read the article below, you can also think about the following questions.

  • Check if you have introduced the spring-boot-starter-actuator dependency in your development project?
  • Do you actually use the spring-boot-starter-actuator related functionality in your projects?
  • Do you know the security risks of spring-boot-starter-actuator and the correct way to configure it?

What is the Spring Boot Actuator

Official Definition

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.

Quick Start

Step 1 Introduce dependencies

tips: spring-boot-starter-actuator has some configuration differences in different versions of Spring Boot, this article uses the 2.4.4 version of the project

1
2
3
4
5
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.4.4</version>
</dependency

Step 2 Understanding endpoint

The endpoint is the most important object we need to care about when using the Spring Boot Actuator, to list some of the endpoints you might be interested in

ID Description
beans View all objects in the Spring container
configprops View the list of objects annotated by @ConfigurationProperties
env View the environment configuration information for the application.yaml configuration
health Health Check Endpoints
info Application Information
metrics Statistical Information
mappings Service contract @RequestMapping related endpoints
shutdown Elegant shutdown

For example, for health, you only need to access the following endpoint to get the status of the application

1
curl "localhost:8080/actuator/health"

Step 3 Understanding the enable and exposure states of endpoint

The spring Boot Actuator provides two states of configuration for all endpoint

  • enabled Enabled status. By default all endpoints are enabled except shutdown. This is understandable, as the other endpoints are basically viewing behavior, while shutdown affects the running state of the application.

  • exposure exposes the state. After endpoint’s enabled is set to true, it needs to be exposed once more before it can be accessed; by default only health and info are exposed.

When enabled is not enabled, the associated endpoint code is not loaded by the Spring context at all, so it doesn’t matter if exposure is configured when enabled is false.

A few typical configuration examples are as follows

Enable and expose all endpoints

1
2
3
4
5
6
7
8
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    shutdown:
      enabled: true

Only enable and expose the specified endpoint

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
management:
  endpoints:
    enabled-by-default: false
  endpoint:
    info:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "info"

Disable all endpoint

1
2
3
management:
  endpoints:
    enabled-by-default: false

Or, remove the spring-boot-starter-actuator dependency!

Understanding the Security Risks of the Spring Boot Actuator

As you can see from the introduction above, there are endpoints provided by the Spring Boot Actuator that expose important information about the application, so take env as an example to get a feel for a typical application.yaml example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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: "*"

The above configuration couldn’t be more classic. Let’s look at the return value after accessing localhost:8080/actuator/env

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
  "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"
        }
      }
    }
  ]
}

You can see that the Spring Boot Actuator is desensitized for the built-in sensitive configuration information spring.datasource.password, but some custom sensitive configurations like kirito.ak and kirito.sk are exposed.

Some readers may immediately question: our machines are deployed intranet, and are generally exposed to the public through a reverse proxy service, this kind of endpoint is not accessible to external users. Then I can only say that it is too naive, for example, the following situations are real examples that lead to security vulnerabilities

  • The reverse proxy misconfigured the root node, exposing the endpoint of the actuator along with the web service
  • The online configuration is fine, but the public network SLB was opened when the test environment was deployed, resulting in the endpoint of actuator being exposed
  • A machine in the same environment is hacked, resulting in the leakage of application configuration information

Security Advice

For the endpoint provided by the Spring Boot Actuator, there are several measures that can be taken to minimize the risk of security attacks

  • Expose endpoint with minimal granularity. Only enable and expose the endpoint that is actually used, instead of configuring: management.endpoints.web.exposure.include=*.
  • Configure a separate access port for endpoint so that it is separate from the port of the web service to avoid exposing the endpoint of the actuator by mistake when exposing the web service. Example: management.port=8099.
  • Introduce the spring-boot-starter-security dependency to configure access control for the endpoint of the actuator.
  • Evaluate carefully whether you need to bring in the spring-boot-stater-actuator. In my personal experience, I have not encountered any requirement that necessarily requires the introduction of spring-boot-stater-actuator to solve, so if you are not aware of the security risks described above, I suggest you remove the dependency first.

Reference https://www.cnkirito.moe/spring-boot-actuator-notes/