description: > Basic security for HTML and JSON response bodies.
Check out secure web development{:rel="noopener"} and secure response headers{:rel="noopener"} for more notes.
This cheat sheet only covers HTML and JSON response bodies. Sample code uses
a combination of slim, and pseudo code. Single letter methods u
, j
escape
their argument's contents.
Table of Contents
Display input, and user-controlled data securely:
Content-Type
header matches the body.src="https://#{ u(uri.host + uri.path) }"
= j hsh.to_json
meta name="robots" content="noindex, follow"
meta name="referrer" content="origin"
= csrf_metatag
/ short for:
meta name="_csrf" content="#{ csrf_token }"
Avoid caching pages with csrf-token
named meta
tags. Instead, retrieve
the token when users perform the first non GET
request as a pre-flight
GET
request to session/csrf
.
Secure CDN loaded assets by adding the integrity
attribute to script
s and link
s.
To prevent attackers from reading data cross-origin we must add the crossorigin
attribute with either anonymous
or use-credentials
value.
script[
src="https://cdn.example.com/in-vogue.js"
integrity="sha256-oqV...= sha512-zM0...=="
crossorigin="anonymous"
]
If our CDN provider doesn't provide integrity hashes we can generate them using httpie{:rel="nofollow noreferrer noopener"} and openssl:
$ http https://trusted.cdn.com/path/to/asset.css | openssl dgst -sha512 -binary | openssl enc -base64 -A
In the first example we included both the sha512, and the less secured sha256 for compatibility with older browsers. Modern browsers will check against the most secured version by default.
a
elements) pointing to external services.a href="https://example.com" rel="nofollow noreferrer noopener"
If for SEO the site requires links (a
) to be followed merely remove nofollow
.
Keeping noopener
to help prevent tabnabbing attacks, won't affect SEO{:rel="nofollow noreferrer noopener"}.
noreferrer
is a fallback for browsers{:rel="nofollow noreferrer noopener"}
that still don't support noopener
.
a href="http://example.com/" referrerPolicy="origin"
| click me
input type="text" name="passport-number" autocomplete="off"
Modern browsers{:rel="nofollow noreferrer noopener"}
ignore the off
option
for inputs type username
, password
, current-password
so credential managers
can auto fill them.
form action="/replace" id="replace" method="post"
input name="_method" type="hidden" value="put"
= csrf_tag
When for legitimate reasons we allow input and/or end-users to manipulate data into structured, and styled content:
h1
= user_controlled.content
div
= input_generated.content
p attr="#{ attribute.value }"
| content
Some elements can NEVER be consider safe enough to inject input and/or user-manipulated content to.
script
= inline_scripts
/!
= inline_comments
div "#{ as_attribute_name }"=test
div
"#{ as_tag_name }".some-class
style
= inline_styling
Some CSS contexts can NEVER be consider to save to use with input even if properly escaped. (Pseudo code)
{ background-url: "URL_TO_MALICIOUS_JS"; } // same for other attributes that can take URLs
{ text-size: "expression(MALICIOUS_JS)"; } // only in IE
Some expressions that will NEVER handle input safely:
window.setInterval('HERE_WE_ALWAYS_GET_XSSED');
This category of attacks doesn't affect a specific piece of software. Web apps compressing HTTP body responses (eg. gzip, brotli), whilst reflecting user provided content, and secrets (eg. CSRF tokens, sensitive data) are likely to be vulnerable.
The recommended mitigation practices, in order of effectiveness, are:
Keep in mind that the practicality of each mitigation varies from one app to another.
Check out secure web development{:rel="noopener"} and secure response headers{:rel="noopener"} for more resources.