API Security, Tips You Can’t Afford To Miss

From Basics To Beyond

alexandre faria
Decathlon Digital

--

As developers, we used to say API first to highlight the need of building and providing APIs. Today we are more talking about Machine Learning first in order to highlight AI, API being an obvious key component of each software. APIs are everywhere, enabling data exchanges or services call, between organization entities, but also and most importantly with partners, being part of an ecosystem. That requires to set up an API strategy, focusing to add value, reduce time to market, but also increase security. In this blog post, I will explain why and how we must pay attention to secure our APIs, providing a non-exhaustive list of solutions.

Paradigm Shift

Decathlon tagline is “Make Sport accessible for the many”. Among all our actions to achieve this target, one of them is “Let’s make sport more accessible through coding”. That requires us to switch our mindset. While before we were focused to build a “big wall” to prevent external access to their information system, today we definitely need to open our information system (through API). Expose data and tools, share our know-how through technology to external developers, entrepreneurs and partners, we believe it can profit the sports industry. Having this in mind, we may see each API as a small open door into the wall, making security more complex to handle. Moreover, we used to say that data is the new gold, and from a hacker point of view, APIs are more interesting to hack because they are direct access to them. Furthermore, losing data is the only tip of the iceberg, identity thieves, deny of service, embarrassing media coverage, legal penalties are other possible consequences to take into consideration.

Basic actions

That seems obvious but first of all, check that you have only httpS (TLS 1.2+) enabled on your APIs, if not then all your efforts will be in vain.

Observe everything, technical & business data access, by setting metrics everywhere and use monitoring/alerting tools to be notified of any abnormal usage of your API as soon as possible.

Always prefer headers to query parameters when dealing with sensible data. URL (including parameters) are logged by default by several http servers and maybe also logged by applications, browsers and so on. Taking as example https://api.mycompany.com/resources?access_token=eyxxxx, people having access to these logs may steal your access_token, along with all data that go with that.

From a source code point of view, ensure to not include any credentials/secrets in your code, avoid to put them in environment variables and instead prefer secrets management tools such as vault. Use SAST (source code analysis tools) to detect vulnerabilities in your code, scan/audit your dependencies as well as your containers with tools similar to snyk. Use of known components vulnerabilities is #9 into below OWASP top 10.

Then keep in mind that your API is still a kind of web application, which rely on http protocol, that is why you should definitely have a look to https://owasp.org, and especially, but not only, to their top 10 application security risks. OWASP (Open Web Application Security Project) is a worldwide not-for-profit charitable organization focused on improving the security of software. They provide many tips & tools to help us in securing our applications.

source

Prevent Injections — A Simple Demo

For this blog post, I will give you an example on injection as it is the number one of the last top ten most used vulnerabilities report (OWASP 2017). There are many kinds of injection (html, javascript, SQL…) In this example, we will try to log in as an admin user by doing a SQL injection.

You can reproduce below examples by cloning my github repository here and follow the documentation.

Demo of SQL injection, source code available here

This works because the field content is directly concatenated to the SQL query, so as a result, the generated SQL query will be: SELECT * FROM user WHERE username=’admin’ AND password=’something’ OR username=‘admin’--’;

The root cause

To solve this issue, you must use prepared statements SELECT * FROM user WHERE username = ? AND password = ? ;This way, you provide separately the SQL query from parameters, and then, the database will ensure to compare each field with the given parameter. Another benefit of using prepared statements is that the database will compute a single execution plan for the query, enabling better performances.

Take away: Have a look to OWASP cheat sheet content as soon as possible.

Understand Authentication And Authorization

As an API, you must ensure who is trying to access to data and check if he is authorized to do so. Here you should avoid using basic authentication (see why below) but rely instead on a strong authorization and authentication tool like OAuth2/OpenID Connect to authenticate your users.

OAuth 2.0 is an Authorization Framework, it enables users (Resource Owner) to access their data through API (Resource Server), without having to expose their credentials to the front-end application (Client). Even if it does not intend to manage authentication, the specification states:The way in which the authorization server authenticates the resource owner is beyond the scope of this specification.”, most solutions provide both as it is difficult to separate them.

