Api Key Exposure in Spring Boot with Api Keys
Api Key Exposure in Spring Boot with Api Keys — how this specific combination creates or exposes the vulnerability
Storing and transmitting API keys in a Spring Boot application can inadvertently expose secrets through multiple avenues, often due to configuration practices, logging, or insufficient access controls. Unlike passwords, API keys are frequently embedded in properties files, environment variables, or code, and if mishandled they become high-value targets for attackers.
One common pattern is defining the key in application.properties or application.yml using a simple key-value pair:
external.api.key=sk_live_abc123xyz789
If the configuration is packaged into a JAR and the file is included in a public repository, the key is exposed. Even when using Spring Profiles, keys may be promoted across environments without rotation, increasing the blast radius.
During runtime, keys can be exposed through HTTP responses if controllers inadvertently include them in serialization logic. For example, a controller that returns a wrapper object containing the key without filtering sensitive fields can leak the value in JSON output:
@GetMapping("/status")
public Map<String, String> status() {
return Map.of("apiKey", apiKey); // Risk: key returned in response
}
Keys may also leak via server logs if the application logs request or configuration details at DEBUG or TRACE levels. A common anti-pattern is logging headers or parameters without redaction:
log.debug("Incoming request headers: {}", headers); // Risk: keys in logs
Another vector is insecure inter-service communication. When Spring Boot services call external APIs, keys may be passed in query parameters or non-encrypted headers, exposing them in network traces or proxy logs. Using RestTemplate or WebClient without enforcing HTTPS can lead to plaintext transmission.
Environment variables injected via deployment manifests (e.g., Kubernetes ConfigMaps or Docker environment) can be accidentally exposed through debug endpoints or shell access. If the container is compromised, keys stored in memory or accessible via /proc may be extracted.
OAuth2 client configurations can also lead to exposure if secrets are used as authorization headers without additional protection. A misconfigured WebSecurityConfigurerAdapter might permit unauthenticated access to endpoints that return key-bearing resources.
Finally, build and deployment pipelines may retain keys in logs or artifact metadata. If a CI/CD system caches environment variables improperly, keys can persist across jobs or be exposed in build history.
Api Keys-Specific Remediation in Spring Boot — concrete code fixes
Remediation focuses on minimizing exposure, enforcing encryption, and ensuring keys are never unnecessarily serialized or logged. Below are concrete, secure patterns for handling API keys in Spring Boot.
1. Store keys securely using environment variables and Spring Cloud Config
Instead of hardcoding keys in properties files, inject them via environment variables and reference them in configuration:
external.api.key=${EXTERNAL_API_KEY}
Set the variable securely in your runtime environment:
export EXTERNAL_API_KEY=sk_live_abc123xyz789
2. Use Java Keystore for sensitive values
For stronger protection, load keys from a Java Keystore:
@Configuration
public class ApiKeyConfig {
@Value("${api.key.alias}")
private String keyAlias;
@Bean
public String apiKey(KeyStore keyStore) throws Exception {
return (String) keyStore.getKey(keyAlias, "keystore-password".toCharArray());
}
}
3. Prevent logging of sensitive data
Override toString() methods and use field exclusion in logging. With SLF4J, avoid logging raw headers:
log.debug("Request processed successfully"); // Safe: no key logged
4. Filter sensitive fields in serialization
Use Jackson annotations to exclude keys from JSON responses:
public class ApiResponse {
private String data;
@JsonIgnore
private String apiKey;
// constructor, getters
}
5. Enforce HTTPS for all external calls
When calling external services, use WebClient with forced HTTPS:
WebClient.create()
.get()
.uri(URI.create("https://api.external.com/endpoint"))
.headers(h -> h.setBasicAuth("user", System.getenv("API_KEY")))
.retrieve()
.bodyToMono(String.class)
.block();
6. Rotate keys regularly and scope permissions
Use short-lived keys with minimal scopes. Rotate keys via your API provider’s dashboard and update them in your secure store without redeploying code.
7. Secure CI/CD and deployment artifacts
Ensure pipeline logs mask sensitive values and that build artifacts do not contain configuration files with keys. Use secret management integrations provided by your CI platform.