Top 13 Tips That Will Help You To Secure Your REST!

Top 13 Tips That Will Help You To Secure Your REST!

REST is an extremely popular web application architecture. To call functions on the server, regular HTTP requests with specified parameters are used (usually JSON or XML is used to structure the parameters), while there is no strict standard for the REST architecture, which adds flexibility (and, of course, a bit of chaos).

REST allows you to flexibly approach the issue of security or, with what many sins, do not approach the question at all. Based on OWASP, we have prepared a list of tips to help you improve the security of your REST application.

As a starting point, in those rare cases where it is needed here, we use Python and Django.

Tip 0

HTTPS

Protection of transmitted data has not harmed anyone. Even if you think that there is nothing to protect at the moment, this will not always be the case and you will still have to configure HTTPS. So set it up better right away and everyone will be fine.

Tip 1

Authentication

It would seem obvious advice, which, however, many prefer to neglect. The application should always have authentication, even if you now think that you will use it only within the company and there is no difference which employee does it. And if you add magazines, the investigation of incidents and analysis of activity will become incomparably easier.

As access tokens at the moment, it is considered a good practice to use JWT (JSON web tokens). Do not use tokens with the value of {"alg": "none"} for integrity monitoring, tokens must always contain a signature or MAC! The signature is preferable due to the fact that the generation and verification keys of the MAC match (or can be easily calculated from each other), that is, if the server is able to verify the MAC value, then it can also generate its values. The signature also confirms not only the integrity of the message but also the identity of the sender.

Tip 2

Prohibit those HTTP methods that you do not use

Configure on the server a whitelist of the methods you work with (GET, POST, PUT, etc.) and reject anything that does not fall under this list. It is unlikely that at production your server needs to handle requests of type TRACE (this method is part of the XST attack (Cross-Site Tracing), which consists of an XSS attack and the TRACE or TRACK method. This attack allows, for example, to steal a user’s cookie, even they are marked as HttpOnly). The less information about your infrastructure is available outside – the better.

Tip 3

Differentiate access

Do all your users need all the methods, for example, DELETE? If you do not want any users to have the opportunity to perform certain operations, configure access control in your application. For example, only the GET method for some functions is accessible to the ordinary user, the GET and POST functions to the manager, etc. For this, it is necessary to specify the roles in the database that can be issued to users for ease of access control.

As a result, each function will have a test block of approximately the following type:

if request.POST and user.is_manager:
     do_stuff()

Tip 4

Consider limiting the number of requests

If you think that your users should not send you a hundred thousand requests per second, then this number should be limited. Use API keys or any other mechanism convenient for you to track and limit the number of requests that will be processed in a specific period of time from one user. For Django, this functionality, for example, is provided by django-ratelimit, where you can set various parameters as an identifier for the restriction, not necessarily API keys, but an IP address.

Tip 5

Be sure to validate/sanitize input data.

Never trust the transmitted input parameters, always carry out validation/sanitization:

  • If this is possible (and where it is possible), put a restriction on the length/type/format of the input data and the request itself. Reject all requests/transmitted data that exceed the length you specify or do not match the type/format.
  • When processing strings, always escape all special characters.
  • If you are using the framework, most of them contain their own built-in validation and sanitization tools (off-the-shelf Django (Python) and Yii2 (php)), so it’s important to explore their capabilities and if some aspect you need is not covered – find a library that closes it, or write such a functional yourself.
  • Keep track of validation errors. If the requests of some users are constantly failing validation – think about the automatic blocking of such users.
  • Make sure your input parameter parser (or its current version) is not susceptible to any attacks by itself.

Tip 6

Do not give away more information than necessary.

If any request caused an error in the application, or it is simply unavailable for some reason at the moment – do not give details in the response, return the most abstract error message. Some servers return stacktrace after an error by default, so make sure that you reconfigure this logic.

Tip 7

Always keep magazines

Let each event (authentication, error, request, etc.) be logged in as much detail as possible. Separate them logically for more convenient search by them if necessary. Just in case, before recording the logs, sanitize the recorded data.

Tip 8

Correctly specify the Content-Type – this is important!

In order for the browser (or client) to correctly read the data provided, the correct Content-Type corresponding to the data provided is important. In the case of browsers, you should also set the X-Content-Type-Options: nosniff header to prevent the browser from trying to detect other Content-Type besides the one that was actually sent (a countermeasure against XSS attacks).

Tip 9

Validate Content-Type

It is necessary to configure the rejection of requests if their Content-Type is different from their content. This will reduce the risk of incorrect data processing, which can lead to injection or code execution at the server/client.
You should also reject requests for which you do not support the Content-Type, or for which this header is completely absent. Avoid also direct answers about which Content-Type the function accepts/issues if this is not necessary (this will help to avoid XXE attacks).
In REST services, it is common to support several types of responses (for example, json and XML), and the client indicates the preferred type of response in the Accept header when requested. Avoid copying the contents of the Accept header to the Content-Type response as a mechanism for setting this header. Reject also requests whose Accept header does not directly contain at least one of the supported types.

Tip 10

Do not forget to configure Cross-Origin Resource Sharing (CORS)

CORS is a standard that describes how to work with cross-domain queries. If your application does not support CORS, disable working with this type of headers. If you need to use it, the access policy should be as specific and strict as possible.

Tip 11

Do not disclose parameters in the URL

All critical data (passwords, keys, tokens, and logins are desirable too) should be inside the request body or in the headers, but in no case should appear in the URL. If you need to transfer sensitive data through the GET method, then put it in the header.

You can not:
example.com/controller/123/action?apiKey=a53f435643de32

You Can:
example.com/controller/123/action

Headlines:

Host: example.com
User-Agent: Mozilla
X-APIkey: a53f435643de32

Tip 12

Consider CSRF protection.

You can read more about all types of protection here, and so, the most popular way to reduce the risk of attacks of this type is to use CSRF tokens.

Tip 13

Learn your framework

If you use a framework to implement REST in your application, then you should study it and not use it blindly, as it is often done. Read the documentation carefully, especially the safety part. Do not leave it to work on the default settings! Each framework has its own nuances, especially when it comes to security, so knowing them is very important.