OpenID Connect is a framework on top of OAuth 2.0 allowing clients (third party applications) to verify the end-user identity and obtain some basic information about him. That is why most of the time you need to include the “openid profile” value in the scope query parameter of the authorization request. (openid to enable oidc endpoint access, profile to enable user data profile information access such as name, family name, gender, birthdate...)

At Decathlon, we are implementing Decathlon login to authenticate our users, aiming to be the entry point of our sports users data ecosystem. This way we delegate authentication, password lifecycle and so on to a dedicated tool.

401 (Unauthorized), must be understood as “I do not know who you are”, while 403 (Forbidden), means I know who you are but you are not allowed to access to the requested resource…

Take away: Rely on Openid Connect providers to authenticate users, and apply access controls on your API. Check if your solution can apply a rate limiting with captcha on the login page (trigger a captcha if too many authentication fail through the same IP in order to avoid brute force)

When Json Web Token make the difference

Authorization tool ends up delivering you a token that will be used to consume APIs. For a while, trend is to use Json Web Token. One main reason is because it enable self validation and avoid the authorization layer to be a SPOF (Single Point Of Failure). JWT are commonly composed of base64 encoded strings separated by two dots: Header.Payload.Signature The two first parts are Json content while the last one is a signature. Thanks to this signature the API will be able to validate the token (ensure no injection into the header or payload), without requiring to contact the Authorization Server, that is why it is so appreciated.

In the Header part of the token, a best practice is to specify the KID (Key ID attribute). This enables a possible signature key rotation. Each key as its own ID, and a validator can validate an old token or a new one based on this kid. If you manage multiple signature algorithms or key size, then the header will contain the ALG (Algorithm) attribute. In such case be careful because a common hack is to override the ALG value with “alg:none”, resulting in bypassing the signature validation, introducing token injection.

In the payload part, best practices are to specify and check those attributes :

  • EXP: expiration time
  • SCOPES: which resources this token grant access to
  • AUD: for which audience/backend the token has been generated for
  • SUB: Subject, unique identifier of the resource owner, aka user.
  • CLIENT_ID: Unique ID of the application claiming the token.

If your API exposes some personal data, you absolutely must scope them, and, allow access only if these scopes are well included in the JWT payload.

Take away: Never trust the JWT content until you have validated the signature, neither to the ALG header attribute to validate it. Use SCOPES and AUD payload attributes when possible.

The blue or the red pill? Symmetric vs Asymmetric

Frequently used signing algorithms are HS (HMAC with SHA) and RS (RSASSA with SHA) among many other available algorithms defined in RFC 7518. Choosing between both can be resumed in choosing between symmetric and asymmetric signatures.

Symmetric signature uses a single key to sign & validate the signature. This solution has a faster signature validation process but comes with some disadvantages. The most important one is that you need to share the key (also called shared secret) with the other party. If the key is leaked, then it can be used to decrypt and re-encrypt tokens, compromising all parties. Furthermore, as there is only one key, JWT secret can be found by trying every possible combination (brute force) or by parsing common password lists. This is also true for RSA but will require more time. Another simple hack is to try default password in case they have not been changed…

Brute forcing HS256 signed Json Web Token with a very small sized secret.

Asymmetric signature uses a key pair, one private key, and one public key. The private one is used to generate a signature and is kept secret by the Authorization Server. The public key can only be used to validate signature. The drawback is a relatively higher cost of cpu/time, but at the opposite of symmetric algorithm, the advantage is that you can communicate and share publicly the key. Regarding OpenID Connect specifications, Authorization Servers should share those public key through the jwks_uri endpoint, available into the .well-known/openid-configuration. That enables some auto-configuration mechanism and allow key pair (private/public) rotation without the need to contact all key owners.

Take away: Prefer Asymmetric algorithm, but if you still want to use symmetric algorithm, then use strong and long sized shared secrets. 256 bits minimum (32 random char long, 1 character = 8bits)

Client Side Security Tips You Can’t Afford To Miss

Even if it does not concern directly yours APIs, I want to provide a few advices on client (application) side.

A common pitfall when we declare a client_id is to apply regex matching on redirect_uri. Google, Microsoft, Facebook, Github all face issues with bad redirect_uri management. You should always specify/perform exact matching URL and register a redirect_uri as much specific as you can.

In addition to that, oauth2 specification define the state query parameter as recommended and not required. A lot of oauth2 libraries does not force the use of this parameter. As it intend to protect users from Cross-Site Request Forgery, you have to consider it as mandatory.

