5 deadly security sins of a Java developer

Every Java application is exposed to a dangerous world, where some people want to break it. Some of them will do it just for fun, others to steal (money or user data, or anything else), others just to gain free access to features that are supposed to cost money. The reasons may be numerous, and you should never think that you are not going to become their victim until you have 100 million customers and millions in revenue. Even if you’ve just opened an internet store, you’re likely to be vulnerable to such threats. Do you think, your users will love you when their personal data and email addresses will be sold to a spam lists? I doubt so.

So, one should keep security in mind from the very beginning when designing even a small Java app. Of course, most of the below principles and typical design mistakes are applicable to any app, not only Java.

These are the most common sins of Java developers, and hackers will always start with exploring them.

1. Input validation

This is the most common mistake when the developer is not validating user input. Remember: any input, including user input, API calls, external databases, 3rd-party products must always be validated on server-side!

You think that AngularJS or some other fancy web framework you are using is already doing this for you? But it’s super easy to record the traffic between the Web page and the server, and then replace any symbols in Ajax calls to whatever the hacker wants. You don’t even need to know how to write code for that, every modern browser has this standard functionality in dev mode. So, input validation in the GUI is for user-friendliness, input validation on server-side is for security.

It is also very important how exactly the validation is performed. First of all, check character encoding. If you expect it to be UFT-8 – then just drop all other symbols. If there is specific character set that is supposed to be present – always check that there are only expected symbols. Never just check for escapes characters and special symbols (for example, % is the most commonly used for SQL injection). Instead, validate against allowed character set. For example, if you expect alphanumeric symbols – strictly check the input using regex \p{Alnum}.

Always check input length and data range for dates and numbers.

If the request fails the input validation – reject it completely.

2. Authentication

Remember: authentication must always be handled by the server. If you have authentication on client side – you don’t have it at all.

There are endless articles on password length, strength and cryptographic security of storing password hashes, so we’ll skip this part.

What is important is: are you sure you want to handle it yourself? There are several providers and 99,99% of the users already have accounts with some of them, for example, Google and Facebook. Integrating with their authentication is easier than it looks, and it significantly improves conversion ration for new users.

Another common topic worth mentioning is two-factor authentication. It is not always required to do this via SMS (which definitely would be an overkill for a new application with handful of users), but services like Google Authenticator make it easier to adopt even for new players.

3. Cross-site scripting

Cross-site scripting (also known as XSS) is one of the most common attacks when a malicious script is injected in a trusted web application. For example, if a user visited malicious web site in the same browser as the trusted site, harmful JavaScript code may be sent to the server and the server may return it back to the browser. In this case, the browser will execute that script, because it looks like a normal legitimate JavaScript, and that script may do anything, from stealing session data to replacing any part of the trusted web page with malicious content. For example, such script may display authentication window and then send user name and password to malicious web site.

To protect your application against this type of attack, the following techniques should be used.

Never display user input back to the user before it was validated and properly escaped. It also means, if you are rejecting user input due to validation error, never display what the user entered, just display general error message like “Date validation failed”, but never display the date that didn’t pass the validation.

Always validate and escape user input before storing it in the database. We recommend using some standard escape library, for example, from ‪owasp.org.

Always set X-FRAME-OPTIONS=deny in HTTP header for all requests. This will not only help prevent this attack, but also clickjacking type of attack. Clickjacking means that a malicious site will include your site in an iframe, and in this case it may intercept mouse clicks.

4. Session hijacking

This scenario is a bit complicated, but is also often used. Imagine that a user has a session established with your site, and simultaneously she has malicious site open in another browser tab. That malicious site may host a JavaScript that will sent a POST or GET request to your site, with some dangerous action, for example, payment or password change. The browser will automatically include existing session cookie into the request, because the user has already authenticated in another tab. In this case, the requested action will be performed with full user permissions, like if the user actually did it herself.

In order to prevent this type of attack, the following technique may be used. When the HTML page first tries to log user in, it will generate random string, which is called XSRF token, and send it to the server, together with the login request. The server will create a session and associate it with XSRF token. HTML page will then send it with every subsequent request to the server, and the server will always check that this is the same token that was stored with the session id. This XSRF token is not accessible through other browser tabs, and thus session highjacking attack will be prevented.

5. Mind your header.

This is the last and the most simple step. By default, server will send the exact engine version in the header. For example, Server: Apache-Coyote/1.1. So, the hacker will already know which HTTP or application server you are using, and will start attacking known vulnerabilities. It’s a good idea to send fake information in this field. Not that the bad guys will not be able to find it out on their own, but why make their life easier, right?

Next goes the name of the cookie that is used for session management. By default, it’s JSESSIONID in many servers. It takes only a few seconds to change it to something unique for you. For example, for Weblogic, edit your application’s webogic.xml and add <cookie-name>YOURSUPERCOOKIE</cookie-name> to <session-descriptor>. It also makes sense to add <cookie-secure>true</cookie-secure> if it’s not already there.

Overall, remember, there is no absolute protection. Every application may be broken into, and every information may be stolen. But the more difficult it is to break into your system (and hence more expensive) – the more expensive and sensitive information you must keep there in order to justify the cost. So, even few simple steps that require probably 10 additional minutes each of the hacker’s time may make breaking into your system absolutely worthless for the bad guys.

Leave a Reply

Your email address will not be published. Required fields are marked *