This post is part of a series that was developed for fintech_devcon 2023. You can see a full video of the workshop on YouTube
When it comes to securing a web application, many developers tend to focus on implementing specific security controls right away. You might hear statements like, “I need authentication,” “Maybe Cloudflare can stop DDoS attacks,” or “Let’s require users to create strong passwords.” While these measures are important, they often skip a crucial step in the process: considering the application’s architecture design.
Designing your architecture with security in mind is a fundamental step in building a robust defense against potential threats. By leveraging architectural modularity, you can create a system that separates security concerns into its own dedicated layer. Just as a web server contains business logic and a database stores data, specific components can be configured to manage cross-cutting security concerns. This approach not only enhances security but also offers benefits such as scalability and improved refactoring capabilities as the application’s complexity grows.
The importance of “Insecure design” has been underscored by the OWASP Top 10 list of common web vulnerabilities. In a new category introduced in 2021, the focus is on risks related to design and architectural flaws. The call is for more use of threat modeling, secure design patterns, and reference architectures. The community needs to move beyond “shift-left” in the coding space to pre-code activities that are critical for the principles of Secure by Design.
One powerful architectural module for web applications is an API Gateway. An API gateway is an application that sits in front of the API and acts as a single entry point for requests from outside the cluster. It routes these requests to the appropriate backend microservices. What makes it particularly valuable is that it allows you to add security controls without needing to modify the backend microservices themselves.
Let’s look at a practical example of how an API Gateway can be used to enhance security. One common concern is limiting the rate of requests accepted by the API for a particular IP address. Rate limiting serves as a potent defense against attacks like “credential stuffing,” where attackers attempt to authenticate with known username/password combinations at high speeds.
We’ll use Traefik, an open source cloud native gateway that can plug into a kubernetes cluster. It has the concept of “middleware” that can process API requests before passing them through to a backend. We can configuring a rate limit for all of our API endpoints by matching on the request path:
+--- apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: http-ratelimit namespace: default spec: rateLimit: average: 50 burst: 75 --- apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: strip-api-prefix namespace: default spec: stripPrefix: prefixes: - /api --- apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: api-ingress namespace: default spec: entryPoints: - web routes: - kind: Rule match: PathPrefix(`/api/v1`) services: - name: api port: 80 middlewares: - name: http-ratelimit - name: strip-api-prefix
We are configuring the gateway to allow on average 50 requests/second across all of our API endpoints for a single client. Up to 75 req/s are also allowed for short periods of time in bursts. Clients are identified by IP addresses, but other configuration options allow for clients to be identified by a header value. The full list of configuration options are documented here.
One gotcha with IP address rate-limited is that it’s not uncommon for many different end-users to share an IP address. This is prevalent for customer apps but can also affect B2B, when several companies are in the same co-working space.
Traefik has a catalog of middlewares that can be downloaded and installed, or you can develop your own for custom functionality.
In addition to rate limiting, we can use the gateway to encrypt traffic with TLS and validate authentication for requests to our API. These are “cross-cutting concerns”, or security principles that we expect every API backend to enforce. Rather than relying on each backend server implementing these controls (or risking that a backend gets deployed without one), our gateway consistently enforces them.
Not only does a gateway provide a layer of security to our architecture, but it also gives us flexibility for upgrading our backend services in the future. We can control our requests are routed through the gateway configuration, and forward version 2 of our API to new services while keeping backwards-compatible services running separately.
Another architectural design consideration is network segmentation. This strategy involves separating a network into distinct sub-networks (subnets), which restrict how machines on the network can communicate with each other or the Internet.
By limiting the sources from which a server can receive network traffic, you can effectively guard against unpatched vulnerabilities being exploited. “Zero day” flaws refer to vulnerabilities discovered after attackers have already started exploiting them to hack into systems. It’s difficult to predict where the next “zero day” will emerge, but a server that is isolated from direct Internet traffic is less likely to be compromised by such vulnerabilities.
The strongest form of network segmentation is achieved by restricting what backend servers can receive traffic directly from the Internet. Given the Internet’s vast and varied population, it’s still one of the primary sources of threats.
A useful design strategy starts with the assumption that “none of your backend servers” need a direct connection to the Internet. For instance, your database likely doesn’t need to accept connections from the Internet; it only needs to communicate with other backend servers. Therefore, start with the assumption that no Internet connectivity is required and then selectively add it to components that absolutely need it.
It’s entirely feasible that, when using an API Gateway as described earlier, none of your servers need a direct Internet connection. The Gateway can handle all incoming traffic from the Internet, ensuring that the traffic is safe and authorized before passing it to a server located on a restricted network.
Incorporating these architectural considerations early in your application’s design can significantly enhance your security posture. By thinking ahead and building security into the very structure of your application, you’re better equipped to defend against evolving threats and vulnerabilities. In today’s digital landscape, this proactive approach is a critical component of your overall security strategy.