Another common pitfall is the logout management, deleting the access_token (JWT) and expiring the session into the application is not enough. Most OIDC providers manage SSO, meaning user can still have a session with the authentication server. In such case, by clicking on the login button, the application will be redirected to the authorization server, and, because the session is still alive, no login page will be displayed. Hence a new access_token will be provided, which will result in a fully usable application (authenticated as the previous user). A good practice here is to call a logout endpoint into the authorization server to kill the session on the login page too.

Last but not least, if you are using Single Page Application, just avoid to store the JWT into a cookie or local/session storage, it is not protected and you have less control on it. The best practice is to keep it in memory.

Take away: Use exact matching on redirect_uri, force use of state query parameter on login, ensure logout is really done, choose the right flow to obtain the token, and finally, store carefully your JWT.

Back to our API, unleash your potential thanks to API Management

Api Management are a set of tools that helps

  • API producers to publish/expose/monitor their APIs
  • API consumers to search/subscribe APIs
  • Control who, when and how APIs are consumed

The most important component is the “API Gateway”, which is placed between the consumer (client) and the resource server (api). It is in charge of executing policies defined by the API provider such as routing, caching, logging, mocking, and many others… Here I will focus on policies improving security.

Simplified illustration of my live demo Architecture, source code is available here.

A first obvious feature of API Management is the possibility to fine-tune how can your APIs be accessed. In my demo, I use Gravitee solution, in which I set up access plan. For each plan, I can set a rate limit (maximum amount of allowed request in a short time interval), Quota (same but for a longer time interval), whitelist/blacklist endpoints & http verb, and finally, whether or not the plan need an API owner manual approval. There are more options, but I will not cover them in this post…

Plans with different access rules settings.

According to the above picture settings, I subscribed to the TRIAL plan, and I will bench it. Due to the white list option, this plan only allows me to call the GET /users endpoint. I will generate as many requests as possible for ten seconds, using wrk command with 12 threads, and keeping 400 HTTP open connections.

Shell wrk command used to generate as many requests as possible.

The result show 6791 requests for 6692 failures, mean 99 requests succeeded. Most of the request falls in error (429 — Too Many Requests status code) due to the 10 req/s rate limit. The count is not exactly 100 because I have selected an asynchronous rate limit to reduce the latency overhead, but you can enable it in a synchronous way if you prefer…

You may notice the headerX-Gravitee-Api-Key: 4d58b5f6... in the request, this is obtained while subscribing to plan. Api-key is used to identify the client and check access permissions. The main pitfall here is to exclusively rely on them, they are not safe, easy to grab on mobile or Single Page App. Use them in addition to JWT and consider them only for monitoring purpose (TOP X consumers).

Another great feature is the Circuit Breaker Design Pattern. Main advantages of this pattern are to enable a fail fast policy. Each time your endpoint is not available, it will call a fallback endpoint, or, if not possible, fail faster (without timeout). But that requires your API to implement a health_check endpoint in order to let the gateway monitor your API status. It will prevent your API to receive a lot of request while unhealthy.

Circuit breaker can be automatically enable according to the API health check endpoint.

API Management has much more features to offer (CORS management, IP filtering, Request content limit, Request validation, etc…) you should have a look to.

Take away: Expose your API through an API Gateway. Use fine grained access controls and measure everything. Always implement health_check. Apply clever rate limiting and quota according to the usage.

Conclusion

Security is an endless topic. In this blog post, I only scratch a few points (from OWASP basics to API Management tips) that you have to pay attention to while developing your API. A good practice is to build your own security checklist. You can start by checking every take away on this post and add another one relevant to your domain, your security level… If you enjoyed this post, feel free to share, clap or give a comment.

Who am I

Software Engineer since 2005, I am currently working for Decathlon group. As a developer, I am more interested in the back side, especially on APIs and authentication/security topics. Sharing knowledge is what I prefer in my daily job. Open source world is also a fascinating topic for me.

Thanks to: Gregoire Waymel, Laurent Thiebault, Alexandre Toulemonde and Boris Stoyanov who helped me to review this post.

We are hiring!

You are passionate about sports and new technologies? Luckily for you, we are hiring! Follow https://developers.decathlon.com/careers to see the different exciting opportunities.

--

--