If you are starting out on software development, you might be wondering what type of security concerns you should be aware of before releasing or publishing a project.
In this post I’ll address some of the most important ones, if you are a security expert or a long time software engineer then this post is probably not for you. Although if you are curious you have the index ahead where I state what will be covered here.
If you implement these principles it doesn’t mean your website or platform will be completely impenetrable but you will know you have a lot of protective measures that will prevent the most common attacks and keep your users pretty safe.
Of course the type of security you need depends on the application you are building, what type of data you deal with, for instance if you are dealing with financial data security is a much bigger concern than if you are developing a website for a local store. Nevertheless your users should be safe and protected when using your website or platform.
- Encrypt passwords on database
- SQL Injection
- Error handling
- Authentication and Authorization
- Cross-Site Scripting (XSS) and CSRF
- Resource consumption
Encrypt passwords on database
This is an issue that gets overlooked a lot, it is a crucial part. If an attacker is able to break into your database he must not be able to steal your users’ passwords, this is a big risk. Even if you think your application is small and its security is not that important, this is one issue you must not overlook. It’s important because a lot of people use the same email and password for a lot of services so if an attacker gets your users’ passwords he might get access to your users’ personal emails, or worse. So you should really encrypt passwords in the database. If you are using a framework like Django this is already taken care of for you, there is no action necessary but if you are building a server using something like Spring Boot and you are using JDBC with an external database then you need to encrypt it. The defacto standard encryption algorithm for passwords at the time is Bcrypt, although you could also use PBKDF2 (Django’s default) or scrypt.
Bcrypt is available for most every framework or language, npm, python, Django and Spring Boot. If you use another one you can probably find it online as well. You need to encrypt when you store the password in the database on account creation and do the same encryption for login or other matching operations, unless you use homomorphic encryption which I won’t get into here. Using it is usually as simple as:
This is one of the top risks you might encounter. SQL injection is what happens when a user is able to run queries on your database that he should not be able to. How can this happen? This vulnerability happens when your inputs are concatenated like this:
So in this query a user could input the username as
hello'; DROP TABLE Users; -- and so the resulting query would be
SELECT * FROM Users WHERE username = 'hello'; DROP TABLE Users; --' and all users would be deleted, or, if your passwords were not encrypted a user could instead query the table for all users' emails and passwords and get them.
So how to fix this?
This is an easy problem to fix, you simply have to use safe(named) parameters, which you could do like this:
So always used parameterized statements! They will prevent many attacks! If you only protect your application against one vulnerability this is probably the one!
If a users tries to do something illegal or that generates an error it’s important to decide what to show to the users, simply showing the error the database gives is a big security risk as you could be revealing information you shouldn’t. Let’s say an user was trying to login and inserts a correct username but a wrong password, it’s important that you do not tell the user the username was correct but the password failed, you should just say something like ‘username and password did not match’, as you have probably noticed most services you use do.
SQL could return a statement like this:
This gives an attacker information on the structure and content of your database that you should not make public.
Handling errors can be done using a
try/catch. In case of an error the catch clause will be triggered and you can define different outputs for different type of exceptions, or, for different type of errors in the same exception.
Authentication and Authorization
First it’s important to differentiate authentication from authorizations as these get mixed up too often. Authentication is to confirm that someone actually is who he claims to be, authorization is the permission users have to access resources.
You might want to allow anonymous/non-authenticated users, you can see my previous post for that.
Managing authenticated users first requires that you make sure only the user has access to his data, so no other user can temper with other users’ data. This means that every query to the database must be written so that only the user that owns the data can read and change this data or some other application-level verifications to prevent users tampering with other users’ data.
Besides this you can also define roles such as Admin, Editor,View, Children/Parent or others and, depending on the users’ roles you might allow, or not, certain access and actions to those users.
You can implement this all by hand or leverage what most frameworks have as built-in. In Spring you can do something like this:
As for authentication you should have email verification and use HTTPS if you are using the HTTP protocol or encrypt the users’ details if you are using another protocol.
Cross-Site Scripting (XSS)
For instance, let’s say a user is logged into the his bank account at the time of the script execution. The script could send cookie information of the bank’s login to the attacker, who could then use this information to access the victims’ bank account. Or the script could actually access pages on the bank’s web site, with the correct information and perform a money transfer. This could in fact actually be done without scripting using a ingle line of code such as
This kind of latter vulnerability is called Cross-site request forgery (CSRF).
To prevent against such attacks you should do the following:
- Prevent your site from launching XSS or CSRF attacks
- Prevent your site from getting attacked with XSS or CSRF from other sites
- You should verify the origin URL from which the request was made and only allow from your site
- NEVER use a GET request to perform an update, this is a really bad practice and will make your server very vulnerable
- If you use a framework like Django, you can use the XSS/CSRF protection mechanisms they have
Every time you see this lock in your browser it means HTTPS.
Hypertext Transfer Protocol Secure (HTTPS) is an extension of the Hypertext Transfer Protocol (HTTP). It is used for secure communication over a computer network, and is widely used on the Internet. In HTTPS, the communication protocol is encrypted using Transport Layer Security (TLS) or, formerly, Secure Sockets Layer (SSL). The protocol is therefore also referred to as HTTP over TLS, or HTTP over SSL. The principal motivations for HTTPS are authentication of the accessed website, and protection of the privacy and integrity of the exchanged data while in transit. It protects against man-in-the-middle attacks, and the bidirectional encryption of communications between a client and server protects the communications against eavesdropping and tampering. In practice, this provides a reasonable assurance that one is communicating with the intended website without interference from attackers. — Wikipedia
So HTTPS provides encryption on the HTTP messages, this is something really important for when users create an account or login and you send passwords to the server from your site. By using HTTPS you don’t need to encrypt the users’ details before sending it to the server, you can just send them as-is.
If your server performs some complex operations over user input you could be exposing yourself to a Denial-of-Service (DoS) attack. If you allow your server to run indefinitely to perform a single request, an attacker could just send a couple of request and really clog your server. To prevent this you should have a maximum time allowed per request, where you would give a request timeout error if it was not possible to perform the request in the maximum time allowed.
Originally published at https://joao-maria-janeiro.github.io on January 7, 2021.