Skip to content

Conversation

@munishchouhan
Copy link
Member

Overview

This PR implements HTTP security headers for all Wave service responses to improve security posture and protect against common web vulnerabilities.

Changes

1. HTTP Security Headers Implementation

New Files Created:

  • src/main/groovy/io/seqera/wave/configuration/SecurityHeadersConfig.groovy
  • src/main/groovy/io/seqera/wave/filter/SecurityHeadersFilter.groovy
  • src/test/groovy/io/seqera/wave/filter/SecurityHeadersFilterTest.groovy

Modified Files:

  • src/main/groovy/io/seqera/wave/filter/FilterOrder.groovy
  • src/main/resources/application.yml

Summary:
Implemented a new HTTP filter that adds industry-standard security headers to all Wave service responses. The filter runs with the highest priority (-120) to ensure security headers are always present.

Security Headers Added:

Header Default Value Purpose
Strict-Transport-Security max-age=31536000; includeSubDomains Enforces HTTPS connections
X-Frame-Options DENY Prevents clickjacking attacks
X-Content-Type-Options nosniff Prevents MIME type sniffing
Referrer-Policy strict-origin-when-cross-origin Controls referrer information
Permissions-Policy camera=(), microphone=(), geolocation=() Restricts browser features
Content-Security-Policy default-src 'self'; frame-ancestors 'none' Prevents XSS and injection attacks

Architecture:

SecurityHeadersConfig (Configuration)
         �
SecurityHeadersFilter (@ServerFilter, Order: -120)
         �
@ResponseFilter (adds headers to all responses)

Key Features:

  • � Fully configurable via application.yml
  • � Can be disabled with wave.security.headers.enabled: false
  • � Individual headers can be customized
  • � Implements Ordered interface for proper filter execution order

Configuration:

Default configuration added to application.yml:

wave:
  security:
    headers:
      enabled: true
      hsts:
        max-age: 31536000
        include-sub-domains: true
      frame-options: "DENY"
      content-type-options: "nosniff"
      referrer-policy: "strict-origin-when-cross-origin"
      permissions-policy: "camera=(), microphone=(), geolocation=()"
      csp: "default-src 'self'; frame-ancestors 'none'"

Filter Order:

SECURITY_HEADERS = -120  (Highest priority - NEW)
DENY_CRAWLER = -110
DENY_PATHS = -100
RATE_LIMITER = -50
PULL_METRICS = 10

Security Benefits

  1. HSTS: Prevents protocol downgrade attacks and cookie hijacking
  2. X-Frame-Options: Protects against clickjacking
  3. X-Content-Type-Options: Prevents MIME confusion attacks
  4. Referrer-Policy: Limits information leakage via referrer header
  5. Permissions-Policy: Restricts access to sensitive browser APIs
  6. CSP: Mitigates XSS and data injection attacks

Signed-off-by: munishchouhan <hrma017@gmail.com>
@munishchouhan
Copy link
Member Author

testing locally:

Testing Wave Security Headers...
================================

Testing: /service-info
---
✓ Strict-Transport-Security: PRESENT
✓ X-Frame-Options: PRESENT
✓ X-Content-Type-Options: PRESENT
✓ Referrer-Policy: PRESENT
✓ Permissions-Policy: PRESENT
✓ Content-Security-Policy: PRESENT

Testing: /v2/
---
✓ Strict-Transport-Security: PRESENT
✓ X-Frame-Options: PRESENT
✓ X-Content-Type-Options: PRESENT
✓ Referrer-Policy: PRESENT
✓ Permissions-Policy: PRESENT
✓ Content-Security-Policy: PRESENT

Test complete!

@munishchouhan
Copy link
Member Author

Check all headers:

%   curl -i http://localhost:9090/service-info | grep "X-Frame-Options"

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    58  100    58    0     0  17144      0 --:--:-- --:--:-- --:--:-- 19333
X-Frame-Options: DENY
%   curl -si http://localhost:9090/service-info | grep -E "^(Strict-Transport|X-Frame|X-Content|Referrer|Permissions|Content-Security)"

Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; frame-ancestors 'none'
% curl -si http://localhost:9090/service-info | grep "Strict-Transport-Security"
Strict-Transport-Security: max-age=31536000; includeSubDomains

