There is no shortage of web development languages and frameworks. Developers have many factors to consider when selecting which framework to use.
Security is one of those factors, especially when developing a critical application for the business. In this post, we’ll discuss how five popular frameworks tackle common security issues.
We’ll discuss how these frameworks measure up to the OWASP Top 10 2017 (PDF). OWASP has long been the standard for secure web development. Therefore, it’s a good baseline against which to measure all of those choices.
We’ll highlight what makes mitigating the Top 10 risks easy in each framework. Any difficulties in mitigating risks will also be discussed. This is not an exhaustive survey of each Top 10 risk, but a general overview of how each framework addresses common security vulnerabilities.
Finally, an overall rating will be given to each framework on how it stacks up against the Top 10.
The Five Frameworks
The five frameworks chosen are Python’s Django, Node.js, Ruby on Rails, ASP.NET Core, and Java Spring. These frameworks were chosen due to their popularity in the development community, thus making them likely candidates for greenfield web development projects.
Up first, we have Django.
Django is the web framework for choice for most Python users. Django’s website lists speed, scalability, and security as its main features.
Let’s see how true its claims about security are.
Django definitely seems to take security seriously. Let’s look at some examples of how.
SQL injection is taken care of by Django’s Queryset API. It not only abstracts away the SQL queries from the developer but automatically parameterizes queries to prevent injection.
Cross-site scripting (XSS) is another common attack that Django takes care of by default, as long as you use Django’s templates to build the user interface. Templates are not completely foolproof (which we’ll discuss in a second), but they do automatically escape most characters used in XSS attacks.
Django does a great job at user authentication and authorization. The Django authentication system provides the means for developers to manage users of the system and to define permissions for each user.
Django provides the ability to create groups of users and apply permissions to the group for easier administration. Passwords are hashed using a Password Based Key Derivation Function (PBKDF2) by default, so your passwords will be protected well. The password hashing is also configurable, allowing developers to increase the number of iterations if necessary.
Django also provides CSRF protection by default. All you have to do is add the “csrf_token” tag inside the form element of any page that performs a POST to an internal URL.
Django is a solid framework when it comes to security. However, there are a couple of minor issues.
First, even though querysets prevent SQL injection by default, functions still exist that allow developers to create raw SQL queries. The extra() function and RawSQL class can be used to create SQL queries and are susceptible to injection attacks. You can use the params argument to escape user input before using it. However, this is still a dangerous way of constructing queries in Django.
As mentioned before, the XSS protection provided by templates is not 100%. The use of safe() and mark_safe() functions can be used to tell Django that a string has been escaped and is safe to render. This naming is a bit confusing, since developers may think this function makes the string safe. If autoescaping is turned off and safe() or mark_safe() are used, it can lead to XSS vulnerabilities in your code base.
Even with some issues, these are corner cases and certainly shouldn’t come up in most applications.
A concerning issue for Django certainly is the session management of subdomains. Subdomains within a site are able to set cookies on the client for the whole domain. This could lead to session fixation attacks.
Django logging defaults can be confusing in how they work. Make sure you don’t put an application to production with DEBUG level logging. This will cause verbose error messages to be returned to the client where bad guys can use the information to assist with an attack.
Django Final Rating: 4.5/5
Django has clearly made security a focus of its implementation. Django takes care of many common security issues and developers should feel pretty good using it.
Node’s philosophy of development is different than other frameworks. Node is minimalistic, meaning it only ships with the bare minimum of what is needed to run a web server.
Most functionality for Node comes in the form of modules that are added to the system as needed. These modules are hosted on and managed by the Node Package Manager (NPM). This development model has interesting security consequences.
Node does ship with some security pieces by default. For instance, it comes with the ability to start up a web application using HTTPS to protect your data from exposure. There is also a strong crypto library so you can protect your data at rest.
A consequence of a minimalist model is dependence on a strong community of contributors to provide good security functionality.
For example, many web development frameworks made to work on Node have to handle session management and injection vulnerabilities. ExpressJS is a popular web framework for Node, but it doesn’t handle everything. You’ll need libraries like cookie-session, helmet, and mongoose to prevent several OWASP Top 10 risks, such as sensitive data exposure, broken authentication, and NoSQL injection.
On the bright side, the Node community is strong. There are many well-written modules for security functionality developers would be wise to use.
Node’s development methodology could be seen as a strength and a weakness.
With so many different developers writing modules and hosting them on NPM, there is a risk of malicious modules being introduced into your code.
For example, check out this slide from a presentation on Node security (PDF link) that illustrates this problem
Phishing attacks on developers have occurred using NPM modules given similar names by attackers. These modules look like the real thing but have malicious code inside of them.
When using Node, make sure to do your homework and use modules that have been vetted by the overall community.
Node.js Final Rating: 3/5
Node has many great features. However, its dependence on a community of developers to create key security functionality can lead to insecure code or outright attacks.
There are strong options for security with Node, but make sure you do your homework before depending on anyone else’s code.
Ruby on Rails is the web framework of choice for Ruby developers. It has a strong community and aims to make web development fast and simple.
Rails provides some solid protections out of the box. SQL injection is handled well by the default Rails object relational mapper (ORM), Active Record.
Starting with Rails version 3.0, XSS is also prevented by default. All string text is escaped before being sent to the browser.
Rails includes proper security headers by default. This protects applications from clickjacking, which is a great default to have as clickjacking can be easily overlooked.
Ruby uses “gems” to provide added functionality. A gem called Devise gives developers robust authentication functionality. Devise allows you to define which routes within your application require authentication.
Another gem, Pundit, defines resource level access control for REST resources. This prevents insecure direct object references, a component of broken access control.
Rails’ dependence on gems for some security functionality can be seen as a disadvantage. The gems I’ve mentioned are well-known and vetted by the likes of OWASP, so you don’t need to worry too much.
So the same advice applies here that applied for Node. Make sure you do your homework.
A definite security issue with the actual Rails framework is its default handling of user sessions. By default, Rails uses cookie-based sessions. The sessions won’t expire on the server, leaving your application open for replay attacks.
In order to fix this you’ll need to change the Rails configuration to use the database to store sessions. You can do this by changing the following configuration:
More information can be found here on how to properly secure Rails.
Rails Final Rating: 4/5
Rails has some flaws, but is still a solid framework when it comes to security defaults. There are several well-known gems that will give you what you need if the framework doesn’t.
ASP.NET Core is the newest kid on the block. Recently released by Microsoft, ASP.NET Core looks to bring .NET development into the future by providing a cross-platform, high-performance, open source framework for building cloud-first web applications.
ASP.NET Core Highlights
ASP.NET Core MVC uses the powerful Razor view engine to render views to the browser. The Razor view engine encodes HTML by default, thus preventing XSS attacks.
Entity Framework, the ORM or choice for .NET developers, handles SQL injection out of the box. Developers write their queries in code and the resulting SQL is parameterized by default.
Authentication and authorization are built into ASP.NET Core in the form of ASP.NET Identity. Identity provides a robust authentication system that can use a username and password with a database or external providers such as Facebook, Google, and others.
Built-in authorization libraries provide the ability to restrict access based on roles and attributes of the user. Restrictions can be made on individual pieces of data as well as controller actions. Developers can even use annotations to easily define which roles have access to which methods and actions.
An especially impressive feature of ASP.NET Core is the Data Protection API. This API gives developers an excellent abstraction for encrypting data at rest. You simply instantiate an instance of a data protection provider and ask it to protect your data. It uses AES-256 by default, and the framework handles key rotation and storage for you. It does the right thing and makes it easy.
ASP.NET Core Lowlights
Honestly, there aren’t many lowlights to offer here. ASP.NET Core has been built with security in mind from the start. It gives developers great defaults and powerful tools to help prevent the most common vulnerabilities.
One vulnerability that can trip you up in the .NET world is OWASP’s A8: Insecure Deserialization. Most JSON parsing libraries are written by third parties. Many are vulnerable to insecure JSON deserialization attacks. Check out this video for a demonstration of how to execute code using insecure deserialization in JSON libraries.
ASP.NET Core Final Rating: 4.5/5
The sensible defaults coupled with useful tools for developers makes ASP.NET Core a strong choice for your web application.
Spring is a Java framework for building applications. It offers robust tools for building web applications and is a popular choice among enterprises.
It has a couple of different flavors, such as Spring Boot for microservices and Spring MVC for more traditional web development.
Java Spring Highlights
A major highlight for Spring is Spring Security, a framework for authentication and authorization for Java Spring applications. Spring Security is highly customizable and serves as the backbone of many enterprise applications.
Spring Vault is another Spring framework that provides strong storage and management of your secrets. Secrets can include encryption keys or usernames and passwords used to access other applications or services.
XSS is taken care of by Spring’s native HtmlUtils.htmlEscape method. This method will escape strings that are returned to the UI. You have to make sure to call this method, but it is written for you by the framework and there for your use.
Java Spring Lowlights
Compared to other frameworks, Spring is very mature. Similar to ASP.NET Core, Spring has few flaws when it comes to the common security problems pointed out by the OWASP Top 10.
SQL injection is the biggest issue when it comes to Spring, since you have to parameterize queries using custom code or use a separate ORM, such as Hibernate. Hibernate protects you for the most part, but can still be vulnerable to injection by way of its HQL language.
Java Spring Final Rating: 4/5
Java Spring is a mature framework with many built-in defenses for common security issues. Some protections are not automatic, so a point will be docked. However, for Java development projects, you won’t regret using Spring as your framework.
Does the Framework Make the Difference?
You may have noticed a trend with the ratings of all of these frameworks. Go back and take a quick look…
Although there are differences, most of the ratings are very close or the same.
The truth is, most mature development frameworks have the necessary pieces to secure applications against the most common vulnerabilities. Why, then, do we see these problems often enough to warrant a position on the OWASP Top 10?
Developers can get trapped in the “frameworks will protect me” mentality. This leads to problems when developers, either by accident or on purpose, work around the default security features of frameworks. When that happens, developers will be responsible for the security features they could have taken for granted. This illustrates an important truth.
It’s not the web framework used, but the developer using it that makes the difference in security.
Developers should be properly trained on how to use the frameworks correctly. Most of the links in this article point to product documentation. The information is available.
Once developers understand what is available, practice will help developers to think about security every day. Contact us if you want hands-on security training that sticks.
Most developers and companies have a language of preference for building applications. Whatever language you use, instruct developers on how to use the tools available to them for security.
Only then will you know you’ve tackled the Top 10.