36
Websecurity through conventions and best practices by Michał Szajbe (netguru.pl)

Websecurity through conventions and best practices

Embed Size (px)

Citation preview

Websecuritythrough

conventions and best practices

by Michał Szajbe (netguru.pl)

web apps are like onions

• web server layer

• back-end storage layer

• application layer

Web application does not run on it’s own.Each web app runs in a specific environment which can be divided into few layers.A web server layer which can be Apache, ISS, Tomcat or even the whole operating system.Back-end storage layer which is the place where application data is stored, be it database, filesystem or some external storage system like Amazon’s S3.The last layer I outlined here is the application itself, so the layer that glues everything together to make it work.As I said before, I am a web developer so I will focus only on the application layer.

attack targets

according to Gartner Group’s report (2005)

There is also another reason for that. According to Gartner Group’s report that was publisher in year 2005, web application layer was a target of 75% of all attacksin the Web.One of the reasons for this is probably the relative ease with which such attacks can be made. In fact, almost all needed tools for this are available for everyone to use. For example consider Firefox browser. It has plugins for everything. You can modify contents of the site, manipulate request headers, easily analyze server responses and so on.As you see the report I mention is 4 years old now, but I don’t think the numbers changed much. In fact I believe that the share of the attacks on web app layer can be even bigger now.That’s because of constantly changing approach to application development process. Nowadays more and more applications are released as early as possible (there is release early, release often approach). They are often labeled beta or even alpha to underline their unstable conditions and the fact that not all functionalities are implemented yet. So if they aren’t, they are very ofter not secured appropriately too.

possible threats

• unauthorized access to sensitive data

• user account hijacking

• bypass of access control

• malicious content injection

No matter if we’re talking about security of applications, servers or networks, consequences of insecure systems can be pretty much the same.

web frameworks

• consistent application structure

• development with conventions in mind

• code reusability

• faster development

• large communities for open-source projects

• ...but no plug and play security

So how is software for web developed?Almost every modern applications is built with some kind of web framework, be it an open-source one or self-developed set of libraries. The main advantage of using framework is that they standardize the whole thing. They promote certain philosophy of doing things. They make the whole process faster. Other aspect is that for large open source frameworks like RoR we can use other developers’ experience and put it almost directly into our work.However even the best web framework is just a set of blocks, you need to put together. So with web security, you get tools and need to apply them yourself.

Conventionsand

best practiceswith examples from Ruby on Rails

So let’s go to the main topic. I will cover some security issues that need to be often faced, and I will give some examples on how to deal with them. The examples come from Ruby on Rails but similar techniques or approaches can be also applied in other languages and frameworks.

User passwords management

Let’s start with user passwords management, as most of the apps offers such things are registrations and signing in.

hash user passwords

*Authlogic plugin

Pretty obvious thing on the beginning. You should never store passwords of your users as plain text. Hash them instead with some hashing function like MD5, SHA1, SHA512.The example here shows how this can be easily done in Rails with use of Authlogic plugin.All you need to do is to define the database table structure for storing passwords and add one line to user model. Now every time before new password is going to be saved, it will be hashed first. The salt is a random value that is used during the hashing to make the same plain-text password produce different hashes.Authlogic also does the automatic hashing of password when we’re authenticating user. So the hashes of passwords are compared, not plain text passwords.

don’t redisplay passwords to users

Web frameworks offer many cool features. The one is that when user submits a form and the input is incorrect, the form is redisplayed to the user with values preserved from his last request so he does not need to supply all the values again. This is certainly great but no in all cases. Passwords should never be redisplayed in these situations. User will see the password as string of stars or dots, but the password will be visible as plain text is HTML source of the page. This could be either sniffed or retrieved later from browser cache.

don’t remind passwords, reset them

You should also never remind forgotten passwords to your users. Instead send them a one-time authorization token with which they can change their password. Again this is easily done with Rails and Authlogic. You only need to add one field to you database table. As the name says the token perishes right after use. In this case every time a record is updated, so after the user changes the password, the token will be no longer valid.

encourage strong passwords

You should probably also encourage your users to use not-weak passwords. Rails and most other web dev framework have some set of default validation rules defined that will help you ensure that the password meets certain conditions. You should define minimal requirements for passwords but you shouldn’t limit your users.I have seen some sites that allowed only use of letters and digits in passwords. I have no idea why, because if user wants to use some special characters, why not let him do so? This would make his password stronger.

Session management

Since we have users, we need to handle their sessions.

store session data on server

...or at least verify cookie session integrity

You should store session data on the server instead of the cookie. Cookie should only carry the session id. The rest should be stored server-side.By storing all data in the cookie you not only let the client manipulate it but also make the requests slower, because cookies are sent with every request to the server.If you however decide that you still want to use cookie store at least try to verify session data integrity. Calculate digest of from a session data with use of secret value stored on the server and place that digest in the cookie.

regenerate session id on authentication

Another thing is that you should always reset session id when user successfully signs in.This prevents from session fixation attacks.Session fixation attacks work like this. Attacker navigates to the site to obtain a cookie. Then he forces another use to use that cookie while signing in to our site. After the user signs in, attacker has authorized cookie and can act on behalf of the other user.So you should always assign a new id to the session when users logs in.As you can see this is another one-liner in Rails. You just need to call reset_session method.

expire sessions

...and/or encourage users to log out manually

You should also make sure that you don’t keep old and unused sessions too long. Expire old sessions. Again one line of configuration in Rails. You should also make the log out link visible so that users can destroy their own session.

Data validation

