Wednesday, December 30, 2015

Re: how to restrict responses to a single server/domain ?

I'm trying to build something similar to a microservice using Django and can't figure out how to setup the authentication part. 

When I say 'microservice' I mean, we have a bunch of systems like - example.com  , test.com  , another.com and another.test.com (a subdomain). I'm going to build a REST API on test.com which needs to be consumed by another.com. How can I enforce this restriction? And if later, I wanted to allow example.com to use the API (or even allow general public access), how can I do this?

My instincts tell me that I'm missing something obvious, but I can't seem to figure out what to search for.

Puzzled,
Abraham V.

Seems like a simple question, but as with most things relating to computer security, the answer is "it depends (on a lot of things)". 

There are dozens of ways to handle this problem, and many of them have nothing to do with Django. You have two primary lines of defense: network controls and authentication controls. The answers aren't necessarily obvious, although any bit of reading on how other people have approached the problem shouldn't be difficult to track down with a quick Google.

Network controls should be where you start, if you can, since you can filter a majority of the Internet noise here without much effort (usually). I'll assume that you have a host firewall such as iptables or Windows Firewall, or a hardware firewall, that is configured to only allow the Internet to access your server on the necessary ports for serving your web application (likely tcp/80 and/or tcp/443). If you can narrow down the source IP addresses or IP ranges that example.com and others will be using, you can add these as exceptions in your firewalls instead of the broad port-based exception I just described (or better yet as a combination of the port-based exceptions and source IP's), while dropping requests from anywhere else. Moving up the stack, most HTTP servers will also allow you to specify the range of source IP's that are valid when responding to requests, but may provide a slightly weaker security posture since I would assume the web server would not be protected by firewalls, and could be subject to buffer-overflows, bad request exploits, etc. I'd recommend using both strategies concurrently, keeping them in sync with a configuration management tool. You would still be exposed if a service/host at another.com were compromised (which is exactly how Target was compromised by an attacker pivoting through a 3rd party vendor), but at least you've significantly lowered your attack surface. Another option would be to hide the entire set of microservices behind a VPN and require the consumer to first connect to the VPN in order to gain access, which may or may not be feasible. Plenty of permanent branch VPN solutions are available so that individual users don't need to be bothered with setting up VPN access. Network control is primary about controlling where and how users are connecting at a low (network) level.

Your HTTP server should support the recommended versions of TLS (I believe the SSL protocol is now totally deprecated and should be avoided, although the term SSL is still commonly used to refer to TLS). I personally believe it should just be assumed that TLS services are used by default. There's not really any excuse not to use encrypted connections for any sort of publicly available service over the Internet, even between two known entities.

Moving further up the stack, we find authentication, authorization, and accounting controls. There are two common ways to authenticate/authorize web requests to microservices: via service account user/pass, or via an API key/token that is given to those services. User/pass is common where a human is directly controlling a local app that will consume those services (and usually on an infrequent basis), and the API token is common where there is no clear logical connection between a human and the request (standalone services pulling data for reporting on a regular basis, etc.). Sometimes the user credentials are only used to retrieve an API token, and then that token is used for all API calls by an end-user application. Of course, either method can be employed for most scenarios. Token authentication will be a likely path for you.

Your microservices should not respond with anything other than error messages unless the requester has validated credentials (unless you have some API calls that are publicly accessible, in which case those calls should succeed regardless of whether or not the requester provides credentials). Each authentication type has it's own implementation strategy and limitations, and will be determined by your HTTP server choice (if using basic authentication via the HTTP server) and/or Django authentication strategy. For example, Django REST Framework supports either method (along with session authentication), and has library calls to generate and assign API tokens to users, or can simply accept credential logins (http://www.django-rest-framework.org/api-guide/authentication/). Ensuring that your API consumers have the only copies of the tokens or user credentials will definitely go a long way to achieve the protection you desire, and may be your only option on a shared-host setup where you do not have access to the HTTP server or host configuration. Use TLS whenever possible (which should be for pretty much everything nowadays) to protect the credentials and data transfer of the innocent.

Another note, these restrictions are heavily impacted by your consumers and what their capabilities for connecting are. Do you have mobile users that want to connect from anywhere in the world? Requirements like that tend to leave network controls wide open, and you are limited to either requiring your users to do extra work (VPN connection), and/or having them use one of the authentication methods I mentioned.

Other more esoteric authentication/authorization methods exist (certificate authentication, header inclusion requirements, proxies, etc.), but I'll be here all night if I went into any sort of detail on those. ;-)

TL;DR; Lock things down with firewalls as much as possible, and look at having non-public API resources protected by either user/pass or an API token. All transactions should occur using SSL/TLS if credentials are involved. There's little excuse nowadays for sites to not support SSL/TLS. That should take care of 99% of the trouble.

Without a thorough examination of your intended infrastructure and clientele, there isn't really a way to give you a more specific answer. If this is really a concern and/or you are providing high-value data, I would suggest hiring a web security consultant to recommend the best course(s) of action.

Security is hard, and usually expensive. If it wasn't, everyone would be doing it.

-James

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CA%2Be%2BciWSAFydb9-4%2BLHOOhn6wLSBDSw4uLskXJozbS_qRxXpXA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment