Structural Safety
Phlex can provide strong HTML safety due to its structural design.
What is cross-site-scripting?
Cross-site scripting (XSS) is when an attacker injects malicious scripts into websites that are then executed in other people’s browsers. As a simple example, what if one user says their name is <script type="text/javascript">alert(1)</script>
and you subsequently display that user’s name to another unsuspecting user.
dt { "Name" }
dd { @user.name }
If the second user sees the alert, that means the first user could have run any code in their browser logged in as them.
How Phlex prevents cross-site-scripting
Phlex prevents cross-site-scripting in a number of different ways.
Text content
All text content is escaped by default. There are five characters that can be used to construct dangerous strings in HTML and they are escaped according to this table:
Original character | Escape |
---|---|
& | & |
< | < |
> | > |
" | " |
' | ' |
Attribute keys
Because Phlex uses Ruby keyword arguments for attributes, it is possible that you might output unsafe strings in attribute keys.
div(**@user.settings)
When rendering these attribute keys, Phlex looks for the unsafe characters and raises an error if any are found. In this case, it raises rather than escaping because it’s not a good idea to splat user data like this. The code should be fixed.
Attribute values
Unlike attribute keys, it is reasonable to output user data in attribute values.
input type: "text", value: @user.name
Phlex wraps attribute values in double quotes ("
) so it escapes double quotes in the attribute values, replacing them with "
.
Unsafe attributes
Some attributes are so unsafe, we completely prevent them by default, raising an error. If your Content Security Policy allows for unsafe inline JavaScript, the attribute onclick
would execute its value as JavaScript when the element is clicked.
Phlex prevents the use of:
- any attribute that starts with
on
and doesn’t contain a dash (-
) srcdoc
sandbox
http-equiv
TIP
You can bypass this guard by branding the value as safe with the safe
method.
button onclick: safe("alert(1)")
Ref attributes
Attributes that reference URLs can be used to execute JavaScript code by using the javascript:
protocol. For example, if your Content Security Policy allows for unsafe inline JavaScript, this link would trigger a JavaScript alert when clicked:
<a href="javascript:alert(1)">Click me</a>
Phlex strips the JavaScript protocol from the following ref attributes:
href
src
action
formaction
lowsrc
dynsrc
background
ping
Browsers are incredibly lenient in what they count as the JavaScript protocol so Phlex takes care to ignore whitespace, to match uppercase, lowercase or mixed case and to prevent tricks like javascript:javascript:alert(1)
.
TIP
You can bypass this guard by branding the value as safe with the safe
method.
a(href: safe("javascript:alert(1)")) { "Click me" }
Additional measures
While Phlex makes every effort to prevent cross-site-scripting attacks by default, there are some additional measures you can take to be extra safe.
Configure a strong Content Security Policy
We strongly recommend configuring a strong Content Security Policy (CSP) that does not allow unsafe-inline JavaScript. Please also see the Rails Guide to configuring a Content Security Policy.
Don’t make a habit of branding things as safe
The safe
method — and in Rails, calling .html_safe
on a String — brand that string as HTML safe. Doing this bypasses security features and allows for the string to be output as HTML.
While it’s sometimes necessary to use this feature, it should be used carefully and kept close to the escaping/sanitization logic.
How is this different to ERB?
Since ERB is string-based, it cannot follow the structure of your HTML. ERB performs basic HTML-escaping, but it doesn’t know if you’re outputting a value as part of a specific attribute.
For example, here ERB doesn’t know that @user.bio_link
is being rendered in an href
attribute.
<a href="<%= @user.bio_link %>">
Reporting security vulnerabilities
If you believe you have found a security vulnerability in Phlex, please do not open an issue or pull request. Instead, please send us a private advisory via GitHub.