Improve your web application security
Improve your web application security
If you want your web application to be bullet proof with no vulnerabilities at all, do not write it.
There is no software that cannot be hacked, it is just a matter of resources and time, as proved many times.
But there are few basic steps that will improve your web application security to a level that attacking it will be much harder and maybe not worthwhile for the attacker.
Even if you think that your application is not under the radar and no one will be interesting in attacking it, know this: there are tools that scan the web and search for websites with known vulnerabilities. If your web application will not defend itself from those common vulnerabilities, it will likely be attacked.
In this blog post I will specify common vulnerabilities, and the way you can defend yourself by using simple methods and technologies (with Rails).
CSRF - Cross-site request forgery
In this attack, the attacker executes commands on the application from a different place while relying on the fact that the user is logged-in to the application.
For example, if you are logged-in to your bank website, and it let you transfer money to different account by sending a post request with the parameters on the amount and the other account number. After logging to the application, the attacker fooled you to open his site and then sending the post request from his page. Because the user is logged in, the request is accepted and the money is transferred.
What to do:
The common way to handle this is by adding a security token to any request. The security token will be included on the real page of the application, and will be send in the request header. If the request header does not contain the right token, the server will reject the request.
In Rails, this is done by the framework, the only thing that need to be done is adding this line to the application_controller.rb:
protect_from_forgery with: :exception
Notice that if the script is running from the page itself (like XSS) it will be able to know the token and use it.
Another important thing is to make an expiration time to this token so it will not be valid after a certain amount of time, so if it is stolen, it will be useless.
XSS - Cross-Site Scripting
Maybe the most popular and harmful attack. It is very hard to defend from it, and sometimes even impossible.
XSS attack is when the attacker makes his code run inside your web application. The attacker has many option to do that. The most common one is when the input of the user is displayed in the output of the application.
For example, message in a forum, user name in the web page etc.
When the attacker is able to run a script, he can achieve a lot, steal cookies, hijack the session, use the user credentials to make actions in the application and almost anything. Especially if the developer counts only on the security of the client.
Because, the attack is within the session, many defenses such as CSRF are useless.
There two types of XSS:
- Reflected (non-persistent): using the user input that is displayed back on the screen (like a search phrase) to run the script. E.g. insert the name:
- Persistent - the user input is saved in the database and then displayed (the script runs) to the user (or even other users) every time the user load the page.
It is very important to know that XSS can happen on the page inputs, but also in the tunnel (man in the middle attacks), so it is not enough to handle the inputs.
What to do? The first thing is to escape every input of the user. Escaping, is removing or replacing any input that contains a script characters like ‘<’.
Many frameworks has escaping mechanisms, and sometimes it is even built in so the developer does not need to worry about it, but it is very important to verify it, and read about the framework vulnerabilities before going to production.
Moreover, sometimes we prefer using other technologies instead of what the framework provides us (for various reasons), it is crucial to escape the inputs of those cases because no one is watching our backs.
The other side of this equation is to verify the outputs and escape them as well.
The second part of it is in the server.
Do not, ever, base your defences on the client. Use all that you can to add protection in the server:
- check the user inputs.
- Verify his identity
- Verify that the action is reasonable for this user.
Do not trust the users. One vicious user is enough to cause a huge damage.
Sometimes the attacker can break our defences and get our users table. Storing the password encrypted will prevent him to access the accounts of the users. There are many tools and methods to do so, Devise is very recommended.
Moreover, sometimes the attacker takes control of the users session, and can change their passwords. A very easy way to prevent it is by asking the current password before changing it.
Another thing is to use technologies like 2FA (two factor authentication), use SMS or mail to verify the identity of the user.
SQL injection was a very popular in the past, but it has changed because every experienced developer knows how to prevent it.
The way SQL injection works, is when the attacker inject an SQL phrase into his input, and then penetrates to the application or collect data from it.
For example, adding to the password the phrase ‘or 1 = 1’, this will make a user authentication query be:
select user from users where user_name = ‘john’ and password = ‘password1’ or 1 =1
The best way to avoid it is to escape SQL in the user inputs, and make where queries with parameters rather than integrate them in the query:
User.where(‘user_name = ? and password = ?’, ‘john, ‘password1).first
A lot of web applications asks for the user’s login name and password, and then store it (usually in a cookie). Then they use it in the session in order to identify the user for everything he does.
The problem is if the attacker seizes the cookie, he can hijack the session and use it, because he has all the user’s permissions.
The way to prevent it is using SSL, this will make it very hard for the attacker to get the cookie.
config.force_ssl = true
The next thing is to encrypt the the cookie so that even if the attacker gets the cookie he cannot use it.
The encryption in rails uses the key from config/secrets.yml file.
Defending web application is hard. But we cannot underestimate the risk to our application or our customers if we ignore it. In order to get complete or almost complete defence we need to put a lot of resources and even then we cannot be sure that we are 100% safe. We need to define the level of protection that will match the data we are trying to defend.
The good news are that with a very simple steps and by using frameworks like Rails we can improve the level of security that it will be very hard to be attacked.
Security issues should be handled through all the development lifecycle in order to improve it, from the design, through the implementation, the code review and the testing.
Remember, it takes one malicious user to destroy a good reputation.