Policy Builder

CSP()

Directives: base_uri(sources), block_all_mixed_content(), connect_src(sources), default_src(sources), font_src(sources), form_action(sources), frame_ancestors(sources), frame_src(sources), img_src(sources), manifest_src(sources), media_src(sources), object_src(sources), plugin_types(types), report_to(json_object), report_uri(uri), require_sri_for(values), sandbox(values), script_src(sources), style_src(sources), upgrade_insecure_requests(), worker_src(sources)

Values(): self_, none, unsafe_inline, unsafe_eval, strict_dynamic, nonce(nonce_value), all = “*”

Example:

csp_value = (
    SecurePolicies.CSP()
    .default_src(SecurePolicies.CSP().Values.none)
    .base_uri(SecurePolicies.CSP().Values.self_)
    .block_all_mixed_content()
    .connect_src(SecurePolicies.CSP().Values.self_, "api.spam.com")
    .frame_src(SecurePolicies.CSP().Values.none)
    .img_src(SecurePolicies.CSP().Values.self_, "static.spam.com")
)

# default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' api.spam.com; frame-src 'none'; img-src 'self' static.spam.com

You can check the effectiveness of your CSP Policy at the CSP Evaluator

HSTS()

Directives: include_subDomains(), max_age(seconds), preload()

Example:

hsts_value = (
    SecurePolicies.HSTS()
    .include_subdomains()
    .preload()
    .max_age(SecurePolicies.Seconds.one_month)
)

# includeSubDomains; preload; max-age=2592000

XXP()

Directives: disabled() = 0, enabled() = 1, enabled_block() = 1; mode=block, enabled_report(uri) = 1; report=uri

Example:

xxp_value = SecurePolicies.XXP().enabled_block()

# 1; mode=block

XFO()

Directives: allow_from(uri), deny(), sameorigin()

Example:

xfo_value = SecurePolicies.XFO().deny()

# deny

Referrer()

Directives: no_referrer(), no_referrer_when_downgrade(), origin(), origin_when_cross_origin(), same_origin(), strict_origin(), strict_origin_when_cross_origin(), unsafe_url()

Example:

referrer_value = SecurePolicies.Referrer().no_referrer()

# no-referrer

Feature()

Directives: accelerometer(allowlist), ambient_light_sensor(allowlist), autoplay(allowlist), camera(allowlist), document_domain(allowlist), encrypted_media(allowlist), fullscreen(allowlist), geolocation(allowlist), gyroscope(allowlist), magnetometer(allowlist), microphone(allowlist), midi(allowlist), payment(allowlist), picture_in_picture(allowlist), speaker(allowlist), sync_xhr(allowlist), usb(allowlist), Values(allowlist), vr(allowlist)

Values(): self_, none, src, all_ = “*”

Example:

feature_value = (
    SecurePolicies.Feature()
    .geolocation(SecurePolicies.Feature.Values.self_, "spam.com")
    .vibrate(SecurePolicies.Feature.Values.none)
)

# geolocation 'self' spam.com; vibrate 'none'

Cache()

Directives: immutable(), max_age(seconds), max_stale(seconds), min_fresh(seconds), must_revalidate(), no_cache(), no_store(), no_transform(), only_if_cached(), private(), proxy_revalidate(), public(), s_maxage(seconds), stale_if_error(seconds), stale_while_revalidate(seconds),

Example:

cache_value = SecurePolicies.Cache().no_store().must_revalidate().proxy_revalidate()

# no-store, must-revalidate, proxy-revalidate

Seconds

Values: five_minutes = “300”, one_week = “604800”, one_month = “2592000”, one_year = “31536000”, two_years = “63072000”

Usage

Example:

from sanic import Sanic
from secure import SecureHeaders, SecurePolicies

csp_value = (
    SecurePolicies.CSP()
    .default_src(SecurePolicies.CSP().Values.none)
    .base_uri(SecurePolicies.CSP().Values.self_)
    .block_all_mixed_content()
    .connect_src(SecurePolicies.CSP().Values.self_, "api.spam.com")
    .frame_src(SecurePolicies.CSP().Values.none)
    .img_src(SecurePolicies.CSP().Values.self_, "static.spam.com")
)

hsts_value = (
    SecurePolicies.HSTS()
    .include_subdomains()
    .preload()
    .max_age(SecurePolicies.Seconds.one_month)
)

xxp_value = SecurePolicies.XXP().enabled_block()

xfo_value = SecurePolicies.XFO().deny()

referrer_value = SecurePolicies.Referrer().no_referrer()

feature_value = (
    SecurePolicies.Feature()
    .geolocation(SecurePolicies.Feature.Values.self_, "spam.com")
    .vibrate(SecurePolicies.Feature.Values.none)
)

cache_value = SecurePolicies.Cache().no_store().must_revalidate().proxy_revalidate()

secure_headers = SecureHeaders(
    csp=csp_value,
    hsts=hsts_value,
    xfo=xfo_value,
    xxp=xxp_value,
    referrer=referrer_value,
    feature=feature_value,
    cache=cache_value,
)
secure_cookie = SecureCookie()

app = Sanic()

. . .

@app.middleware("response")
async def set_secure_headers(request, response):
    secure_headers.sanic(response)

. . .

Response Headers:

Strict-Transport-Security: includeSubDomains; preload; max-age=2592000
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' api.spam.com; frame-src 'none'; img-src 'self' static.spam.com
Referrer-Policy: no-referrer
Cache-control: no-store, must-revalidate, proxy-revalidate
Feature-Policy: geolocation 'self' spam.com; vibrate 'none'