diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringBoot.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringBoot.qll new file mode 100644 index 000000000000..d77e4549e4e7 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringBoot.qll @@ -0,0 +1,24 @@ +/** + * Provides classes for working with Spring classes and interfaces from + * `org.springframework.boot.*`. + */ + +import java + +/** + * The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`. + */ +class SpringEndpointRequest extends Class { + SpringEndpointRequest() { + this.hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", + "EndpointRequest") + } +} + +/** A call to `EndpointRequest.toAnyEndpoint` method. */ +class SpringToAnyEndpointCall extends MethodCall { + SpringToAnyEndpointCall() { + this.getMethod().hasName("toAnyEndpoint") and + this.getMethod().getDeclaringType() instanceof SpringEndpointRequest + } +} diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringSecurity.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringSecurity.qll new file mode 100644 index 000000000000..835b679d50a6 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringSecurity.qll @@ -0,0 +1,124 @@ +/** + * Provides classes for working with Spring classes and interfaces from + * `org.springframework.security.*`. + */ + +import java + +/** The class `org.springframework.security.config.annotation.web.builders.HttpSecurity`. */ +class SpringHttpSecurity extends Class { + SpringHttpSecurity() { + this.hasQualifiedName("org.springframework.security.config.annotation.web.builders", + "HttpSecurity") + } +} + +/** + * The class + * `org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer$AuthorizedUrl` + * or the class + * `org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer$AuthorizedUrl`. + */ +class SpringAuthorizedUrl extends Class { + SpringAuthorizedUrl() { + this.hasQualifiedName("org.springframework.security.config.annotation.web.configurers", + [ + "ExpressionUrlAuthorizationConfigurer$AuthorizedUrl<>", + "AuthorizeHttpRequestsConfigurer$AuthorizedUrl<>" + ]) + } +} + +/** + * The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. + */ +class SpringAbstractRequestMatcherRegistry extends Class { + SpringAbstractRequestMatcherRegistry() { + this.hasQualifiedName("org.springframework.security.config.annotation.web", + "AbstractRequestMatcherRegistry>") + } +} + +/** + * A call to the `HttpSecurity.authorizeRequests` method. + * + * Note: this method is deprecated and scheduled for removal + * in Spring Security 7.0. + */ +class SpringAuthorizeRequestsCall extends MethodCall { + SpringAuthorizeRequestsCall() { + this.getMethod().hasName("authorizeRequests") and + this.getMethod().getDeclaringType() instanceof SpringHttpSecurity + } +} + +/** + * A call to the `HttpSecurity.authorizeHttpRequests` method. + * + * Note: the no-argument version of this method is deprecated + * and scheduled for removal in Spring Security 7.0. + */ +class SpringAuthorizeHttpRequestsCall extends MethodCall { + SpringAuthorizeHttpRequestsCall() { + this.getMethod().hasName("authorizeHttpRequests") and + this.getMethod().getDeclaringType() instanceof SpringHttpSecurity + } +} + +/** + * A call to the `HttpSecurity.requestMatcher` method. + * + * Note: this method was removed in Spring Security 6.0. + * It was replaced by `securityMatcher`. + */ +class SpringRequestMatcherCall extends MethodCall { + SpringRequestMatcherCall() { + this.getMethod().hasName("requestMatcher") and + this.getMethod().getDeclaringType() instanceof SpringHttpSecurity + } +} + +/** + * A call to the `HttpSecurity.requestMatchers` method. + * + * Note: this method was removed in Spring Security 6.0. + * It was replaced by `securityMatchers`. + */ +class SpringRequestMatchersCall extends MethodCall { + SpringRequestMatchersCall() { + this.getMethod().hasName("requestMatchers") and + this.getMethod().getDeclaringType() instanceof SpringHttpSecurity + } +} + +/** A call to the `HttpSecurity.securityMatcher` method. */ +class SpringSecurityMatcherCall extends MethodCall { + SpringSecurityMatcherCall() { + this.getMethod().hasName("securityMatcher") and + this.getMethod().getDeclaringType() instanceof SpringHttpSecurity + } +} + +/** A call to the `HttpSecurity.securityMatchers` method. */ +class SpringSecurityMatchersCall extends MethodCall { + SpringSecurityMatchersCall() { + this.getMethod().hasName("securityMatchers") and + this.getMethod().getDeclaringType() instanceof SpringHttpSecurity + } +} + +/** A call to the `AuthorizedUrl.permitAll` method. */ +class SpringPermitAllCall extends MethodCall { + SpringPermitAllCall() { + this.getMethod().hasName("permitAll") and + this.getMethod().getDeclaringType() instanceof SpringAuthorizedUrl + } +} + +/** A call to the `AbstractRequestMatcherRegistry.anyRequest` method. */ +class SpringAnyRequestCall extends MethodCall { + SpringAnyRequestCall() { + this.getMethod().hasName("anyRequest") and + this.getMethod().getDeclaringType() instanceof SpringAbstractRequestMatcherRegistry + } +} diff --git a/java/ql/lib/semmle/code/java/security/SpringBootActuatorsQuery.qll b/java/ql/lib/semmle/code/java/security/SpringBootActuatorsQuery.qll new file mode 100644 index 000000000000..68c20adabdd1 --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/SpringBootActuatorsQuery.qll @@ -0,0 +1,110 @@ +/** Provides classes and predicates to reason about exposed actuators in Spring Boot. */ + +import java +private import semmle.code.java.frameworks.spring.SpringSecurity +private import semmle.code.java.frameworks.spring.SpringBoot + +/** + * A call to an `HttpSecurity` matcher method with argument + * `EndpointRequest.toAnyEndpoint()`. + */ +private class HttpSecurityMatcherCall extends MethodCall { + HttpSecurityMatcherCall() { + ( + this instanceof SpringRequestMatcherCall or + this instanceof SpringSecurityMatcherCall + ) and + this.getArgument(0) instanceof SpringToAnyEndpointCall + } +} + +/** + * A call to an `HttpSecurity` matchers method with lambda + * argument `EndpointRequest.toAnyEndpoint()`. + */ +private class HttpSecurityMatchersCall extends MethodCall { + HttpSecurityMatchersCall() { + ( + this instanceof SpringRequestMatchersCall or + this instanceof SpringSecurityMatchersCall + ) and + this.getArgument(0).(LambdaExpr).getExprBody() instanceof SpringToAnyEndpointCall + } +} + +/** + * A call to an `AbstractRequestMatcherRegistry.requestMatchers` method with + * argument `EndpointRequest.toAnyEndpoint()`. + */ +private class RegistryRequestMatchersCall extends MethodCall { + RegistryRequestMatchersCall() { + this.getMethod().hasName("requestMatchers") and + this.getMethod().getDeclaringType() instanceof SpringAbstractRequestMatcherRegistry and + this.getAnArgument() instanceof SpringToAnyEndpointCall + } +} + +/** A call to an `HttpSecurity` method that authorizes requests. */ +private class AuthorizeCall extends MethodCall { + AuthorizeCall() { + this instanceof SpringAuthorizeRequestsCall or + this instanceof SpringAuthorizeHttpRequestsCall + } +} + +/** Holds if `permitAllCall` is called on request(s) mapped to actuator endpoint(s). */ +predicate permitsSpringBootActuators(SpringPermitAllCall permitAllCall) { + exists(AuthorizeCall authorizeCall | + // .requestMatcher(EndpointRequest).authorizeRequests([...]).[...] + authorizeCall.getQualifier() instanceof HttpSecurityMatcherCall + or + // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...] + authorizeCall.getQualifier() instanceof HttpSecurityMatchersCall + | + // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or + // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) + authorizeCall.getArgument(0).(LambdaExpr).getExprBody() = permitAllCall and + ( + permitAllCall.getQualifier() instanceof SpringAnyRequestCall or + permitAllCall.getQualifier() instanceof RegistryRequestMatchersCall + ) + or + // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or + // [...].authorizeRequests().anyRequest().permitAll() + authorizeCall.getNumArgument() = 0 and + exists(RegistryRequestMatchersCall registryRequestMatchersCall | + registryRequestMatchersCall.getQualifier() = authorizeCall and + permitAllCall.getQualifier() = registryRequestMatchersCall + ) + or + exists(SpringAnyRequestCall anyRequestCall | + anyRequestCall.getQualifier() = authorizeCall and + permitAllCall.getQualifier() = anyRequestCall + ) + ) + or + exists(AuthorizeCall authorizeCall | + // http.authorizeRequests([...]).[...] + authorizeCall.getQualifier() instanceof VarAccess + | + // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) + authorizeCall.getArgument(0).(LambdaExpr).getExprBody() = permitAllCall and + permitAllCall.getQualifier() instanceof RegistryRequestMatchersCall + or + // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or + authorizeCall.getNumArgument() = 0 and + exists(RegistryRequestMatchersCall registryRequestMatchersCall | + registryRequestMatchersCall.getQualifier() = authorizeCall and + permitAllCall.getQualifier() = registryRequestMatchersCall + ) + or + exists(Variable v, HttpSecurityMatcherCall matcherCall | + // http.securityMatcher(EndpointRequest.toAnyEndpoint()); + // http.authorizeRequests([...].permitAll()) + v.getAnAccess() = authorizeCall.getQualifier() and + v.getAnAccess() = matcherCall.getQualifier() and + authorizeCall.getArgument(0).(LambdaExpr).getExprBody() = permitAllCall and + permitAllCall.getQualifier() instanceof SpringAnyRequestCall + ) + ) +} diff --git a/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.java b/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.java new file mode 100644 index 000000000000..5f61127db288 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.java @@ -0,0 +1,25 @@ +@Configuration(proxyBeanMethods = false) +public class CustomSecurityConfiguration { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed + http.securityMatcher(EndpointRequest.toAnyEndpoint()); + http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll()); + return http.build(); + } + +} + +@Configuration(proxyBeanMethods = false) +public class CustomSecurityConfiguration { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints + http.securityMatcher(EndpointRequest.toAnyEndpoint()); + http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN")); + return http.build(); + } + +} diff --git a/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.qhelp b/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.qhelp new file mode 100644 index 000000000000..97ced3576f66 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.qhelp @@ -0,0 +1,36 @@ + + + +

