visit
<code style="box-sizing: border-box; font-family: Monaco, Consolas, "Lucida Console", monospace;">First Call: GET /items?skip<span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=</span>0&take<span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=</span>10
Second Call: GET /items?skip<span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=</span>10&take<span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=</span>10
</code>
<code style="box-sizing: border-box; font-family: Monaco, Consolas, "Lucida Console", monospace;"><span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">skip</span> <span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=</span> <span class="mi" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(247, 140, 108);">0</span>
<span class="k" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(199, 146, 234);">while</span> <span class="bp" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">True</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">:</span>
<span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">response</span> <span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=</span> <span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">requests</span><span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">.</span><span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">post</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">(</span><span class="s" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">'//api.acmeinc.com/widgets?take=10&skip='</span> <span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">+</span> <span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">skip</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">),</span>
<span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">headers</span><span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">{</span><span class="s" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">'Authorization'</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">:</span> <span class="s" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">'Bearer'</span> <span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">+</span> <span class="s" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">' '</span> <span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">+</span> <span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">sys</span><span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">.</span><span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">argv</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">[</span><span class="mi" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(247, 140, 108);">1</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">]})</span>
<span class="k" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(199, 146, 234);">print</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">(</span><span class="s" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">"Fetched 10 items"</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">)</span>
<span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">sleep</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">(</span><span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">randint</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">(</span><span class="mi" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(247, 140, 108);">100</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">,</span><span class="mi" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(247, 140, 108);">1000</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">))</span>
<span class="n" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">skip</span> <span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">+=</span> <span class="mi" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(247, 140, 108);">10</span>
</code>
How to secure against pagination attacks
To secure against pagination attacks, you should track how many items of a single resource are accessed within a certain time period for each user or API key rather than just at the request level. , you can block a user or API key once they hit a threshold such as “touched 1,000,000 items in a one hour period”. This is dependent on your API use case and can even be dependent on their subscription with you. Like a Captcha, this can slow down the speed that a hacker can exploit your API, like a Captcha if they have to create a new user account manually to create a new API key.How to secure against API key pools
The easiest way to secure against these types of attacks is by requiring a human to sign up for your service and generate API keys. Bot traffic can be prevented with things like Captcha and 2-Factor Authentication. Unless there is a legitimate business case, new users who sign up for your service should not have the ability to generate API keys programmatically. Instead, only trusted customers should have the ability to generate API keys programmatically. Go one step further and ensure any anomaly detection for abnormal behavior is done at the user and account level, not just for each API key.How to prevent accidental key exposure
The easiest way to prevent key exposure is by leveraging two tokens rather than one. A refresh token is stored as an environment variable and can only be used to generate short lived access tokens. Unlike the refresh token, these short lived tokens can access the resources, but are time limited such as in hours or days.
The customer will store the refresh token with other API keys. Then your SDK will generate access tokens on SDK init or when the last access token expires. If a CURL command gets pasted into a GitHub issue, then a hacker would need to use it within hours reducing the attack vector (unless it was the actual refresh token which is low probability)Stopping DDoS attacks
The magical part about APIs is almost every access requires an API Key. If a request doesn’t have an API key, you can automatically reject it which is lightweight on your servers (Ensure authentication is short circuited very early before later middleware like request JSON parsing). So then how do you handle authenticated requests? The easiest is to leverage rate limit counters for each API key such as to handle X requests per minute and reject those above the threshold with a 429 HTTP response. There are a variety of algorithms to do this such as leaky bucket and fixed window counters.How to ensure proper SSL
Test your SSL implementation over at or similar tool. You should also block all non-HTTP requests which can be done within your load balancer. You should also remove any HTTP headers scrub any error messages that leak implementation details. If your API is used only by your own apps or can only be accessed server-side, then reviewHow to ensure no caching
You should ensure headers are properly configured.A big gotcha for APIs is that many do not use the standard Authorization header instead using a custom header like X-Api-Key. Caching servers do not have knowledge of this request being authenticated and thus chooses to cache the request.
<code style="box-sizing: border-box; font-family: Monaco, Consolas, "Lucida Console", monospace;"><span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">app</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">.</span><span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">use</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">((</span><span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">req</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">,</span> <span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">res</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">,</span> <span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">next</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">)</span> <span class="o" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(137, 221, 255);">=></span> <span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">{</span>
<span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">res</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">.</span><span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">setHeader</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">(</span><span class="s1" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">'Cache-Control'</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">,</span> <span class="s1" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">'no-store, no-cache, must-revalidate'</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">);</span>
<span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">res</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">.</span><span class="nx" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(130, 170, 255);">setHeader</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">(</span><span class="s1" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">'Pragma'</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">,</span> <span class="s1" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(195, 232, 141);">'no-cache'</span><span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">);</span>
<span class="c1" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(178, 204, 214);">// ...</span>
<span class="p" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s; color: rgb(238, 255, 255);">});</span>
</code>
How to properly add API logging
You should ensure your API logging not only tracks the API requests themselves, but also be tied back to users for user behavior analytics and stored for at least a year. These systems should be protected to ensure data cannot be accidentally deleted or retired early. GDPR and CCPA provide exceptions for API audit logs for security purposes. Solutions like provide a full suite of API monitoring and analytics for API products and can get started in just a few minutes.
While most API developers will add a global Authentication scheme such as API keys or OAuth to verify who the person is, it’s harder to implement Authorization is also required and separate from Authentication. Authorization involves checking whether this person (who is already identified) can access a particular resource. This can be done via API scopes, checking against a tenant id or user id, among other things.
Because it’s specific to your application logic and is not always cross cutting, Authorization can be an area developers forget about. Unless your object identifiers have enough entropy, a hacker could easily test different ids through iteration. This is especially true for SQL databases that increment the id on insertion.How to fix authorization
Ensure the authenticated user is authorized to access all resources that is required to generate the API response. This may involve checking against a user id or access control lists (ACL) that’s linked to the objects in question.
For more info on how to handle authorization, view our postPreviously published at