Browse Source
Address PR review comments
- Use kebab-case 'report-only' in web-ui configs to match thingsboard.yml
- Add log.warn for unrecognized X-Frame-Options values in customizer
- Replace @Configuration with @Component on HttpSecurityHeadersProperties
- Add comment explaining '!== false' vs truthiness pattern in server.ts
pull/15254/head
Viacheslav Klimov
7 months ago
Failed to extract signature
5 changed files with
15 additions and
7 deletions
application/src/main/java/org/thingsboard/server/config/HttpSecurityHeadersCustomizer.java
application/src/main/java/org/thingsboard/server/config/HttpSecurityHeadersProperties.java
msa/web-ui/config/custom-environment-variables.yml
msa/web-ui/config/default.yml
msa/web-ui/server.ts
@ -16,11 +16,13 @@
package org.thingsboard.server.config ;
import lombok.RequiredArgsConstructor ;
import lombok.extern.slf4j.Slf4j ;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer ;
import org.springframework.security.web.header.writers.StaticHeadersWriter ;
import org.springframework.stereotype.Component ;
import org.springframework.util.StringUtils ;
@Slf4j
@Component
@RequiredArgsConstructor
public class HttpSecurityHeadersCustomizer {
@ -41,6 +43,9 @@ public class HttpSecurityHeadersCustomizer {
if ( "DENY" . equalsIgnoreCase ( value ) ) {
headers . frameOptions ( HeadersConfigurer . FrameOptionsConfig : : deny ) ;
} else {
if ( ! "SAMEORIGIN" . equalsIgnoreCase ( value ) ) {
log . warn ( "Unrecognized X-Frame-Options value '{}', falling back to SAMEORIGIN. Valid values: DENY, SAMEORIGIN" , value ) ;
}
headers . frameOptions ( HeadersConfigurer . FrameOptionsConfig : : sameOrigin ) ;
}
}
@ -17,9 +17,9 @@ package org.thingsboard.server.config;
import lombok.Data ;
import org.springframework.boot.context.properties.ConfigurationProperties ;
import org.springframework.context.annotation.Configuration ;
import org.springframework.stereotype.Component ;
@Configuration
@Component
@ConfigurationProperties ( prefix = "security.headers" )
@Data
public class HttpSecurityHeadersProperties {
@ -38,7 +38,7 @@ security:
content-security-policy:
enabled : "SECURITY_HEADERS_CONTENT_SECURITY_POLICY_ENABLED"
value : "SECURITY_HEADERS_CONTENT_SECURITY_POLICY_VALUE"
reportO nly : "SECURITY_HEADERS_CONTENT_SECURITY_POLICY_REPORT_ONLY"
report-o nly : "SECURITY_HEADERS_CONTENT_SECURITY_POLICY_REPORT_ONLY"
logger:
level : "LOGGER_LEVEL"
path : "LOG_FOLDER"
@ -38,7 +38,7 @@ security:
content-security-policy:
enabled : false
value : ""
reportO nly : false
report-o nly : false
logger:
level : "info"
path : "logs"
@ -60,7 +60,9 @@ let connections: Socket[] = [];
const app = express ( ) ;
server = http . createServer ( app ) ;
// Build security headers map once at startup
// Build security headers map once at startup.
// Headers enabled by default use '!== false' so they stay on unless explicitly disabled.
// Headers disabled by default use simple truthiness checks.
const securityHeaders : Record < string , string > = { } ;
if ( config . has ( 'security.headers' ) ) {
const hc : any = config . get ( 'security.headers' ) ;
@ -74,9 +76,10 @@ let connections: Socket[] = [];
securityHeaders [ 'X-Frame-Options' ] = hc [ 'x-frame-options' ] ? . value || 'SAMEORIGIN' ;
}
if ( hc [ 'content-security-policy' ] ? . enabled && hc [ 'content-security-policy' ] ? . value ) {
const name = hc [ 'content-security-policy' ] ? . reportOnly
const csp = hc [ 'content-security-policy' ] ;
const name = csp [ 'report-only' ]
? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy' ;
securityHeaders [ name ] = h c[ 'content-security-policy' ] . value ;
securityHeaders [ name ] = csp . value ;
}
} else {
// Defaults when no security.headers config block exists