Securing Cascade Style Sheets (CSS) Cheat Sheet
Last revision (mm/dd/yy): 11/24/2018
The goal of this “CSS (Not XSS, but Cascade Style Sheet) Cheat Sheet is intended for Programmers, Testers, Security Analysts, Front-End Developers and anyone who is interested in Web Application Security to use these recommendations or requirements in order to achieve better security from “Cascade Style Sheet” perspective.
You may be confused and wondering, “How is Cascade Style Sheet going to impact on Application Security? Your situation is completely fair enough if you are confused to understand this and that is why this Cheat Sheet will help you to understand and also mitigate risks associated with Cascade Style Sheet that you use in your Web Application.
Let’s demonstrate this risk with an example, Santhosh is a programmer who works for a company called “X” and writes Cascade Style Sheet to implement styling of the web application. The application for which he is writing CSS Code has various roles like “Student”, “Teacher”, “Super User” & “Administrator” and these roles have different permissions (PBAC - Permission Based Access Control) and Roles (RBAC - Role Based Access Control).Not only these roles have different access controls, but also styling of the webpages for every role is totally different.
Santhosh thinks that it would a great optimised idea to create a “global styling” css file which has all the CSS styling/selectors for all the roles. Note that, there is only login webpage through which all the roles can login and they will be authenticated based on their access control list or roles. According to their role, the specific features of a particular role will be loaded on to the pages. For instance, Administrator will have different features compared to “Student” or “Teacher” or “SuperUser”. However, some permissions or features maybe common to some roles. For example: Profile Settings will be applicable to all the users here while “Adding Users” or “Deleting Users” is only applicable for “Administrator”.
Example: .login .profileStudent .changePassword .addUsers .deleteUsers .addNewAdmin .deleteAdmin .exportUserData .exportProfileData ... ... Now, let’s examine what are the risks associated with this style of coding.
Motivated Attackers always take a look at *.CSS files to learn the features of the application even without being logged in.
For instance: Jim is a motivated attacker and always tries to look into CSS files from the View-Source even before thinking of attacking the web application to compromise the accounts and gain unauthorized access. When Jim looks into the CSS file, he sees that there are different features and different roles based on the CSS selectors like .profileSettings, .editUser, .addUser, .deleteUser and so on. Jim does this intel gathering and this process of OSINT (Open Source Intelligence) motivates him to go further and attack the web application to gain access to sensitive roles. In an attacker’s perspective, it is him doing due diligence even before trying to perform dangerous attacks to gain access to the web application. Once an attacker knows what’s inside the house, he is fully sure that he would get that treasure once he exploits any vulnerability to reach that access.
In a nutshell, having a global styling motivates malicious hackers / attackers to proceed further. Had Santhosh not created this kind of global styling, probably Jim would have not been motivated as much as he was motivated looking into global styling and learning about attack areas of the application.
Let’s say, Santhosh has this habit of writing the descriptive selector names like .profileSettings, exportUserData, .changePassword, .oldPassword, .newPassword, .confirmNewPassword etcetera. He loves to keep his code readable and usable by other Code Reviewers in his team. Of course, code Readability is one of the good practice; but when you are thinking of “Security”, let’s not think about “Usability” because when I am setting up front-door for my home, I am thinking about my safety from thieves and this door has to be really be secure enough and I don’t think about usability by saying, “Ah, I don’t want to get this door because it wastes my time in terms of closing and opening while I also need to lock it using a key”.
Going back to Santhosh’s context, the risk is hackers or attackers can always get great hint from these descriptive selector names which match with the features of the web application.
Defensive Mechanisms to Mitigate Attacker’s Motivation
Defense Mechanism #1
As a CSS Coder / Programmer, always keep the CSS isolated. By this, it means “Student” will have a different CSS file called as “StudentStyling.CSS” while “Administrator” has “AdministratorStyling.CSS” and so on.
Once you do this, make sure these *.CSS files are accessed only for an authenticated user while you keep the public pages like login (login.CSS) same for everyone.
And also, only users with a specific role should be able to access only their *.CSS file and other *.CSS file should not be loaded and also should have authorisation to access it.
For instance, if the role is student we need to have a logic similar to following. Scenario #1
if Role(student): load(Student.CSS) else: print(“Please login using your credentials”)
Scenario #2 If Student Role (authenticated user) tries to access AdministratorStyling.CSS forcefully through the URL by replacing StudentStyling.CSS with AdministratorStyling.CSS, the permission should not be granted and the request should be forbidden because the Student Role doesn’t have access to any other *.CSS file except “StudentStyling.CSS”.
if Role(student) load(AdministratorStyling.CSS) else: print(“Sorry, you are not authorized to access this file”)
Defense Mechanism #2
Being a programmer or a tester, take care of the naming conventions of your CSS (Cascade Style Sheet) Selectors. Obfuscate the selector names in such a fashion that hackers don’t get a hint of what a specific selector is linking to. Of course, your customers or users who have access to their roles can always use “Web Developer Tools” to perform reverse-engineering in order to know the features using those selectors as they are authorised to use your application. However, they are not under Threat Actor category based on the context.
Example: CSS Selectors for addUser, addAdmin, profileSettings, changePassword can be something like aHj879JK, bHjsU, ahkrrE, lOiksn respectively. This is just an example and you can use your own custom obfuscation, but watch out for “Rogue Insiders” who leave the company or who share the information about this specific obfuscation that you use in your code. Also, there have to be guidelines in terms of who should do this obfuscation activity and what happens when they leave the company? Of course, someone in the company need to change this obfuscation because someone out there in the web world knows what keys are you using?
Note that the usage of online obfuscators or some tools maybe deobfuscated very quickly and attacker can use the online de-obfuscators if you are using prefabricated tools.
Defense Mechanism #3
If your web application sends some styling via JSON request in specific features for various reasons, then make sure that the properties and values are not tampered with and also reject anything that appears to be suspicious or anything that is out of your whitelist. This attack may work even when you have escaped characters, or done input encoding and output encoding.
Example: Someone may just tamper with the request body of a specific feature and edit the styling to create an attack where height or width can be changed to make it look like fullpage & also every part of the webpage is clickable which will redirect the users to malicious websites which will inturn have multitude of attacks. You can read about how LinkedIn had a vulnerability through Cascade Style Sheet which was fixed once reported. You can read the article provided in the “References” section.
Authors and Primary Editors
Santhosh Tuppad -santhosh[at][email protected]