%  curl -si http://localhost:9090/service-info | grep "X-Frame-Options"
X-Frame-Options: DENY

@munishchouhan munishchouhan self-assigned this Dec 23, 2025
Signed-off-by: munishchouhan <hrma017@gmail.com>
@munishchouhan
Copy link
Member Author

tested in dev:

Testing environment: https://wave.dev-seqera.io


>>> Test 1: Endpoint Reachability
✓ /service-info is reachable (HTTP 200)
✓ /v2/ is reachable (HTTP 200)

>>> Test 2: Security Headers Presence
  ℹ Testing endpoint: /service-info
✓ /service-info - Strict-Transport-Security matches expected value
✓ /service-info - X-Frame-Options matches expected value
✓ /service-info - X-Content-Type-Options matches expected value
✓ /service-info - Referrer-Policy matches expected value
✓ /service-info - Permissions-Policy matches expected value
✓ /service-info - Content-Security-Policy matches expected value
  ℹ Testing endpoint: /v2/
✓ /v2/ - Strict-Transport-Security matches expected value
✓ /v2/ - X-Frame-Options matches expected value
✓ /v2/ - X-Content-Type-Options matches expected value
✓ /v2/ - Referrer-Policy matches expected value
✓ /v2/ - Permissions-Policy matches expected value
✓ /v2/ - Content-Security-Policy matches expected value

>>> Test 3: HSTS Header Validation
✓ HSTS max-age is set to 31536000 (1 year)
✓ HSTS includeSubDomains directive is present

>>> Test 4: X-Frame-Options Validation
✓ X-Frame-Options is set to DENY (prevents clickjacking)

>>> Test 5: Content-Security-Policy Validation
✓ CSP contains frame-ancestors directive
✓ CSP contains default-src directive

>>> Test 6: Service Info API Response
✓ Service info returns valid JSON
✓ Service info contains 'serviceInfo' field

>>> Test 7: Error Pages Have Security Headers
✓ 404 error page includes security headers

>>> Test 8: Response Time Check
  ℹ Response time: 0.164170s (164ms)
✓ Response time is acceptable (< 5s)

>>> Test 9: Multiple Concurrent Requests
  ℹ Sending 10 concurrent requests...
200
200
200
200
200
200
200
200
200
200
✓ Service handles concurrent requests
  ℹ Note: Full concurrent test requires parallel execution

>>> Test 10: Security Headers on Different HTTP Methods
✓ GET requests include security headers
✓ HEAD requests include security headers
✓ OPTIONS requests include security headers

>>> Test 11: SSL/TLS Configuration
✓ SSL/TLS connection established
  ℹ TLS version: UNDEF


========================================
Test Summary
========================================

Environment: https://wave.dev-seqera.io
Timestamp:   2025-12-26 15:45:06

Total Tests:  28
Passed:       28
Failed:       0
Skipped:      0

Pass Rate:    100.00%

========================================
✓ ALL TESTS PASSED!
========================================


@munishchouhan
Copy link
Member Author

tested augmentation:

% wave -i ubuntu --config-file https://fusionfs.seqera.io/releases/v2.5.0-amd64.json  --wave-endpoint https://wave.dev-seqera.io/
wave.dev-seqera.io/wt/28851c3b97bc/library/ubuntu:latest
 % docker pull wave.dev-seqera.io/wt/28851c3b97bc/library/ubuntu:latest
latest: Pulling from wt/28851c3b97bc/library/ubuntu
Digest: sha256:bca3a2fdc3b293cfed293f53e8ee34424cf62cf5f101a54b29e29a4c55364fae
Status: Downloaded newer image for wave.dev-seqera.io/wt/28851c3b97bc/library/ubuntu:latest
wave.dev-seqera.io/wt/28851c3b97bc/library/ubuntu:latest

Signed-off-by: munishchouhan <hrma017@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants