Forums

Block Inbound Connections

Hi,

How can I limit the ip ranges from which I accept incoming connections?

Thanks!

You can, but you'd have to code it manually. The external IP address is stored in the header; more information on this help page.

PythonAnywhere staff -- is there any facility for blocklisting at a lower level, e.g. nginx? I would really like to see that.

For mitigating against DOS/DDoS attacks, doing this at the application server layer is usually too slow. Nginx is orders of magnitude faster.

-- Signed, veteran of a DDoS attack involving several thousand IPs, several million requests, and a request signature that was easy to block with a one-line rule in nginx.conf.

We do not expose that layer of configuration to users.

I understand you don't currently offer this. As a paying user, I'm asking for the functionality.

You don't let me run crontab -e either, but that's OK because you provide a workable front-end for periodic jobs.

In the DDoS incident I mentioned, my first attempt at mitigation was at the application level as you suggest above, and it was utterly insufficient.

If you aren't up for giving users ability to tweak nginx.conf, how about adding one of the following to the webapps screen?

  • a field for a user-provided list of IPs/subnets to block

  • optional specific block lists to activate, e.g. the Barracuda Reputation Block List

  • an option to turn on fail2ban for dynamic rate-limiting/banning

I look forward to your response.

Ok. Thanks for the suggestion. I've added it to our issue tracker.

Thanks!

Just reiterating my request for this feature. My application-level blocklist is at 134 IPs and rising.

I don't suppose there's a public link to that issue in the PA issue tracker?

Noted. We do not have public access to our issue tracker.

Hi PA team, follow-up to the request from paulbissex, is there any update to the ability to run fail2ban or equivalent on PA web apps?

No update

I've developed a couple application-level solutions for this in the meanwhile. If you're using Django, check them out:

Thanks, paulbissex. One of our apps is Django, so will take a look. Others are Flask.

Glenn, as a paying user since 2018, that is honestly quite a disappointing response, after >18 months. Can I take it then that this is not prioritised?

It's not prioritised in the way that there are issues with more upvotes from the users (like enabling ASGI), but it is on our to-do list along with several thousands of other good ideas on how to improve the UX.

How does your upvoting system take into account the implicit weight of security-related requirements, particularly those that are actually recommended by official bodies - e.g. the UK NCSC's latest recommendations for infrastructure, which talks about rate-limiting as a means of defending against brute force attacks (see https://www.ncsc.gov.uk/files/Cyber-Essentials-Requirements-for-IT-infrastructure-3-0.pdf).

My concern is that potentially these standards will never be that attractive or obvious or important to hobby developers (over something more exciting like ASGI), but as an organisation, we actually want to (and in some cases need to) achieve these standards.

Security-related stuff does get a higher priority, certainly. But rate-limiting at the PythonAnywhere platform level is never going to be enough to realistically mitigate against brute-force attacks -- we don't have enough information to know what a reasonable rate limit is. For example, you might have one endpoint that you expect people to hit frequently because it's serving up normal data, while you might have others (say, your login page) where you don't want the same IP to be able to hit it more than a few times a minute.

If you want to write a secure site, you'll need to implement it in your own code, perhaps by using the packages that @paulbissex wrote.

All we can do is try to help mitigate DDoSes; we currently do that in cases where they are causing broader system issues because then we can identify IPs hitting multiple sites and block them.

Thanks, Giles. Appreciate the response. I'm not sure that a "roll your own" approach is what is really recommended, above using something battle-tested, but I will look into it. Thanks!

Agreed re: a roll-your-own approach -- if you're using Django or Flask, though, you can use plugins that other people have written in order to handle the rate-limiting yourself, but then configure the rate limits based on your own site's requirements. For example, we use the django-ratelimit package, so on our login view we have a number of decorators like this:

@ratelimit(key="post:auth-username", rate="XXXX/YYYYm", method=ratelimit.UNSAFE, block=True)

...which says that we only allow XXXX logins per YYYY minutes for a particular username. By contrast, we have a much looser rate-limit on other pages.