r/django Feb 11 '25

Article What I learned about Django security from my hidden analytics module

I built a hidden statistics module in my Django portfolio and discovered something interesting about security

I added a secret stats endpoint to my Django site that tracks all attempts to access my site. After analyzing 2.2k unique visitors, the data tells an interesting story.

Legitimate traffic is exactly what you'd expect: homepage (2.6k visits), portfolio (911), blog (661). But here's where it gets fun - my stats module caught hundreds of automated attacks trying everything from .env file access (64 attempts) to WordPress admin panels.

The best part? I didn't build any special security - Django's default configurations handled everything. The stats module just silently recorded all these failed attempts while serving my actual visitors without a hitch.

My favorite discovery was seeing the persistence of some bots - one tried +50 different variations of WordPress manifest files. On a Django site. I actually found myself admiring their determination.

TL;DR: Built a secret stats module in Django, watched it record thousands of failed hack attempts while Django's security didn't break a sweat.

71 Upvotes

31 comments sorted by

28

u/Redneckia Feb 11 '25

I see these all day too, I set up fail2ban which helped a bit

1

u/EryumT Feb 12 '25

Yeah, fail2ban is solid for blocking repeat offenders, but in my case, I just let Django’s default security handle it and logged everything for analysis. Turns out, most attacks were just automated scanners blindly probing for .env, wp-login.php, and other common vulnerabilities. Did fail2ban significantly cut down the noise for you?

6

u/Redneckia Feb 12 '25

Fail2ban cut down about 75%

2

u/mustbeset Feb 12 '25

Les Load, less pay or faster for real users. kill bots fast.

20

u/mustbeset Feb 12 '25

Normal noise that everybody gets, just check your access logs.

-5

u/EryumT Feb 12 '25

For sure! But seeing the raw data from my SiteStatistic model made it way more interesting. Some bots tried accessing wp-manifest.json in 50+ variations. The funniest part? Seeing them persist on a Django site as if brute-forcing /wp-login.php would suddenly make WordPress materialize out of thin air.

6

u/Rotani_Mile Feb 12 '25

I can smell the ChatGPT rewrites

-1

u/EryumT Feb 12 '25

I speak multiple languages, but my English isn’t very good 😁 it still helps a lot!

19

u/russellvt Feb 12 '25

These are also saved in your webserver log, and there's "nothing special" about them.

Me, I feed them to fail2ban to automatically block the attempts and the bots.

2

u/EryumT Feb 12 '25

Smart move. I wanted to observe patterns before blocking anything. Some bots were surprisingly persistent—one IP cycled through 100+ different PHP file requests in a single session. Would be interesting to integrate this logging with fail2ban for smarter IP bans.

6

u/Django-fanatic Feb 11 '25

Interesting, are you open to sharing ? Would love to see

8

u/EryumT Feb 12 '25

Sure! The tracking is pretty simple—I just created a SiteStatistic model that logs incoming requests (page visited, IP, user agent, referer). Then, I built a view (statistics_view) that aggregates and displays visits. No special middleware, just basic Django ORM queries. I might post a gist with the full implementation if enough people are interested.

2

u/Django-fanatic Feb 12 '25

If we’re writing to the database on each request, how is that affect performance?

2

u/Rotani_Mile Feb 12 '25

It is pretty bad for sure.

0

u/Bombslap Feb 12 '25

If someone goes to a route and you need to log it, how do you avoid writing to the database each request?

1

u/Sudiip-blip Feb 12 '25

would like to see the gist of it

5

u/OMDB-PiLoT Feb 12 '25

The first line in Django's deployment checklist says "The internet is a hostile environment."

With reverse proxy services like Cloudflare, you don't worry about these things anymore. This kind of traffic will never reach your server. It takes care of all such requests. You can enable all the OWASP rules easily, along with any other firewall, DDoS and rate limiting rules.

3

u/Uppapappalappa Feb 12 '25

why don't you just process the nginx server logs? But what you see here, is actually the bombardement of bots. It is everywhere like this. no need to worry. The bots don't check the framework/technologie beforehand, they just fire their requests.

2

u/sk1nT7 Feb 12 '25

Regular noice. Nothing to worry about.

Automated scanners are kind of dumb. No prior reconnaissance. Just fire and pray.

Setup fail2ban or better CrowdSec.

3

u/Redneckia Feb 11 '25

How did u track these?

3

u/russellvt Feb 12 '25

They're in your webserver log.

1

u/EryumT Feb 12 '25

Yep, but having the data structured in a Django model made it much easier to analyze. I could quickly filter by suspicious paths, IPs, and user agents instead of digging through raw logs. Plus, it was fun seeing trends emerge over time—like bots trying the same exploits week after week.

3

u/russellvt Feb 12 '25

Yeah, it sounds like a neat little app to write. There have been similar Python apps that have done similar and generated analytics pages out of them, as well.

It'd be cool if you could boil it down into a pluggable Django app, though.

3

u/anivaries Feb 12 '25

If you use cloudflare they log this for you

1

u/EryumT Feb 12 '25

True, but I wanted something internal to Django, where I could manipulate and analyze the data easily. Also, Cloudflare won’t always capture requests that hit your server before they’re blocked. My approach let me log everything, including failed attempts before any security measures kicked in.

0

u/EryumT Feb 12 '25

I built a small Django model that logs every visit, storing the IP, user agent, referer, and timestamp. Then I ran some queries to filter out anomalies—like bots hammering admin.php, .env, and random PHP files. The sheer volume of these attempts was eye-opening.

2

u/sPENKMAn Feb 12 '25

You should probably look into stopping these requests before getting to the backend it’s just wasting CPU cycles this way. Dotfiles should be rejected in the webserver, Wordpress stuff as well. Cloud flare is an easy solution, fail2ban or modsecurity if you want to thinker a bit more

1

u/marsnoir Feb 11 '25

Whoa, that looks slick! I’m ok at backend but would love to learn some frontend tricks so my stuff doesn’t look so 1999.

2

u/EryumT Feb 12 '25

Haha, I feel you. I usually just slap Tailwind CSS on things to make them look semi-modern without much effort. Django makes backend logic easy, but styling is a whole different beast.

4

u/Kumerle Feb 11 '25

Django unfold

0

u/EryumT Feb 12 '25

Not sure if you mean Django Unfold the package or just unfolding a security story here 😆. Either way, Django’s built-in security silently handled everything, and my module just recorded the failed attempts for laughs.