mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-04-06 02:58:15 +00:00
Merge branch 'PROWLER-386-add-cloudflare-provider-to-cli' into cloudflare-pr2-tls-email-checks
This commit is contained in:
@@ -3,7 +3,25 @@ from prowler.providers.cloudflare.services.zones.zones_client import zones_clien
|
||||
|
||||
|
||||
class zones_dnssec_enabled(Check):
|
||||
"""Ensure that DNSSEC is enabled for Cloudflare zones.
|
||||
|
||||
DNSSEC (Domain Name System Security Extensions) adds cryptographic signatures
|
||||
to DNS records, protecting against DNS spoofing and cache poisoning attacks.
|
||||
When enabled, it ensures that DNS responses are authentic and have not been
|
||||
tampered with during transit.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[CheckReportCloudflare]:
|
||||
"""Execute the DNSSEC enabled check.
|
||||
|
||||
Iterates through all Cloudflare zones and verifies that DNSSEC status
|
||||
is set to 'active'. A zone passes the check if DNSSEC is actively
|
||||
protecting its DNS records; otherwise, it fails.
|
||||
|
||||
Returns:
|
||||
A list of CheckReportCloudflare objects with PASS status if DNSSEC
|
||||
is active, or FAIL status if DNSSEC is not enabled for the zone.
|
||||
"""
|
||||
findings = []
|
||||
for zone in zones_client.zones.values():
|
||||
report = CheckReportCloudflare(
|
||||
|
||||
@@ -3,7 +3,28 @@ from prowler.providers.cloudflare.services.zones.zones_client import zones_clien
|
||||
|
||||
|
||||
class zones_hsts_enabled(Check):
|
||||
"""Ensure that HSTS is enabled with secure settings for Cloudflare zones.
|
||||
|
||||
HTTP Strict Transport Security (HSTS) forces browsers to only connect via
|
||||
HTTPS, preventing protocol downgrade attacks and cookie hijacking. This check
|
||||
verifies that HSTS is enabled with a minimum max-age of 6 months (15768000
|
||||
seconds) and includes subdomains for complete protection.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[CheckReportCloudflare]:
|
||||
"""Execute the HSTS enabled check.
|
||||
|
||||
Iterates through all Cloudflare zones and validates HSTS configuration
|
||||
against security best practices. The check verifies three conditions:
|
||||
1. HSTS is enabled for the zone
|
||||
2. The includeSubdomains directive is set to protect all subdomains
|
||||
3. The max-age is at least 6 months (15768000 seconds)
|
||||
|
||||
Returns:
|
||||
A list of CheckReportCloudflare objects with PASS status if all
|
||||
HSTS requirements are met, or FAIL status if HSTS is disabled,
|
||||
missing subdomain inclusion, or has insufficient max-age.
|
||||
"""
|
||||
findings = []
|
||||
# Recommended minimum max-age is 6 months (15768000 seconds)
|
||||
recommended_max_age = 15768000
|
||||
|
||||
@@ -3,7 +3,26 @@ from prowler.providers.cloudflare.services.zones.zones_client import zones_clien
|
||||
|
||||
|
||||
class zones_https_redirect_enabled(Check):
|
||||
"""Ensure that Always Use HTTPS redirect is enabled for Cloudflare zones.
|
||||
|
||||
The Always Use HTTPS setting automatically redirects all HTTP requests to
|
||||
HTTPS, ensuring that all traffic to the zone is encrypted. This prevents
|
||||
man-in-the-middle attacks and protects sensitive data transmitted between
|
||||
clients and the origin server.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[CheckReportCloudflare]:
|
||||
"""Execute the HTTPS redirect enabled check.
|
||||
|
||||
Iterates through all Cloudflare zones and verifies that the
|
||||
always_use_https setting is turned on. When enabled, Cloudflare
|
||||
automatically redirects all HTTP requests to their HTTPS equivalents.
|
||||
|
||||
Returns:
|
||||
A list of CheckReportCloudflare objects with PASS status if
|
||||
Always Use HTTPS is enabled ('on'), or FAIL status if the
|
||||
setting is disabled for the zone.
|
||||
"""
|
||||
findings = []
|
||||
for zone in zones_client.zones.values():
|
||||
report = CheckReportCloudflare(
|
||||
|
||||
@@ -3,7 +3,27 @@ from prowler.providers.cloudflare.services.zones.zones_client import zones_clien
|
||||
|
||||
|
||||
class zones_min_tls_version_secure(Check):
|
||||
"""Ensure that minimum TLS version is set to 1.2 or higher for Cloudflare zones.
|
||||
|
||||
TLS 1.0 and 1.1 have known vulnerabilities (BEAST, POODLE) and are deprecated.
|
||||
Setting the minimum TLS version to 1.2 or higher ensures that only secure
|
||||
cipher suites are used for encrypted connections, protecting against
|
||||
downgrade attacks and known cryptographic weaknesses.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[CheckReportCloudflare]:
|
||||
"""Execute the minimum TLS version check.
|
||||
|
||||
Iterates through all Cloudflare zones and verifies that the minimum
|
||||
TLS version is configured to 1.2 or higher. The check parses the
|
||||
min_tls_version setting as a float for comparison, defaulting to 0
|
||||
if the value cannot be parsed.
|
||||
|
||||
Returns:
|
||||
A list of CheckReportCloudflare objects with PASS status if the
|
||||
minimum TLS version is 1.2 or higher, or FAIL status if older
|
||||
TLS versions (1.0, 1.1) are still allowed.
|
||||
"""
|
||||
findings = []
|
||||
|
||||
for zone in zones_client.zones.values():
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"Provider": "cloudflare",
|
||||
"CheckID": "zones_ssl_strict",
|
||||
"CheckTitle": "SSL/TLS encryption mode is set to Full Strict",
|
||||
"CheckTitle": "SSL/TLS encryption mode is set to Full, or Full Strict",
|
||||
"CheckType": [],
|
||||
"ServiceName": "zones",
|
||||
"SubServiceName": "",
|
||||
|
||||
@@ -3,7 +3,28 @@ from prowler.providers.cloudflare.services.zones.zones_client import zones_clien
|
||||
|
||||
|
||||
class zones_ssl_strict(Check):
|
||||
"""Ensure that SSL/TLS encryption mode is set to strict for Cloudflare zones.
|
||||
|
||||
The SSL/TLS encryption mode determines how Cloudflare connects to the origin
|
||||
server. In 'strict' or 'full' mode, Cloudflare validates the origin
|
||||
server's SSL certificate, ensuring end-to-end encryption with certificate
|
||||
verification. Lower modes (off, flexible, full) are vulnerable to
|
||||
man-in-the-middle attacks between Cloudflare and the origin.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[CheckReportCloudflare]:
|
||||
"""Execute the SSL strict mode check.
|
||||
|
||||
Iterates through all Cloudflare zones and verifies that the SSL/TLS
|
||||
encryption mode is set to 'strict' or 'full'. These modes
|
||||
require a valid SSL certificate on the origin server and provide
|
||||
full end-to-end encryption with certificate validation.
|
||||
|
||||
Returns:
|
||||
A list of CheckReportCloudflare objects with PASS status if
|
||||
SSL mode is 'strict' or 'full', or FAIL status if using
|
||||
less secure modes like 'off', 'flexible', or 'full'.
|
||||
"""
|
||||
findings = []
|
||||
for zone in zones_client.zones.values():
|
||||
report = CheckReportCloudflare(
|
||||
@@ -11,11 +32,11 @@ class zones_ssl_strict(Check):
|
||||
resource=zone,
|
||||
)
|
||||
ssl_mode = (zone.settings.ssl_encryption_mode or "").lower()
|
||||
if ssl_mode in ["strict", "full_strict"]:
|
||||
if ssl_mode in ["strict", "full"]:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"SSL/TLS encryption mode is set to {ssl_mode} for zone {zone.name}."
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"SSL/TLS encryption mode is set to {ssl_mode} for zone {zone.name}."
|
||||
report.status_extended = f"SSL/TLS encryption mode is set to {ssl_mode} for zone {zone.name}, which is not strict or full."
|
||||
findings.append(report)
|
||||
return findings
|
||||
|
||||
@@ -73,43 +73,6 @@ class Test_zones_ssl_strict:
|
||||
== f"SSL/TLS encryption mode is set to strict for zone {ZONE_NAME}."
|
||||
)
|
||||
|
||||
def test_zone_ssl_full_strict_mode(self):
|
||||
zones_client = mock.MagicMock
|
||||
zones_client.zones = {
|
||||
ZONE_ID: CloudflareZone(
|
||||
id=ZONE_ID,
|
||||
name=ZONE_NAME,
|
||||
status="active",
|
||||
paused=False,
|
||||
settings=CloudflareZoneSettings(
|
||||
ssl_encryption_mode="full_strict",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_cloudflare_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.cloudflare.services.zones.zones_ssl_strict.zones_ssl_strict.zones_client",
|
||||
new=zones_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.cloudflare.services.zones.zones_ssl_strict.zones_ssl_strict import (
|
||||
zones_ssl_strict,
|
||||
)
|
||||
|
||||
check = zones_ssl_strict()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"SSL/TLS encryption mode is set to full_strict for zone {ZONE_NAME}."
|
||||
)
|
||||
|
||||
def test_zone_ssl_full_mode(self):
|
||||
zones_client = mock.MagicMock
|
||||
zones_client.zones = {
|
||||
@@ -141,7 +104,7 @@ class Test_zones_ssl_strict:
|
||||
check = zones_ssl_strict()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"SSL/TLS encryption mode is set to full for zone {ZONE_NAME}."
|
||||
@@ -181,7 +144,7 @@ class Test_zones_ssl_strict:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"SSL/TLS encryption mode is set to flexible for zone {ZONE_NAME}."
|
||||
== f"SSL/TLS encryption mode is set to flexible for zone {ZONE_NAME}, which is not strict or full."
|
||||
)
|
||||
|
||||
def test_zone_ssl_off_mode(self):
|
||||
@@ -218,5 +181,5 @@ class Test_zones_ssl_strict:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"SSL/TLS encryption mode is set to off for zone {ZONE_NAME}."
|
||||
== f"SSL/TLS encryption mode is set to off for zone {ZONE_NAME}, which is not strict or full."
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user