HTTP Strict Transport Security(HSTS) for Wazuh & Kibana


HTTP Strict Transport Security (HSTS) is a vital security measure in today’s
digital landscape, where data security and privacy are paramount. With the increasing sophistication of cyber threats, safeguarding sensitive
information transmitted over the internet has become critical for individuals
and organizations.

HSTS plays a crucial role in this regard by enforcing secure connections. It
instructs browsers to only interact with a website using a secure HTTPS
connection, rather than the less secure HTTP. This simple yet powerful
mechanism mitigates the risk of man-in-the-middle attacks, where attackers
can intercept or manipulate data being transferred over less secure
connections.

This article describes how to add HTTP headers to implement HSTS
(assuming HTTPS is already implemented):

Wazuh Dashboard:

Navigate to the file /etc/wazuh-dashboard/opensearch_dashboards.yml and add the option server.customResponseHeaders with our STS and any custom HTTP headers as shown below:

server.host: 0.0.0.0
opensearch.hosts: https://127.0.0.1:9200
server.port: 443
opensearch.ssl.verificationMode: certificate
opensearch.requestHeadersAllowlist: ["securitytenant","Authorization"]
opensearch_security.multitenancy.enabled: false
opensearch_security.readonly_mode.roles: ["kibana_read_only"]
server.ssl.enabled: true
server.ssl.key: "/etc/wazuh-dashboard/certs/wazuh-dashboard-key.pem"
server.ssl.certificate: "/etc/wazuh-dashboard/certs/wazuh-dashboard.pem"
opensearch.ssl.certificateAuthorities: ["/etc/wazuh-dashboard/certs/root-ca.pem"
uiSettings.overrides.defaultRoute: /app/wazuh
opensearch_security.cookie.secure: true
server.customResponseHeaders: {"Strict-Transport-Security":" max-age=63072000;includeSubDomains; preload","x-content-type-options": "nosniff"}

Restart Wazuh Dashboard:

systemctl retart wazuh-dashboard

Confirm the implementation: curl -v https://wazuh-dashboard -k -X

curl -v https://wazuh-dashboard -k -X
HTTP/1.1 302 Found
location: /app/login?
strict-transport-security: max-age=63072000; includeSubDomains; preload;
x-content-type-options: nosniff
osd-name: localhost.localdomain
x-frame-options: sameorigin
cache-control: private, no-cache, no-store, must-revalidate
set-cookie: security_authentication=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:0
content-length: 0
Date: Thu, 04 Jan 2024 16:50:08 GMT
Connection: keep-alive
Keep-Alive: timeout=120


Kibana:

Use the option server.customResponseHeaders within the file /etc/kibana/kibana.yml as shown below (Note the syntax is different even
if the option is the same):

server.host: 0.0.0.0
server.port: 443
elasticsearch.hosts: https://localhost:9200
elasticsearch.password: xfdddd
# Elasticsearch from/to Kibana
elasticsearch.ssl.certificateAuthorities: /etc/kibana/certs/ca/ca.crt
elasticsearch.ssl.certificate: /etc/kibana/certs/kibana.crt
elasticsearch.ssl.key: /etc/kibana/certs/kibana.key

# Browser from/to Kibana
server.ssl.enabled: true
server.ssl.certificate: /etc/kibana/certs/kibana.crt
server.ssl.key: /etc/kibana/certs/kibana.key

# Elasticsearch authentication
xpack.security.enabled: true
elasticsearch.username: elastic
uiSettings.overrides.defaultRoute: "/app/wazuh"
elasticsearch.ssl.verificationMode: certificate
server.customResponseHeaders:
Strict-Transport-Security: "max-age=63072000; includeSubDomains; preload;"
X-content-type-options: "nosniff"

Restart Kibana: systemctl restart kibana

Confirm the implementation: curl -v https://kibana -k

HTTP/1.1 302 Found
location: /login?next=%2F
strict-transport-security: max-age=63072000; includeSubDomains; preload;
x-content-type-options: nosniff
kbn-name: localhost.localdomain
kbn-license-sig: 8abb6707d135b062d0066e8049907961156f811af5f4ba3892e8a9006f94e
x-frame-options: sameorigin
cache-control: private, no-cache, no-store, must-revalidate
content-length: 0
Date: Thu, 04 Jan 2024 17:10:14 GMT 
Connection: keep-alive
Keep-Alive: timeout=120

I hope you find it useful 😀


Leave a Reply

Your email address will not be published. Required fields are marked *