When managing Apigee API proxies, security is critical to protecting sensitive data, maintaining user trust, and avoiding breaches. Whether you're new to securing proxies or looking to strengthen your existing setup, it's essential to understand the vulnerabilities you may face and how to mitigate them.
In this post, I’ll guide you through the steps of securing your Apigee proxy, starting with simple actions you can take today, and gradually moving to more advanced techniques.
Whether you're working with a small team or managing a large, complex system, CodeSent can help streamline the process by automatically identifying vulnerabilities. This ensures that even without extensive manual effort, your APIs remain secure against a wide range of threats.
Step 1: Enforce Strong Encryption and Secure Backend Communications
The foundation of securing any API is to ensure that data transmitted between clients, proxies, and backend systems is encrypted using secure protocols. This is essential for protecting the confidentiality and integrity of sensitive information, such as API keys, tokens, and user data.
TLS provides encryption for communications, so that any data exchanged over the network is safe from interception and tampering. Without it, sensitive information can be exposed through man-in-the-middle attacks or network sniffing.
To mitigate this risk, your HTTPTargetConnection
and ServiceCallout
policies should be configured to use TLSv1.2 or TLSv1.3, as well as the TrustStore.
<SSLInfo>
<Enabled>true</Enabled>
<IgnoreValidationErrors>false</IgnoreValidationErrors>
<TrustStore>ref://TrustStore</TrustStore>
<Protocols>
<Protocol>TLSv1.2</Protocol>
<Protocol>TLSv1.3</Protocol>
</Protocols>
</SSLInfo>
In this configuration:
- Enabled ensures that TLS is active.
- IgnoreValidationErrors set to false makes proxy aware that an error must be thrown if something is wrong during communication.
- TrustStore specifies that only certificates from trusted Certificate Authorities (CAs) are accepted, which is critical for securing communications.
- Protocols enforces the use of TLS 1.2 or higher, avoiding outdated and vulnerable protocols like SSLv3 or TLSv1.0.
Be cautious with your TLS configuration
Failing to specify protocols or using outdated ones can expose your systems to attacks. CodeSent can detect insecure protocol configurations or missing TLS settings in your proxies, making sure you stay compliant and secure.
Step 2: Validate All Inputs
Validating inputs is essential to maintaining the integrity of your API and protecting against common attack vectors such as injection attacks, data tampering, and denial-of-service (DoS) vulnerabilities. Failing to validate input leaves your API open to exploits, potentially leading to a breach.
JSONThreatProtection
and XMLThreatProtection
policies should be applied to validate structured data formats like JSON or XML. These policies ensure that incoming data conforms to expected formats and size constraints, preventing malformed or oversized payloads from reaching your backend.
<JSONThreatProtection continueOnError="false" enabled="true" name="JSON-Threat-Protection">
<DisplayName>JSONThreatProtection</DisplayName>
<ArrayElementCount>16</ArrayElementCount>
<ContainerDepth>4</ContainerDepth>
<ObjectEntryCount>8</ObjectEntryCount>
<ObjectEntryNameLength>32</ObjectEntryNameLength>
<Source>request</Source>
<StringValueLength>32</StringValueLength>
</JSONThreatProtection>
But remember that validation isn’t just for JSON or XML payloads. You should also validate path and query parameters, headers, and body parameters to ensure they meet expected formats and values.
Let’s say you're validating a user-id
passed in a header. The first step is to ensure that the user-id
header is present (i.e., not undefined
), and then confirm it follows the UUID format. Here’s an example using JavaScript:
// Regular expression for UUID validation
var userIdRegExp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
// Get the user-id from the request header
var userId = context.getVariable('request.header.user-id');
// Check if the user-id is defined
if (userId === undefined || userId === null) {
throw new Error("User-id header is missing");
}
// Validate user-id against the regular expression
if (!userIdRegExp.test(userId)) {
throw new Error("Invalid user-id format");
}
// If valid, proceed with other logic
Why the input validation is important?
Injection attack prevention: by validating incoming data, you reduce the risk of injection attacks (e.g., SQL or command injection) where attackers attempt to exploit poorly validated inputs and cross trust boundaries, allowing them to access sensitive areas of your system.
Data integrity: proper validation ensures that data entering your system is what you expect, preserving the integrity of information as it crosses trust boundaries, and preventing unauthorized data tampering or manipulation.
DoS protection: enforcing size limits on payloads helps mitigate denial-of-service attacks that aim to overwhelm your backend with large or complex payloads, particularly when data comes from less trusted sources outside your security perimeter.
Understanding and enforcing trust boundaries is crucial to prevent untrusted data from crossing into secure areas of your system, ensuring that your API maintains its security posture.
Tracking untrusted data is tough!
Manually tracing where untrusted data (like user input from the body) flows through your system—especially when it ends up in sensitive places like the URL—is challenging. CodeSent's taint analysis feature detects these flows automatically, ensuring that untrusted user input never reaches critical components without proper validation.
Check out the Target URL Tainted by User Input Rule to see how it works!
Step 3: Prevent Data Leaks and Protect Sensitive Information
One of the important aspects of securing your API is preventing data leaks, especially when dealing with sensitive information like API keys, passwords, tokens or personally identifiable information (PII). Even small oversights in handling sensitive data can lead to severe security breaches, exposing private data to unintended parties.
Avoid Sensitive Data in URLs
Never accept sensitive data like credentials, passwords, or API keys through URL parameters. Even though TLS ensures data is encrypted during transmission, it does not protect against the logging of URLs. URL parameters can be logged in various places, such as server logs, browser history, or intermediate network devices, which creates a significant risk of unintentional exposure.
Instead of allowing sensitive data in URL parameters, you should reconfigure your proxy to accept such information via headers or the request body, where you can enforce better security controls. It’s also important to ensure that consumers of your API follow these security practices. Enforcing these changes helps reduce the risk of accidental data leaks.
However, if there is a strict business need to receive sensitive data in the URL, you can at least move it from the URL to headers at the proxy level. This mitigates the risk of sensitive data being exposed in logs in subsequent systems.
Use the AssignMessage
policy to extract sensitive data from the URL and move it into headers before forwarding the request to the backend:
<AssignMessage>
<AssignVariable>
<Name>request.header.X-User-Id</Name>
<Ref>request.queryparam.user_id</Ref>
</AssignVariable>
<Remove>
<QueryParams>
<QueryParam name="user_id"/>
</QueryParams>
</Remove>
</AssignMessage>
By doing this, you remove sensitive information from the URL, reducing the risk of exposure, while still fulfilling business requirements.
Mask Sensitive Data in Apigee Trace (Debug) tool
When debugging API calls in Apigee, sensitive data—such as API keys, tokens, or PII—can sometimes appear in the Trace tool. To protect this data from exposure, Apigee provides several mechanisms for masking or hiding sensitive information.
To prevent sensitive data from being exposed, you can configure data masking or use the private.
prefix for custom variables.
Stay secure!
By using CodeSent, you can automatically detect and prevent these issues, ensuring that your sensitive data remains secure and never unintentionally exposed during API operations or debugging.
Step 4: Protect Against Denial-of-Service (DoS) Attacks with Rate Limiting
Even well-secured APIs can be vulnerable to DoS attacks if they don’t have proper rate limiting in place. DoS attacks aim to overwhelm your system with a flood of requests, degrading performance or even making your service unavailable. Implementing rate limiting helps protect your backend by ensuring that legitimate traffic is prioritized and preventing malicious actors from overwhelming your API with excessive requests.
In Apigee, the SpikeArrest
policy is used to control the number of requests an API can handle within a given time frame. By limiting the number of requests per minute (or second), you can effectively throttle traffic and mitigate the impact of DoS attacks.
Here’s an example of a basic SpikeArrest
policy configuration:
<SpikeArrest continueOnError="false" enabled="true" name="SpikeArrest-Policy">
<DisplayName>Spike Arrest</DisplayName>
<Rate>100pm</Rate> <!-- Limits to 100 requests per minute -->
<Identifier ref="request.header.x-api-key"/> <!-- Uses API key as the identifier -->
</SpikeArrest>
In this configuration:
- Rate specifies the maximum number of requests allowed per minute (in this case, 100).
- The Identifier ensures that the rate limit applies individually to each client based on their API key.
Why rate limiting is critical?
DoS mitigation: Rate limiting prevents your API from being overwhelmed by a flood of requests, maintaining availability and ensuring that your service remains responsive to legitimate users.
Traffic control: By limiting the number of requests, you prevent any single client from monopolizing API resources, allowing a fair distribution of traffic across all users.
Abuse prevention: Rate limiting also helps protect against abuse by clients who may attempt to exploit your API by sending an excessive number of requests in a short time.
While SpikeArrest
is a powerful tool for preventing DoS attacks, it’s crucial to configure it carefully. Improper configuration—such as choosing the wrong identifier—can inadvertently lead to service disruption or even cause a self-inflicted DoS. For instance, using an overly broad identifier (like using app identifier when an API is consumed by end-users) could throttle all users connection from the same app, causing unintended outages.
But don’t worry!
CodeSent understands the context of your proxy and can detect when you’re using an incorrect identifier, ensuring your configuration is always secure and optimized
Step 5: Implement Strong Authentication and Authorization
A critical aspect of securing your Apigee proxy is ensuring that only authorized users and systems can access your APIs. Authentication confirms the identity of the client, while authorization determines what resources they are permitted to access. Implementing these correctly protects your API from unauthorized access, data breaches, and abuse.
Apigee supports OAuth 2.0, one of the most widely used protocols for securing APIs. It allows client applications to access APIs on behalf of users without exposing sensitive credentials like passwords. By generating short-lived tokens, OAuth ensures secure access while minimizing risk.
However, misconfiguring OAuth token expiration times can lead to serious vulnerabilities. Some developers mistakenly set very long expiration times for tokens, leaving the door open for abuse. For instance, if an access token with a long lifespan is compromised, it gives attackers more time to exploit it, significantly increasing the security risk. This is why setting an appropriate expiration time for tokens is crucial.
But while OAuth2 is a robust solution for user authentication, for simpler use cases, API keys can be used to authenticate and control access to your APIs. However, API keys should be managed carefully:
- Rotate API keys regularly to prevent abuse.
- Set rate limits and quotas for API keys to prevent overuse and potential DoS attacks.
Here’s an example of API key validation using Apigee policies:
<VerifyAPIKey name="VerifyAPIKey">
<APIKey ref="request.header.x-api-key" />
</VerifyAPIKey>
Misconfigured tokens are a security hazard!
Developers often set overly long expiration times for OAuth tokens, significantly increasing the window for exploitation. CodeSent helps you detect these misconfigurations automatically, ensuring that your token expiration settings are always secure.
Conclusion
Securing your Apigee proxy involves a multi-step process, starting with basic protections like enforcing TLS encryption and validating input, and extending to more advanced measures such as rate limiting, data masking, and proper token management. These steps are critical not only for maintaining data integrity and compliance but also for protecting your systems from common vulnerabilities like DoS attacks, data leaks, and unauthorized access.
By following these best practices, you can significantly reduce the risk of security incidents in your API proxies. However, as your systems grow and become more complex, it’s easy for security gaps to appear. This is where CodeSent steps in, automating vulnerability detection and ensuring that your proxy configurations remain secure and optimized. Whether it's catching long-lived tokens, identifying insecure flow variable handling, or flagging incorrect rate limit configurations, CodeSent is your proactive solution to staying ahead of security threats.
Securing your Apigee proxies doesn’t have to be a manual, time-consuming process. With the right tools and practices, you can keep your APIs safe, scalable, and compliant with minimal effort.
Ready to secure your proxy the right way?
Try CodeSent today and see how easy it is to safeguard your API infrastructure.
How to Start Securing Your Proxy