Spring Boot includes features called actuators that let you monitor and interact with your +web application. Exposing unprotected actuator endpoints can lead to information disclosure or +even to remote code execution.

+
+ + +

Since actuator endpoints may contain sensitive information, carefully consider when to expose them, +and secure them as you would any sensitive URL. Actuators are secured by default when using Spring +Security without a custom configuration. If you wish to define a custom security configuration, +consider only allowing users with certain roles to access these endpoints. +

+ +
+ + +

In the first example, the custom security configuration allows unauthenticated access to all +actuator endpoints. This may lead to sensitive information disclosure and should be avoided.

+ +

In the second example, only users with ENDPOINT_ADMIN role are allowed to access +the actuator endpoints.

+ + +
+ + +
  • +Spring Boot Reference Documentation: +Endpoints. +
  • +
    +
    diff --git a/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql b/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql new file mode 100644 index 000000000000..1e0944062a01 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql @@ -0,0 +1,20 @@ +/** + * @name Exposed Spring Boot actuators + * @description Exposing Spring Boot actuators may lead to information leak from the internal application, + * or even to remote code execution. + * @kind problem + * @problem.severity error + * @security-severity 6.5 + * @precision high + * @id java/spring-boot-exposed-actuators + * @tags security + * external/cwe/cwe-200 + */ + +import java +import semmle.code.java.frameworks.spring.SpringSecurity +import semmle.code.java.security.SpringBootActuatorsQuery + +from SpringPermitAllCall permitAllCall +where permitsSpringBootActuators(permitAllCall) +select permitAllCall, "Unauthenticated access to Spring Boot actuator is allowed." diff --git a/java/ql/src/change-notes/2025-02-24-spring-boot-actuators-promo.md b/java/ql/src/change-notes/2025-02-24-spring-boot-actuators-promo.md new file mode 100644 index 000000000000..8f407de95ac2 --- /dev/null +++ b/java/ql/src/change-notes/2025-02-24-spring-boot-actuators-promo.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* The query `java/spring-boot-exposed-actuators` has been promoted from experimental to the main query pack. Its results will now appear by default, and the query itself will be removed from the [CodeQL Community Packs](https://github.com/GitHubSecurityLab/CodeQL-Community-Packs). This query was originally submitted as an experimental query [by @ggolawski](https://github.com/github/codeql/pull/2901). diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java deleted file mode 100644 index 538620550efc..000000000000 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.java +++ /dev/null @@ -1,22 +0,0 @@ -@Configuration(proxyBeanMethods = false) -public class SpringBootActuators extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity http) throws Exception { - // BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) -> - requests.anyRequest().permitAll()); - } -} - -@Configuration(proxyBeanMethods = false) -public class ActuatorSecurity extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity http) throws Exception { - // GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) -> - requests.anyRequest().hasRole("ENDPOINT_ADMIN")); - http.httpBasic(); - } -} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp deleted file mode 100644 index 53ee653aaff3..000000000000 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qhelp +++ /dev/null @@ -1,39 +0,0 @@ - - - -

    Spring Boot includes a number of additional features called actuators that let you monitor -and interact with your web application. Exposing unprotected actuator endpoints via JXM or HTTP -can, however, lead to information disclosure or even to remote code execution vulnerability.

    -
    - - -

    Since actuator endpoints may contain sensitive information, careful consideration should be -given about when to expose them. You should take care to secure exposed HTTP endpoints in the same -way that you would any other sensitive URL. If Spring Security is present, endpoints are secured by -default using Spring Security’s content-negotiation strategy. If you wish to configure custom -security for HTTP endpoints, for example, only allow users with a certain role to access them, -Spring Boot provides some convenient RequestMatcher objects that can be used in -combination with Spring Security.

    -
    - - -

    In the first example, the custom security configuration allows unauthenticated access to all -actuator endpoints. This may lead to sensitive information disclosure and should be avoided.

    -

    In the second example, only users with ENDPOINT_ADMIN role are allowed to access -the actuator endpoints.

    - - -
    - - -
  • -Spring Boot documentation: -Actuators. -
  • -
  • -Exploiting Spring Boot Actuators -
  • -
    -
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql deleted file mode 100644 index 574336074254..000000000000 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Exposed Spring Boot actuators - * @description Exposing Spring Boot actuators may lead to internal application's information leak - * or even to remote code execution. - * @kind problem - * @problem.severity error - * @precision high - * @id java/spring-boot-exposed-actuators - * @tags security - * experimental - * external/cwe/cwe-16 - */ - -import java -deprecated import SpringBootActuators - -deprecated query predicate problems(PermitAllCall permitAllCall, string message) { - permitAllCall.permitsSpringBootActuators() and - message = "Unauthenticated access to Spring Boot actuator is allowed." -} diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll deleted file mode 100644 index 881f2a131720..000000000000 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll +++ /dev/null @@ -1,157 +0,0 @@ -deprecated module; - -import java - -/** The class `org.springframework.security.config.annotation.web.builders.HttpSecurity`. */ -class TypeHttpSecurity extends Class { - TypeHttpSecurity() { - this.hasQualifiedName("org.springframework.security.config.annotation.web.builders", - "HttpSecurity") - } -} - -/** - * The class - * `org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer`. - */ -class TypeAuthorizedUrl extends Class { - TypeAuthorizedUrl() { - this.hasQualifiedName("org.springframework.security.config.annotation.web.configurers", - "ExpressionUrlAuthorizationConfigurer$AuthorizedUrl<>") - } -} - -/** - * The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. - */ -class TypeAbstractRequestMatcherRegistry extends Class { - TypeAbstractRequestMatcherRegistry() { - this.hasQualifiedName("org.springframework.security.config.annotation.web", - "AbstractRequestMatcherRegistry>") - } -} - -/** - * The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`. - */ -class TypeEndpointRequest extends Class { - TypeEndpointRequest() { - this.hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", - "EndpointRequest") - } -} - -/** A call to `EndpointRequest.toAnyEndpoint` method. */ -class ToAnyEndpointCall extends MethodCall { - ToAnyEndpointCall() { - this.getMethod().hasName("toAnyEndpoint") and - this.getMethod().getDeclaringType() instanceof TypeEndpointRequest - } -} - -/** - * A call to `HttpSecurity.requestMatcher` method with argument `RequestMatcher.toAnyEndpoint()`. - */ -class RequestMatcherCall extends MethodCall { - RequestMatcherCall() { - this.getMethod().hasName("requestMatcher") and - this.getMethod().getDeclaringType() instanceof TypeHttpSecurity and - this.getArgument(0) instanceof ToAnyEndpointCall - } -} - -/** - * A call to `HttpSecurity.requestMatchers` method with lambda argument - * `RequestMatcher.toAnyEndpoint()`. - */ -class RequestMatchersCall extends MethodCall { - RequestMatchersCall() { - this.getMethod().hasName("requestMatchers") and - this.getMethod().getDeclaringType() instanceof TypeHttpSecurity and - this.getArgument(0).(LambdaExpr).getExprBody() instanceof ToAnyEndpointCall - } -} - -/** A call to `HttpSecurity.authorizeRequests` method. */ -class AuthorizeRequestsCall extends MethodCall { - AuthorizeRequestsCall() { - this.getMethod().hasName("authorizeRequests") and - this.getMethod().getDeclaringType() instanceof TypeHttpSecurity - } -} - -/** A call to `AuthorizedUrl.permitAll` method. */ -class PermitAllCall extends MethodCall { - PermitAllCall() { - this.getMethod().hasName("permitAll") and - this.getMethod().getDeclaringType() instanceof TypeAuthorizedUrl - } - - /** Holds if `permitAll` is called on request(s) mapped to actuator endpoint(s). */ - predicate permitsSpringBootActuators() { - exists(AuthorizeRequestsCall authorizeRequestsCall | - // .requestMatcher(EndpointRequest).authorizeRequests([...]).[...] - authorizeRequestsCall.getQualifier() instanceof RequestMatcherCall - or - // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...] - authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall - | - // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or - // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) - authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and - ( - this.getQualifier() instanceof AnyRequestCall or - this.getQualifier() instanceof RegistryRequestMatchersCall - ) - or - // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or - // [...].authorizeRequests().anyRequest().permitAll() - authorizeRequestsCall.getNumArgument() = 0 and - exists(RegistryRequestMatchersCall registryRequestMatchersCall | - registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and - this.getQualifier() = registryRequestMatchersCall - ) - or - exists(AnyRequestCall anyRequestCall | - anyRequestCall.getQualifier() = authorizeRequestsCall and - this.getQualifier() = anyRequestCall - ) - ) - or - exists(AuthorizeRequestsCall authorizeRequestsCall | - // http.authorizeRequests([...]).[...] - authorizeRequestsCall.getQualifier() instanceof VarAccess - | - // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) - authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and - this.getQualifier() instanceof RegistryRequestMatchersCall - or - // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or - authorizeRequestsCall.getNumArgument() = 0 and - exists(RegistryRequestMatchersCall registryRequestMatchersCall | - registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and - this.getQualifier() = registryRequestMatchersCall - ) - ) - } -} - -/** A call to `AbstractRequestMatcherRegistry.anyRequest` method. */ -class AnyRequestCall extends MethodCall { - AnyRequestCall() { - this.getMethod().hasName("anyRequest") and - this.getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry - } -} - -/** - * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument - * `RequestMatcher.toAnyEndpoint()`. - */ -class RegistryRequestMatchersCall extends MethodCall { - RegistryRequestMatchersCall() { - this.getMethod().hasName("requestMatchers") and - this.getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and - this.getAnArgument() instanceof ToAnyEndpointCall - } -} diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected deleted file mode 100644 index f2874e3694d1..000000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.expected +++ /dev/null @@ -1,7 +0,0 @@ -| SpringBootActuators.java:6:88:6:120 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | -| SpringBootActuators.java:10:5:10:137 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | -| SpringBootActuators.java:14:5:14:149 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | -| SpringBootActuators.java:18:5:18:101 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | -| SpringBootActuators.java:22:5:22:89 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | -| SpringBootActuators.java:26:40:26:108 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | -| SpringBootActuators.java:30:5:30:113 | permitAll(...) | Unauthenticated access to Spring Boot actuator is allowed. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java deleted file mode 100644 index da59919fbe6c..000000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java +++ /dev/null @@ -1,104 +0,0 @@ -import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; - -public class SpringBootActuators { - protected void configure(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest().permitAll()); - } - - protected void configure2(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); - } - - protected void configure3(HttpSecurity http) throws Exception { - http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); - } - - protected void configure4(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); - } - - protected void configure5(HttpSecurity http) throws Exception { - http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); - } - - protected void configure6(HttpSecurity http) throws Exception { - http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()); - } - - protected void configure7(HttpSecurity http) throws Exception { - http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); - } - - protected void configureOk1(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()); - } - - protected void configureOk2(HttpSecurity http) throws Exception { - http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint()); - } - - protected void configureOk3(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().permitAll(); - } - - protected void configureOk4(HttpSecurity http) throws Exception { - http.authorizeRequests(authz -> authz.anyRequest().permitAll()); - } - - protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll()); - } - - protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); - } - - protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception { - http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); - } - - protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); - } - - protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception { - http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); - } - - protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception { - http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll()); - } - - protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception { - http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); - } - - protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest()); - } - - protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); - } - - protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception { - http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); - } - - protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception { - http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); - } - - protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception { - http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); - } - - protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception { - http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint())); - } - - protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception { - http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); - } -} diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.qlref b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.qlref deleted file mode 100644 index ec49ecd718c2..000000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-016/SpringBootActuators.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.java new file mode 100644 index 000000000000..4b5d7614eef6 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.java @@ -0,0 +1,281 @@ +import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; + +public class SpringBootActuatorsTest { + // Spring security version 5.2.3 used `authorizeRequests` and `requestMatcher(s)` + protected void configure(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator + } + + protected void configure2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()); // $ hasExposedSpringBootActuator + } + + protected void configure7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configureOk1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOk2(HttpSecurity http) throws Exception { + http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOk3(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOk4(HttpSecurity http) throws Exception { + http.authorizeRequests(authz -> authz.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); + } + + protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll()); + } + + protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest()); + } + + protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } + + protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint())); + } + + protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } + + // Spring security version 5.5.0 introduced `authorizeHttpRequests` + protected void configure_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator + } + + protected void configure2_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure3_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure4_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure5_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure6_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()); // $ hasExposedSpringBootActuator + } + + protected void configure7_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configureOk3_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests().anyRequest().permitAll(); + } + + protected void configureOk4_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints1_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints2_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); + } + + protected void configureOkSafeEndpoints3_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints4_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll(); + } + + protected void configureOkSafeEndpoints5_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints6_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll()); + } + + protected void configureOkSafeEndpoints7_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll(); + } + + protected void configureOkNoPermitAll1_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest()); + } + + protected void configureOkNoPermitAll2_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll3_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll4_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest(); + } + + protected void configureOkNoPermitAll5_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll6_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint())); + } + + protected void configureOkNoPermitAll7_authorizeHttpRequests(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest(); + } + + // Spring security version 5.8.0 introduced `securityMatcher(s)` + protected void configure_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator + } + + protected void configure2_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure3_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure4_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configure7_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest().permitAll(); // $ hasExposedSpringBootActuator + } + + protected void configureOk1_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOk2_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatchers().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkSafeEndpoints1_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints2_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.to("health")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); + } + + protected void configureOkSafeEndpoints3_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints4_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll(); + } + + protected void configureOkSafeEndpoints7_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeHttpRequests().anyRequest().permitAll(); + } + + protected void configureOkNoPermitAll1_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests(requests -> requests.anyRequest()); + } + + protected void configureOkNoPermitAll2_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll3_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll4_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest(); + } + + protected void configureOkNoPermitAll7_securityMatchers(HttpSecurity http) throws Exception { + http.securityMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeHttpRequests().anyRequest(); + } + + // QHelp Bad example + public void securityFilterChain1(HttpSecurity http) throws Exception { + // BAD: Unauthenticated access to Spring Boot actuator endpoints is allowed + http.securityMatcher(EndpointRequest.toAnyEndpoint()); + http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll()); // $ hasExposedSpringBootActuator + } + + // QHelp Good example + public void securityFilterChain2(HttpSecurity http) throws Exception { + // GOOD: only users with ENDPOINT_ADMIN role are allowed to access the actuator endpoints + http.securityMatcher(EndpointRequest.toAnyEndpoint()); + http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN")); + } +} diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.ql b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.ql new file mode 100644 index 000000000000..214886fce511 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/SpringBootActuatorsTest.ql @@ -0,0 +1,19 @@ +import java +import semmle.code.java.frameworks.spring.SpringSecurity +import semmle.code.java.security.SpringBootActuatorsQuery +import utils.test.InlineExpectationsTest + +module SpringBootActuatorsTest implements TestSig { + string getARelevantTag() { result = "hasExposedSpringBootActuator" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasExposedSpringBootActuator" and + exists(SpringPermitAllCall permitAllCall | permitsSpringBootActuators(permitAllCall) | + permitAllCall.getLocation() = location and + element = permitAllCall.toString() and + value = "" + ) + } +} + +import MakeTest diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/options b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/options new file mode 100644 index 000000000000..161a6ddf23d7 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SpringBootActuators/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../../stubs/springframework-5.3.8 diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 3dbe33cdeb9c..f900fc74d2fd 100644 --- a/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -9,6 +9,7 @@ import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; public final class HttpSecurity extends AbstractConfiguredSecurityBuilder @@ -18,6 +19,14 @@ public HttpSecurity requestMatcher(RequestMatcher requestMatcher) { return this; } + public HttpSecurity securityMatcher(RequestMatcher requestMatcher) { + return this; + } + + public HttpSecurity securityMatcher(String... patterns) { + return this; + } + public HttpSecurity authorizeRequests( Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer) throws Exception { @@ -29,6 +38,17 @@ public ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrl return null; } + public HttpSecurity authorizeHttpRequests( + Customizer.AuthorizationManagerRequestMatcherRegistry> authorizeHttpRequestsCustomizer) + throws Exception { + return this; + } + + public AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry authorizeHttpRequests() + throws Exception { + return null; + } + public HttpSecurity requestMatchers(Customizer requestMatcherCustomizer) { return this; } @@ -37,6 +57,14 @@ public RequestMatcherConfigurer requestMatchers() { return null; } + public HttpSecurity securityMatchers(Customizer requestMatcherCustomizer) { + return this; + } + + public RequestMatcherConfigurer securityMatchers() { + return null; + } + public CsrfConfigurer csrf() { return null; } diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java new file mode 100644 index 000000000000..ff54fc7e3d11 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java @@ -0,0 +1,22 @@ +package org.springframework.security.config.annotation.web.configurers; + +import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; +import org.springframework.security.config.annotation.web.HttpSecurityBuilder; + +public final class AuthorizeHttpRequestsConfigurer> + extends AbstractHttpConfigurer, H> { + + public final class AuthorizationManagerRequestMatcherRegistry extends + AbstractRequestMatcherRegistry { + } + + public class AuthorizedUrl { + public AuthorizationManagerRequestMatcherRegistry permitAll() { + return null; + } + + public AuthorizationManagerRequestMatcherRegistry hasRole(String role) { + return null; + } + } +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java index 012997dc5024..be4e14019779 100644 --- a/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java @@ -12,5 +12,9 @@ public class AuthorizedUrl { public ExpressionInterceptUrlRegistry permitAll() { return null; } + + public ExpressionInterceptUrlRegistry hasRole(String role) { + return null; + } } }