How to protect API endpoints?

What is the name of the domain?

What is the error number?

403 (usually), 415

What is the error message?

Can’t say with precision (see below)

What is the issue you’re encountering

I’m using Cloudflare in front of an API-providing Web-based service, and have done so for many, many years. Requests and replies are almost always in text/plain, possibly JSON, and even sometimes XML, depending on the service. This has worked reliably for years, but recents increases in CF’s protection measures have made all requests coming from Amazon AWS IP range to be protected via JavaScript-based CAPTCHA — which obviously an API client cannot produce. The rules I wrote to attempt to exclude my endpoint from CAPTCHAs seem to have no effect whatsoever. The vague references I read about “API Shield” and similar technologies are appropriate for Pro/Enterprise users, but not for Basic users. What is the workaround, sort of removing CF proxying for that specific domain name?

What steps have you taken to resolve the issue?

  • Added a Configuration Rule to turn off Browser Integrity Protection for that specific hostname
  • Added a Page Rule to turn off Browser Integrity Protection for all URLs starting with that hostname
  • On the API side and the client side, enforced text/plain as the MIME type for encoding and accepting, in the hope that CF’s systems understand that these requests are NOT to be subject to ‘Browser Integrity Protection’ since they obviously do NOT come from a browser!

I tried also to add a rule to exclude text/plain requests from being subject to BIP altogether (since I have several other APIs running under the same hostname, all of which presumably now being filtered out by BIP), but to no avail: without passing BIP at least once, the system will continue to assume it’s a request from a ‘suspicious’ network.
The only ‘workaround’, of course, is to disable CF proxying for that hostname.

Note: Currently this address is being actively used by API consumers; as such, since I don’t know any alternative, I have removed the address from CF proxying. I will shortly provide an alternative endpoint for testing purposes only, in the case that it might be useful.

Some references:

What are the steps to reproduce the issue?

You will need a client making an API request from a large pool of IP addresses which are often rotated/recycled among several different IP addresses — such as, in fact, anything on a cloud service. I have tested it with Amazon AWS, but hosting the client on any cloud should, in theory, exhibit the same issue.
Note that several tests I made on, say, bare metal servers with a fixed IP address and which have never been subject to ‘Browser Integrity Protection’, show that in such cases the API works exactly like intended (and like it did work for years).
The exact error is hard to figure out, since, in my case, clients are only able to retrieve the first 1000 bytes or so, and this hardly captures the whole BIP page. You can still see the ‘Just a moment…’ title on the header, though. But getting HTML when you asked for text/plain — and expected text/plain as a response — is a good sign that BIP is filtering the request and treating it as coming from a web browser on a ‘suspect’ ever-changing range of IP addresses (as, inevitably, almost all Cloud-base infrastructures will be these days, as well as most residential ones).

Check your security event log for the reason the request was challenged or blocked and then adjust rules as necessary…
https://dash.cloudflare.com/?to=/:account/:zone/security/events

If using Bot Fight Mode on a free plan you will probably need to disable it as WAF custom rules can’t skip that protection, or instead use Super Bot Fight Mode on a paid plan which can be skipped by WAF custom rules.

1 Like

Hmm.

I’m afraid I was a bit premature with my acceptance of your solution…

The truth is that no events show up on the event logs for that particular host/destination.

Which, in turn, means that I cannot confirm that any rule fired up to send a challenge to the client requesting an API call. As far as I can tell, none were fired.

This does not correspond with my experience. While it’s possible —not 100% certain, of course, just ‘possible’ — that the answer being given is not the HTML for the challenge, it certainly looks like it.

For the time being, I’m turning the CF proxying off… it’s the only way, thus far, that works around this issue…

Oh, and I forgot: as a basic user, I don’t have the Super Bot Fighter Mode available at all. All I can do is to enable or disable the Browser Integrity Protection. But, so far, I haven’t found a working configuration that actually disables it altogether…

I wonder, is there a way to know which rules have been triggered for each request, if any? Or is that what already happens with the zone events you mention? I can see all sorts of automatic challenges being triggered based on rules set up for, say, fail2ban, which I have configured from scratch… these are fine, and correspond correctly with my own server’s fail2ban logs.

Therefore, I do know that the overall concept works as intended; it just happens not to work for in practice

This host name is not being proxied by Cloudflare. Cloudflare rules can’t act on traffic that don’t pass through it’s edge.

Please… give me some credit here!.. Obviously I had to remove CF’s proxying, since that’s currently the only way I know of stepping around the issue. But it’s meant as a temporary kludge to prevent existing code that relies on that API endpoint to break :roll_eyes:

My hope was that this would be a simple question with a simple answer, e.g. “just turn X off” or “add a rule mentioning Y” or “make your server emit a special header for Cloudflare” or something basic like that. Apparently, it’s not that easy, or, if it is, so far, I couldn’t find any hints on what to search for…

I’d be more than glad to set up a new hostname which is proxied via CF to allow others to do experiments, though. I have at least another two (if not three) which I had to move out from CF’s proxying to be 100% confident that they would also work, but I’ll gladly add a new one if needed.

In fact, I might do that anyway, in order to avoid further confusions…