Security is a difficult topic, experts spend their careers learning and researching, and new threats are constantly arising. As new technology comes out, so do new threats.
As developers, we may not always be able to do make our applications impervious to attacks, but it’s our responsibility to ensure we at least take some basic steps to ensure the security of our applications and the data it holds or transmits, especially when it comes to private user data like passwords.
When it comes to Ionic applications, and more generally Cordova applications, there are a few key things that I feel are important to know and understand when building applications with potential security concerns.
Terminology
I’ll be referring to a few different security terms in this article, so I wanted to elaborate on what some of those are upfront first. This is only intended to highlight the basic idea behind these concepts.
SSL, HTTP, & HTTPS
Most developers will be familiar with these terms, but not everybody will understand what is going on behind the scenes. Web traffic is sent primarily over HTTP (Hyper Text Transfer Protocol) or HTTPS (Hyper Text Transfer Protocol Secure/over SSL). SSL is an acronym for Secure Sockets Layer and it can be used to communicate data securely. Traffic that is sent over HTTP can be intercepted, read, and altered by attackers. Traffic that is sent over HTTPS can not be read (they will only be able to see encrypted data) or altered by attackers.
Encryption vs Hashing
Both encryption and hashing involve modifying data in a way that it would not be decipherable to an attacker. The big and important difference between encryption and hashing is that encryption is two-way, hashing is one-way.
If you encrypt some value, you can also decrypt it later to retrieve the original value (e.g. sending and receiving data over HTTPS). Theoretically, there is no way to retrieve the original value after hashing a value, but that depends on how good the hashing algorithm is.
You should never encrypt a user’s password, you should only ever hash it. Since encryption is two-way, that means that you could unencrypt the user’s password if you want to, and if you can then so can an attacker. A hash allows you to check if a user’s password matches (you just need to hash the password they attempted to log in with and see if it matches the stored hashed password), so there is never a reason to encrypt a password for authentication purposes.
1. Treat the codebase like a public website
It’s easy to forget, but an Ionic application and any other Cordova application is a website. It includes an index.html file that includes HTML, CSS, and JavaScript code. In security terms, there isn’t much difference between a normal website running on the web, and a Cordova application running on a device.
I find one of the most important things to remember when building Ionic applications is to consider: would this be safe to do on a website? Would you hard code secret API keys or passwords into the JavaScript for a website? Definitely not, so you shouldn’t do it in an Ionic application either.
You might reasonably assume your applications source code is safe from prying eyes because it is packaged up into a native package for the app stores, but attackers can quite easily view the source code for your application, just like anybody can go and view the front end code for the Facebook website or any other website.
2. Move sensitive operations to a server
In the last point, we established that an Ionic application should be treated like a website that anybody can view the source code of. So, what do we do if we want to include sensitive code?
Just like you would for a website, you can outsource any sensitive operations to the server (where people, as long as your server is secure, can’t see what you’re doing). Your application can then make an HTTPS request to your server via some API to retrieve the result of that operation.
3. Communicate over HTTPS
We established what the difference between HTTP and HTTPS is in the introduction, so it should be pretty clear why you would want your application to communicate over HTTPS. Really, you should probably just always communicate with your server via HTTPS, but especially when you are logging in a user or attempting to send any kind of sensitive data.
4. Don’t store sensitive data in local storage
Just as you should assume that anybody can view the source code of your application, you should also make the assumption that anybody may gain access to whatever is stored in local storage (both on their own device, and on other users devices). If you want to store some setting in local storage, or maybe you want to cache some public posts in local storage, that’s fine, but don’t store anything sensitive in there. Whilst it might be fine to store a public post in local storage, if you were to store private messages then you will be making those messages vulnerable to attack.
Gaining access to values in local storage would first require the attacker to have physical access to the device, or to exploit some other vulnerability (e.g. through XSS), so it is not as if local storage values are publicly available for everybody to snoop around, but there are some concerns here if the security of the data stored is important.
One thing I want to specifically mention because I see it mentioned quite a bit is to never store a user’s password in your application, even if you encrypt it. As I mentioned before, a user’s password should only ever be stored as a hash on the server where you need to perform authentication. I often see people attempt to store a user’s password (sometimes encrypted, sometimes not) in local storage so that they can automatically log a user back in later. This absolutely should NOT be done.
Instead, you can use some kind of token like a JWT that you can store in local storage to authorise the user. A JWT does not contain any sensitive information, it just identifies the user, but a JWT can not be tampered with (if it has been, the server will reject it) so if a user has a JWT that identifies them as a particular user, we can automatically log them in. However, if someone manages to steal somebody else’s JWT from local storage and use it for themselves, they could technically log in as that user – so make sure to consider that when implementing your authorisation process.
5. Consider using an authentication service
As perhaps the point above may have indicated, authentication is hard. Not only from the perspective that it is a lot of work (user registration, login, password resets, emails), but there is a lot that can go wrong from a security perspective.
There are many options out there that can handle authentication for you like the various social providers like Facebook, GitHub, or Google Plus. There are also Backend-as-a-Service (BaaS) solutions like Firebase that will handle authentication for you, or even services like Auth0 and Ionic Auth.
You can even integrate Ionic Auth with your own server, so you can rely on them for authentication but still do custom things on your own server.
6. Beef up your content security policy
The content security policy is this weird tag we add to the index.html file:
<meta
http-equiv="Content-Security-Policy"
content="font-src 'self' data:; img-src * data:; default-src gap://ready file://* *; script-src 'self' 'unsafe-inline' 'unsafe-eval' * ; style-src 'self' 'unsafe-inline' *"
/>
IMPORTANT: This CSP should only be used for development, a more strict policy should be created for production environments.
Its responsibility is deciding what content can be loaded into your application and what can be executed. The policy above is reasonably permissive and one that I typically use by default when developing an application, but it shouldn’t be used in production. It allows images to be loaded from any domain, it uses unsafe-eval
which allows for the execution of Javascript functions like eval()
which can create XSS vulnerabilities, and it allows for the inline execution of Javascript code (i.e. through an onclick
handler),
In a production environment, it would be beneficial to make this policy as strict as possible. How that will look will depend on what exactly your application does. This website is a great resources for explaining the various options in a content security policy.
Summary
I think of developers and security like business owners and the law. You don’t need to know everything about the law in order to run a business, but you should have a good enough understanding that you are able to identify potential issues and seek help where it is required.
The points I’ve discussed in this article are what I believe to be the key issues when developing Cordova based applications, but of course, it doesn’t cover nearly everything. If security is a completely new field to you, it would be worth spending some time to research the basics of web security and try to get to that point here you can at least identify potential areas of concern.