Skip to main content

Create, maintain, parse and manipulate Content Security Policies

Project description

Handling Content-Security-Policy with less footguns

Create, maintain, parse and manipulate Content Security Policies.

For site developers / operators

Content-Security-Policy (CSP) is a very effective mitigation against cross site scripting (XSS). It should be right up there with HTTPS on your list of mitigations to deploy on your site. Depending on your applicaiton, creating and maintaining a CSP can be somewhat frickle and annoying. This library hopes to alleviate that pain by allowing you to create (or automate creating) your policy as code.

Django integration

There is a brand-new integration with django. Documentation outside the source-code is still a TODO (PRs welcome). You can get an idea from the corresponding tests.

pip install content-security-policy[django]

For researchers

Parse, analyze and manipulate csp strings.

Principles

Immutability

Any policy / directive / directive value object you create is immutable.

Strict construction

:warning: This feature is still being developed! There are a lot of things not yet being validated.

When explicitly constructing objects with invalid values, errors will be raised! For example, you can not construct a nonce source expression with non-base64 characters.

>>> NonceSrc("ungültig")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<redacted>/content_security_policy/values.py", line 55, in __init__
    raise BadSourceExpression(
content_security_policy.exceptions.BadSourceExpression: Nonce value 'ungültig' does not match ([A-Za-z]|[0-9]|[+\/\-_]){2, 0}={0, 2}

Lenient parsing

The parsing functions should be able to take any string and "somehow" parse it. If (parts of) the string can not be matched to a known directive or directive value, instances of UnrecognizedDirective and UnrecognizedValueItem will represent those parts of the string.

from content_security_policy.parse import *

policy_string = "script-src 'strict-dynamic' garbage; whatsthis directive 'supposedTobe'?"

policy = policy_from_string(policy_string)

for directive in policy:
    print(f"Name: {directive.name}\nType: {directive.__class__.__name__}\nValues:")
    for val in directive:
        print(f"\tType: {val.__class__.__name__}\n\tValue: {val}\n")
Name: script-src
Type: ScriptSrc
Values:
        Type: KeywordSource
        Value: 'strict-dynamic'

        Type: UnrecognizedValueItem
        Value: garbage

Name: whatsthis
Type: UnrecognizedDirective
Values:
        Type: UnrecognizedValueItem
        Value: directive

        Type: UnrecognizedValueItem
        Value: 'supposedTobe'?

Usage

There are classes for policy, different kinds of directives and directive values.

:information_source: Proper documentation is still a TODO.

For now, you will need to check the source code / rely on auto-completion. The tests cover a lot of the intended use-cases. Some of the general ideas are hopefully well conveyed in these examples:

Something very simple

from content_security_policy import *

policy = Policy(
    DefaultSrc(KeywordSource.self), FrameAncestors(SelfSrc), ObjectSrc(NoneSrc)
)
assert str(policy) == "default-src 'self'; frame-ancestors 'self'; object-src 'none'"

Something a little more dynamic

from content_security_policy import *

script_src = ScriptSrc()

for url in ["https://example.com/some-lib.js", "https://example-cdn.com/other-lib.js"]:
    script_src += HostSrc(url)

script_src += SelfSrc

assert str(
    script_src) == "script-src https://example.com/some-lib.js https://example-cdn.com/other-lib.js 'self'"

Parse and manipulate

from content_security_policy import *
from content_security_policy.parse import *

policy = policy_from_string(
    "deFault-src 'self'; Frame-Ancestors\t 'self'; \t object-src 'none'"
)

frame_ancestors = policy["frame-ancestors"]
# alternatively:
# frame_ancestors = policy.frame_ancestors
frame_ancestors += HostSrc("https://example.com")

# Splice frame-ancestors from the policy
policy -= FrameAncestors

# Adding always appends the directive at the end!
policy += frame_ancestors

# Notice that whitespace and capitalization was preserved!
assert str(
    policy) == "deFault-src 'self'; \t object-src 'none'; Frame-Ancestors\t 'self' https://example.com"

Installation

pip install content-security-policy

Priorities

1. Correctness

As per the license, there is no warranty, but the number one rule is:

If you don't deliberately bypass any safeguards when constructing a CSP programmatically, the string you obtain from it will be according to spec.

Note that this does not mean your CSP will be effective! A script-src with 'unsafe-inline' is correct according to the spec, but you loose any XSS protection CSP could have provided you!

2. Useful

Handling the objects created with this library should be reasonably intuitive and " pythonic".

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

content_security_policy-0.2.3.tar.gz (29.8 kB view details)

Uploaded Source

Built Distribution

content_security_policy-0.2.3-py3-none-any.whl (40.0 kB view details)

Uploaded Python 3

File details

Details for the file content_security_policy-0.2.3.tar.gz.

File metadata

  • Download URL: content_security_policy-0.2.3.tar.gz
  • Upload date:
  • Size: 29.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.3 Linux/6.9.1-arch1-1

File hashes

Hashes for content_security_policy-0.2.3.tar.gz
Algorithm Hash digest
SHA256 e84217ccbd44c3eed5c2086d8de28f937a802ec442088646eaf21bf6b57ad695
MD5 27c28f0f7b52f0708d0fc3e6e5ab9f65
BLAKE2b-256 47e8e9f9b8410a4457653ca74444108edb9eb431b4dfbc92ae860bad8a6c6168

See more details on using hashes here.

File details

Details for the file content_security_policy-0.2.3-py3-none-any.whl.

File metadata

File hashes

Hashes for content_security_policy-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 4888c862b6f76c3f3033fda2fd2df9aa1012424140b360878296d8d184436d31
MD5 76d37d23f23257498e227a60a331c7bc
BLAKE2b-256 fbbaa0dfb1ed46c97a350fddfa30b59c165ca988aa9ee3238fd9e2391be58c7d

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page