This is a general purpose library for working with Content Security Policy policies.
- parse CSP policies into an easy-to-use representation
- ask questions about what a CSP policy allows or restricts
- warn about nonsensical CSP policies and deprecated or nonstandard features
- safely create and manipulate CSP policies
- render CSP policies
cspvalidator.org demonstrates some of the features of Salvation in action.
mvn install
The CSP specification is fairly complex even if you only care about the latest version. However, in practice you are likely to care that your policy does the things you intend it to on the browsers you care about, which are likely to implement different and potentially broken subsets of the specification (and potentially additional behavior which is not in the specification). And there are inevitable tradeoffs to be made regarding the size of your policy vs the security it provides.
As such, this project does not attempt to provide a one-size-fits-all way to manipulate a policy purely in terms of its effects - the full set of effects across all browsers is too vast to provide an effective API in general. It can help you build up a policy based on the directives and source-expressions you want, but to ensure your policy is correct, for your own definition of correct, there is no alternative to testing it on the real browsers you care about.
Parse a policy using either Policy.parseSerializedCSP
or Policy.parseSerializedCSPList
. The second parameter will be called for each warning or error.
String policyText = "script-src 'none'";
Policy policy = Policy.parseSerializedCSP(policyText, (severity, message, directiveIndex, valueIndex) -> {
System.err.println(severity.name() + " at directive " + directiveIndex + (valueIndex == -1 ? "" : " at value " + valueIndex) + ": " + message);
});
The high-level querying methods allow you to specify whatever relevant information you have. The missing information will be assumed to be worst-case - that is, these methods will return true
only if any object which matches the provided characteristics would be allowed, regardless of its other characteristics.
Policy policy = Policy.parseSerializedCSP("script-src http://a", Policy.PolicyErrorConsumer.ignored);
// true
System.out.println(policy.allowsExternalScript(
Optional.empty(),
Optional.empty(),
Optional.of(URI.parse("http://a")),
Optional.empty(),
Optional.empty()
));
// false
System.out.println(policy.allowsExternalScript(
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty()
));
Note that these methods were correct according to current draft of the CSP specification when this library was written, but no browser implements precisely the current draft, and changes to the specification may also invalidate assumptions this library makes. There is no alternative to testing on the browsers you care about.
Because the Policy
objects are rich structures, you can also ask about the presence or absence of specific directives or expressions:
Policy policy = Policy.parseSerializedCSP("script-src 'strict-dynamic'", Policy.PolicyErrorConsumer.ignored);
// Assumes the policy has a `script-src` directive (or else the `get` would throw), and checks if it contains the `'strict-dynamic'` source expression
System.out.println(policy.getFetchDirective(FetchDirectiveKind.ScriptSrc).get().strictDynamic());
Policy policy = Policy.parseSerializedCSP("", Policy.PolicyErrorConsumer.ignored);
policy.add("sandbox", Collections.emptyList(), Directive.DirectiveErrorConsumer.ignored);
// you can use the provided Java APIs to manipulate values Salvation knows about
policy.sandbox().get().setAllowScripts(true);
// or you can use the lower-level APIs to manipulate values directly
policy.sandbox().get().addValue("allow-something-new");
// "sandbox allow-scripts allow-something-new"
System.out.println(policy.toString());
policy.toString();
To reduce the overhead of running this library, it will now automatically be transpiled to JS as part of the compile goal by using TeaVM. It can then be placed on any webpage to be used as static JavaScript, thus alleviating the need for a JRE.
The transpiled code will be placed in target/javascript
as salvation-v${project.version}.min.js
.
If you experience errors relating to TeaVM transpiling, check the supported TeaVM classes.
First run mvn clean install
to build the JS file. Then include salvation-vX.X.X.min.js
in your webpage.
To use the parsing functions in on the webpage run window.main()
to initialize them. From then on, window.parseSerializedCSPList()
and window.parseSerializedCSP()
will be available.
parseSerializedCSP()
and parseSerializedCSPList()
will return strings containing the parsing results. If there are multiple results, they will be separated by a newline. This is simply because TeaVM requires a lot of extra work for it to be able to return JS objects.