Saptak's Blog Posts
Adding CSP hashes for styles in Chromium
Posted: 2021-01-17T14:13:55+05:30Content Security Policy (or CSP) is a way of avoiding certain types of website-related attacks like cross-site scripting and malicious data injections. It is a way by which website developers can tell the browser what content origins are approved so that everything else is blocked. One needs to add a Content-Security-Policy
HTTP header mentioning the sources which they allow for loading scripts, styles, images, etc.
To read in detail about CSP, check Content Security Policy Level 3 working draft.
We are going to discuss here why sha256 hashes often don't let inline styles to not pass in chromium browsers. Chromium browser console complains about the style-src hashes mismatch even though it shows them to be the same. Why? And how to solve it?
TL;DR: If using <style>
, use style-src
. If using style=""
attribute in HTML tag, use style-src-attr
Now, if you are interested in more information, let's dive a little deeper into what's going on.
Hashes to allow inline styles & scripts
The usual practice of having a tight, secure CSP is to not allow any inline style or inline scripts. This helps mitigate malicious scripts entered via data injection from getting executed.
When I say inline scripts, one might understand 2 different scenarios:
<!-- Scenario 1 -->
<script>alert('Hello world');</script>
or
<!-- Scenario 2 -->
<button onclick="alert('Hello world');">
Click me!
</button>
Now, the easiest way to allow this would be to add unsafe-inline
in script-src
of the CSP. But then we are back to the problem of executing malicious scripts entered by data injection. There are two ways to still allow only these scripts to work: nonce
and sha256
hashes. We are going to talk about sha256
hashes here.
The idea is to get the sha256 hash of the entire script and add it to the script-src
. So in this case, it would be something like this:
script-src 'self' 'sha256-DUTqIDSUj1HagrQbSjhJtiykfXxVQ74BanobipgodCo='
You can get the hash from https://report-uri.com/home/hash. Also, chromium browsers will usually show the hash that should be added for a particular inline script.
The Problem
Now, all this sounds good, and in Firefox, just adding the above to your CSP will make both the scripts to work. However, in chromium, the above CSP will work only in Scenario 1 but not in Scenario 2. You can read more about the discussion here: https://bugs.chromium.org/p/chromium/issues/detail?id=546106#c8
In JavaScript, I think in general scenario 1 will be much more encouraged than scenario 2. So scenario 2 might not be encountered that often. However, the situation changes, when it comes to styles (or CSS)
In case of inline styles, following are the scenarios:
<!-- scenario 1 -->
<style>p{color: blue;}</style>
and
<!-- scenario 2 -->
<p style="color: blue;">This is a text</p>
In CSS, the second scenario is much more common when someone does inline styles than scenario 1. But again, in this case, adding a sha256 hash to style-src
won't execute the scenario 2 in chromium browsers.
This is because styles added in scenario 2 are part of the style attribute in the HTML tag which in CSP terms are essentially event handlers. According to w3c CSP draft, the hash in style-src
allows the inline styles mentioned inside <style>
tag to pass but doesn't allow event handlers (as is the case in scenario 2). There's more on this discussion here.
So it's a feature?
Yes, it is a feature. In chromium browsers, adding a hash to style-src
only allows any inline style written inside the <style>
tags to execute. This is by design. If you need to execute the inline styles present in style=
attribute of HTML tags, you need to use another directive in CSP called style-src-attr
. Similarly, script-src-attr
should be used if you are doing JavaScript event handling in the HTML tag itself.
So, for example, if you want to only allow an inline CSS such as this:
<p style="color: blue;">This is a text</p>
all you need to do is put the sha256 hash in style-src-attr
along with 'unsafe-hashes'
. This will tell the browser to allow any inline style, with the hashes that you added in style-src-attr
to be executed.
So the CSP will have something like this:
style-src-attr 'unsafe-hashes' 'sha256-C8uD/9cXZAvqgnwxgdb67jgkSDq7f8xjP8F6lhY1Gtk='
And, that's it! That will do the trick in any chromium browser. The related code for chromium can be found here. According to caniuse.com, all chromium browsers above 75 supports this behaviour.
Even though firefox still doesn't have support for style-src-attr
but it allows inline styles and scripts of all types to pass based on style-src
and script-src
hashes. So as long as the hash is mentioned in both style-src
and style-src-attr
, it should work in most of the browsers.
As for the explanation behind why 'unsafe-hashes'
, there is a pretty good explainer document written by andypaicu talking about exactly this.
Also, read more about style-src-attr
in detail in the w3c draft to understand exactly what's happening and what kind of risk it may still pose.
PS: Inline JavaScript event handlers using script-src-attr
can be very risky given an attacker can trigger a passing javascript from within an unrelated HTML tag.
What's the preferred unit in CSS for responsive design?
Posted: 2018-04-04T17:16:00+05:30Sadly, the answer isn't as simple as that. In fact, there is no proper answer to that question and depends a lot on the design decisions taken rather than a fixed rule of making websites responsive. Funny thing is, many times you might actually want to use px instead of % because the later is going to mess things up. In this blog, I will try to describe some scenario's when each of the units work better in a responsive environment.
PS: All of this is mostly my personal opinion and working experience. Not to be mistaken as a rule book.
Where to use %?
Where to use px?
Where to use em?
Where to use rem?
Where to use vh or vw?
Where to use media queries?
It works in Firefox, but not in Tor Browser
Posted: 2018-01-25T12:11:00+05:30What is tor and tor browser?
Tor browser and Firefox
If you’ve used Tor, you’ve probably used Tor Browser, and if you’ve used Tor Browser you’ve used Firefox. By lines of code, Tor Browser is mostly Firefox -- there are some modifications and some additions, but around 95% of the code in Tor Browser comes from Firefox.So, basically, Tor Browser is built on top of firefox after applying some Privacy and Security patches. But this also means, to update Tor Browser, everytime a new firefox version comes means update the Privacy and Security patch codes to make them compatible with the new version of the browser. The latest version of Tor Browser is thus often not built on top of the latest version of Firefox. So how do you know if a feature is compatible with tor or not?
Will it work in Tor browser?
- Start your tor browser. Open About section and there you can find the version of Firefox which is being used.
- Alternatively, You can check the release notes for Tor browser to know about the Firefox version. So right now according to the release blog of the latest Tor browser till date, it is built on top of Firefox 52.5.0
- Go to website https://caniuse.com/
- Search for the feature you are wanting to use.
- Then, click on show all to get the compatibility over all the versions of the common browser.
- Now, to understand whether a feature is compatible, check for the Firefox version on top of which the Tor Browser is built, latest being 52.5
- So, I, for example, checked Firefox 52 for the compatibility of CSS Masking properties, which reveals that before Firefox 53, there was only partial support for CSS Masking.
CSS Masking: Mask of Batman
Posted: 2018-01-04T13:23:00+05:30So this is the final prototype I made using just CSS without any Javascript.
The main CSS property that is used in the above example is mask-image and associated CSS Masking properties. What masking does is hiding parts of the visual section of the webpage by the mask layer. there are two ways of masking - CSS or SVG. So you can either use a CSS gradient or luminance to create a mask, or use an SVG image. In our example, we are going to take about how to use SVG.
<div class="content">
<p>Hover</p>
</div>
<div class="wipe">
<div class="content black">
<p>I am Batman!</p>
</div>
</div>
So, in the HTML code we basically have 2 layers. To create that, I made a <div class="content"> with the actual content inside a <div class="wipe">. So the text of the class "content" must remain hidden until the wipe class reveals the content.
Now it's time to implement the CSS code to make this thing happen.
.wipe {
mask-image: url(https://vignette.wikia.nocookie.net/logopedia/images/3/3c/Batman_symbol_%282008-2011%29.svg);
mask-repeat: no-repeat;
mask-position: 50% 50%;
mask-size: 0;
}
The above CSS code applies the mask over the content class so that only a part of the content is visible. Here we use mask-image which is a link to the SVG image which we want to use as our mask. Since it's a Bat Swipe, I have used the logo of Batman. You can use pretty much use any SVG image but I would suggest that you use a filled SVG image rather than line art. This is because the SVG masking uses the alpha factor of the image. Say in our case, since the Batman logo is a filled black image on top of a white background, so when we apply it as a mask, the visual area behind the black part of the image is visible, and the area behind white part gets masked or hidden.
The CSS properties mask-repeat and mask-position are used to ensure that there is only one mask no matter whatever the size of the mask and it stays always in the middle. You can modify these parameters based on your use case. Say, you wanted a polka dot mask style, you would want then want to have a black disk mask-image and mask-repeat as "repeat".
The CSS property mask-size is most important in our case to create the effect of swipe or reveal. By now, most of you must have already guessed that to get the effect, what we essentially need to do is increase the size of the image with time. I have done the entire animation of swiping on hover because it is the easiest way to display a transition with only CSS.
So at the beginning, we keep the mask-size as 0 and then we add a pseudo hover property to increase the mask-size to 500% (enough to cover the entire page over most resolutions) with a transition.
.wipe:hover {
mask-size: 500%;
transition: 3s;
}
We apply a transition over 3s using the CSS transition property. So, if you would like a really slow animation instead of a swiping action you can just increase the value of transition property so that the transition of size happens over a longer duration of time.
The only last thing remaining is cross-browser compatibility. So will this code work in all browsers? Sadly, no. As of now, the mask-image and associated CSS properties are fully supported only in Firefox since version 53. However, you can make it work in Google Chrome, Opera and Safari using the prefix "-webkit-". So if you add -webkit-mask-image property as well, then it starts working in chrome and safari as well. Sadly, IE, Edge and Opera Mini doesn't provide any kind of support.