Keeping application data integral is a critical thing.You need to make sure that your app behaves in the way it’s supposed to, so do not let any wrong input in.

use server-side validation

Client-side validation is nice for user experience. It also helps to improve performance a little, because when user tries to send a form that we know that does not pass our validation checks, we show him errors immediately without sending anything to the server.However we still have to validate data again on the server, because such javascript validation is easy to go round.Rails and other frameworks have some default validation mechanism that help to check some basic conditions and display appropriate error messages when needed. You can also easily define you own validation check, so the validation can be done really quickly and with little effort.

protect sensitive data from being overwritten

Beside validation we still need to protect critical attributes from being overwritten.Check the last snippet first. This is a usual method of updating records in many frameworks. We pass a set of attributes’ values to the model and the record is updated.This has some security flaws however. User can set some attributed we don’t want for him to change, even if the corresponding fields are not present in html form on the edit page.For example he could set an admin flag to 1 and become an admin.There are two approaches to defend from this. In whitelist approach you tell explicitely which fields can be updated via mass-assignment, and the blacklist approach in which you tell which fields can’t be updated via mass-assignment.

don’t correct invalid input

In most cases you should only check whether your data pass your validations rule or not. You shouldn’t try to correct data that doesn’t. For example if you don’t want script tags, you should deny data that contains them, you shouldn’t try to remove them.As you can see on the example you’d have been tricked if you did so.

escape user input

When you do any queries to the database you should always make sure that you escape all values for parameters that come from outside of the app (for example from user).As you can see on examples above user can manipulate params in a way that somthing more will be executed along with the normal database query.In the first example user makes himself an admin, in the second he signs in as ad admin with no password.Rails offers some standard some mechanisms that act like proxies to database queries. You can see how the same queries are done in Rails, then the values will be automatically escaped and no unwanted queries will be executed.

escape application output

Escaping user input is important, but it is also important that we escape the app output.In some situations we want to allow users to save everything they want to database. But then we need to make sure that this won’t hurt another user.For example user may save some html code and include some javascript code that would get executed in the browser it outputted normally.So we need to encode some special characters with html entities to revome their special meaning.

escape response headers

You should also escape your response headers if they contain values that can be supplied by the user.The common patter is that we want to redirect user to the page he came from. Or the return page is set in the URL.This could be easily taken advantage of. So we should limit the return pages to the adresses that are relative to our server.

REST

REST stays for Representative State Transfer.

read with GET,write with POST

I like to think of it as a way of limiting the entry points to the application while keeping application structure and interface very consistent.Here you can see a controller that implements typical CRUD operations in restful manner.In rest GET request are used only to retrieve the data from the server, and POST/PUT/DELETE request are used to modify data.In fact some browser do not support PUT and DELETE requests, so they are simulated with POST requests with additional param _method set to define which request should the server detect.

verify authenticity ofPOST/PUT/DELETE requests

In Rails it is very easy to create links and forms that invoke given types of request. It is done behind the scenes. For example if we create a html form for some object Rails detects what request should it use to send the form. If we’re creating a new record POST will be user, if we’re updating it will use PUT. In HTML all links are executed as GET requests, however Rails can deal with this by generating link with some javascript defined in onclick event. This JS builds a hidden HTML form a then sends it.There is also a method to make sure that all AJAX and non-GET requests are authentic. Rails automatically attach authenticity token to all non-GET and AJAX requests that is calculated from session and secret stored on the server. If the authenticity token check fails, the request will not be handles. It is again a one-liner to turn this behavior on.

Files

File uploads are another way to input data to an application so we should also take some precautions here.

don’t trust file extensions,validate MIME

• filename and extension can be easily manipulated

• the same stands for content type

• file header can contain malicious code that may be executed in browser when user clicks on malformed image

As always we can’t trust users to supply only files they’re supposed to.Even if the file looks harmless it may contain some malicious code. For example user can upload a malformed image with some JS code in file header. That image would render normally in the browser, however when another user clicks it, the JS will be executed. I am not sure how big a threat it is now, but it was possible to exploit in some older browsers for sure.

don’t let users choose file save path

*Paperclip plugin

We should always decide ourselves where we want to save uploaded files. We should also normalize filenames. This will prevent us from overwriting important files. In this example we use a Rails Paperclip plugin that handles file uploads in Rails. As you can see we save the uploaded avatars in public directory, with the filename changed to user’s id.

store files below Apache DocumentRoot

• everything in DocumentRoot is served by the web server

• uploaded php or cgi file may be executed by the web server when someone downloads the file

If we let the users upload any file they want, we need to make sure to save the files in a path that is not executable by the web server, so we should save the files at least one level downwards from web server’s document root.

process asynchronously

• save the file

• schedule it for processing

• handle the processing in the background with another process

Btw paperclip let’s us do some other cool things with our files like generating image thumbnails or do some other file processing when we save the file.Such operations can be time consuming especially when we’re processing media files.And if there are many files to process at once we can run out of resources.Solution to this is to only save file and schedule it for later processing in background. Probably on some other machine. Otherwise there is a possibility that we can face DOS attack when there are many files being processed at once.

control what can be downloaded

Another thing is that we should also keep control on what users are downloading from our servers.For example we may store some private files like invoices that should be available to download only by authorized users.In such cases these files should not be stored in a directory that is publicly available. Instead, they should be streamed to user after verifying his authenticity.

Other things

Other things...

• don’t reveal your application structure

• don’t reveal what framework, libraries, plugins you use

• keep your externals up-to-date

but don’t forget that...

security is just a feature, not the product

thank you

[email protected]

codetunes.comdevguru.plnetguru.pl

questions?