{"id":21814333,"url":"https://github.com/snawoot/httptrap","last_synced_at":"2025-04-13T23:46:28.298Z","repository":{"id":57570786,"uuid":"254820583","full_name":"Snawoot/httptrap","owner":"Snawoot","description":"Web-server which produces infinite chunked-encoded responses to slowdown malicious clients","archived":false,"fork":false,"pushed_at":"2021-06-10T10:32:04.000Z","size":28,"stargazers_count":21,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-27T13:51:23.000Z","etag":null,"topics":["ddos-mitigation","filter","filtering","http-flood","http-server","security","webserver"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Snawoot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-11T08:02:14.000Z","updated_at":"2024-11-24T19:20:31.000Z","dependencies_parsed_at":"2022-08-28T18:23:56.281Z","dependency_job_id":null,"html_url":"https://github.com/Snawoot/httptrap","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snawoot%2Fhttptrap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snawoot%2Fhttptrap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snawoot%2Fhttptrap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snawoot%2Fhttptrap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Snawoot","download_url":"https://codeload.github.com/Snawoot/httptrap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248799697,"owners_count":21163398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ddos-mitigation","filter","filtering","http-flood","http-server","security","webserver"],"created_at":"2024-11-27T14:37:47.656Z","updated_at":"2025-04-13T23:46:28.275Z","avatar_url":"https://github.com/Snawoot.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"httptrap\n========\n\n[![httptrap](https://snapcraft.io//httptrap/badge.svg)](https://snapcraft.io/httptrap)\n\nWeb-server which produces infinite chunked-encoded responses. It's intended to be a part of active defense against malicious HTTP clients to cancel their load impact and/or bruteforce efforts. Depending on settings, httptrap may keep busy most of attacker's resources, diverting them to wait slowly fed infinite response, or cause often OOM and botnet payload crash if httptrap sends response as fast as possible and client uses RAM to buffer entire response.\n\n---\n\n:heart: :heart: :heart:\n\nYou can say thanks to the author by donations to these wallets:\n\n- ETH: `0xB71250010e8beC90C5f9ddF408251eBA9dD7320e`\n- BTC:\n  - Legacy: `1N89PRvG1CSsUk9sxKwBwudN6TjTPQ1N8a`\n  - Segwit: `bc1qc0hcyxc000qf0ketv4r44ld7dlgmmu73rtlntw`\n\n---\n\n## Why?\n\nWhy just not collect attackers IP addresses and ban them? Or maybe even automate this process and establish it on ongoing basis?\n\nFiltering approach has some drawbacks:\n\n* It prevents access of legitimate users who share IP address with attacker (e.g. common ISP NAT gateway, compromised devices in network, common proxy or TOR exit node and so on). Consequently, it gives attacker an additional power to cut someone's access from service if one will manage originate flood traffic from same IP. Slowdown approach is more gentle and capable to not impact correct requests from legitimate users.\n* Filtering may have lower stopping power if attacker posesses a huge pool of source addresses. In fact, if pool is sufficiently large and it's full rotation period is longer than IP cooldown time, attackers may conduct their activities continously, without downtimes.\n\n## Installation\n\n#### Pre-built binaries\n\nPre-built binaries available on [releases](https://github.com/Snawoot/httptrap/releases/latest) page.\n\n#### From source\n\nAlternatively, you may install httptrap from source:\n\n```\ngo get github.com/Snawoot/httptrap\n```\n\n#### From Snap Store\n\n[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/httptrap)\n\n```sh\nsudo snap install httptrap\n```\n\n#### Docker\n\n```sh\ndocker run -it --rm -p 8008:8008 yarmak/httptrap\n```\n\n## Use Case\n\nConsider following example. We have some web application which suffers from HTTP request flood or authorization bruteforce attempts. In this example such application represented by Python script [demo/webapp.py](demo/webapp.py). It serves HTTP requests on port 8080 and it is exposed to the outer world via nginx reverse proxy with simple server configuration section like this one:\n\n```nginx\n    server {\n        listen       80 default_server;\n        listen       [::]:80 default_server;\n        server_name  _;\n\n        location / {\n            proxy_pass http://127.0.0.1:8080;\n        }\n\n        error_page 404 /404.html;\n            location = /40x.html {\n        }\n\n        error_page 500 502 503 504 /50x.html;\n            location = /50x.html {\n        }\n    }\n\n```\n\nWeb application greets users which passed authorization:\n\n```\n$ curl -d 'login=admin\u0026password=12345678' -D- http://localhost/\nHTTP/1.1 200 OK\nServer: nginx/1.16.1\nDate: Sat, 11 Apr 2020 21:08:31 GMT\nContent-Type: text/plain\nTransfer-Encoding: chunked\nConnection: keep-alive\n\nYou are in!\n```\n\nAnd it rejects unauthorized requests:\n\n```\n$ curl -d 'login=admin\u0026password=badpass' -D- http://localhost/\nHTTP/1.1 403 Forbidden\nServer: nginx/1.16.1\nDate: Sat, 11 Apr 2020 21:10:17 GMT\nTransfer-Encoding: chunked\nConnection: keep-alive\n\n```\n\nLet's model bruteforcer or flooder with Apache Benchmark `ab` utility:\n\n```\n$ time ab -c 50 -t 30 -s 5 -r -p post_data_bad.txt http://localhost/\nThis is ApacheBench, Version 2.3 \u003c$Revision: 1843412 $\u003e\nCopyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\nLicensed to The Apache Software Foundation, http://www.apache.org/\n\nBenchmarking localhost (be patient)\nCompleted 5000 requests\nCompleted 10000 requests\nCompleted 15000 requests\nCompleted 20000 requests\nCompleted 25000 requests\nCompleted 30000 requests\nCompleted 35000 requests\nFinished 39821 requests\n\n\nServer Software:        nginx/1.16.1\nServer Hostname:        localhost\nServer Port:            80\n\nDocument Path:          /\nDocument Length:        0 bytes\n\nConcurrency Level:      50\nTime taken for tests:   30.000 seconds\nComplete requests:      39821\nFailed requests:        0\nNon-2xx responses:      39821\nTotal transferred:      4141384 bytes\nTotal body sent:        6179850\nHTML transferred:       0 bytes\nRequests per second:    1327.36 [#/sec] (mean)\nTime per request:       37.669 [ms] (mean)\nTime per request:       0.753 [ms] (mean, across all concurrent requests)\nTransfer rate:          134.81 [Kbytes/sec] received\n                        201.17 kb/s sent\n                        335.98 kb/s total\n\nConnection Times (ms)\n              min  mean[+/-sd] median   max\nConnect:        0    0   0.1      0       4\nProcessing:     1   19 209.2      4   27422\nWaiting:        0   19 209.2      4   27422\nTotal:          1   19 209.2      4   27422\n\nPercentage of the requests served within a certain time (ms)\n  50%      4\n  66%      5\n  75%      5\n  80%      6\n  90%      7\n  95%      9\n  98%     13\n  99%   1014\n 100%  27422 (longest request)\n\nreal\t0m30,046s\nuser\t0m0,521s\nsys\t0m2,058s\n```\n\nTest lasted 30 seconds and allowed attacker to probe almost 40000 accounts (for purposes of discussion we omit that fact `ab` probed same single login and password pair). Obviously, Python server process hit 100% CPU limit during test, illustrating load impact caused by request flood.\n\nAnd here is how we can derail such attacks without restrictions to normal users.\n\nLet's add few lines to our nginx config so it'll be looking like this:\n\n```nginx\n    server {\n        listen       80 default_server;\n        listen       [::]:80 default_server;\n        server_name  _;\n\n        location / {\n            proxy_intercept_errors on;\n            proxy_pass http://127.0.0.1:8080;\n        }\n\n        error_page 404 /404.html;\n        location = /40x.html {\n        }\n\n        error_page 500 502 503 504 /50x.html;\n        location = /50x.html {\n        }\n\n        error_page 454 = @trap;\n        location @trap {\n            internal;\n            proxy_pass http://127.0.0.1:8008;\n            proxy_buffering off;\n        }\n    }\n```\n\nNamely, we've enabled error interception from backend responses and added named internal location which redispatches request to httptrap server. `error_page 454 = @trap` directive binds this internal location to HTTP response code 454. Now it is sufficient for backend to respond with HTTP code 454 and client will be dumped to endless response backend.\n\nIt's up to backend server how to identify malicious clients which should be locked out. It's possible to use complex behavior analysis or per-IP statistics - everything what fits your case. In our example web application uses simple stateless logic: 1% of requests which failed authorization responded with HTTP 454 error code and consequently redispatched to slow stream server. This way bruteforcers eventually will hit httptrap server. Let's see what impact such policy has on attacker:\n\n```\n$ time ab -c 50 -t 30 -s 5 -r -p post_data_bad.txt http://localhost/\nThis is ApacheBench, Version 2.3 \u003c$Revision: 1843412 $\u003e\nCopyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\nLicensed to The Apache Software Foundation, http://www.apache.org/\n\nBenchmarking localhost (be patient)\n^C\n\nServer Software:        nginx/1.16.1\nServer Hostname:        localhost\nServer Port:            80\n\nDocument Path:          /\nDocument Length:        0 bytes\n\nConcurrency Level:      50\nTime taken for tests:   368.656 seconds\nComplete requests:      4565\nFailed requests:        0\nNon-2xx responses:      4565\nTotal transferred:      499165 bytes\nTotal body sent:        715325\nHTML transferred:       18305 bytes\nRequests per second:    12.38 [#/sec] (mean)\nTime per request:       4037.849 [ms] (mean)\nTime per request:       80.757 [ms] (mean, across all concurrent requests)\nTransfer rate:          1.32 [Kbytes/sec] received\n                        1.89 kb/s sent\n                        3.22 kb/s total\n\nConnection Times (ms)\n              min  mean[+/-sd] median   max\nConnect:        0    0   0.3      0       4\nProcessing:     1   32 352.2      3    7657\nWaiting:        0   32 352.2      3    7657\nTotal:          1   33 352.3      3    7659\n\nPercentage of the requests served within a certain time (ms)\n  50%      3\n  66%      4\n  75%      5\n  80%      5\n  90%      7\n  95%     10\n  98%     15\n  99%   1023\n 100%   7659 (longest request)\n\nreal\t6m8,670s\nuser\t0m0,140s\nsys\t0m0,438s\n```\n\n`ab` was started with 50 threads, 30 seconds total time limit and 5 second timeout per request. However, it didn't even completed at all: It made less than 5000 requests until all workers were locked out. It took 11 seconds till `ab` hang completely and after 6 minutes it was killed manually. Note that five second network operation timeout doesn't actually helps here because httptrap server feeds data continously, avoiding client timing out and leaving. All the time during test application was available to legitimate users, no per-address restrictions were imposed.\n\n## Synopsis\n\n```\n$ ./httptrap -h\nUsage of ./httptrap:\n  -bind string\n    \tlisten address (default \":8008\")\n  -cert string\n    \tenable HTTPS and use certificate\n  -ct string\n    \tContent-Type value for responses (default \"text/html\")\n  -interval duration\n    \tinterval between chunks (default 1s)\n  -key string\n    \tkey for TLS certificate\n  -string string\n    \thex-encoded representation of byte string repeated in responses (default \"0a\")\n  -verbosity int\n    \tlogging verbosity (10 - debug, 20 - info, 30 - warning, 40 - error, 50 - critical) (default 20)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnawoot%2Fhttptrap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnawoot%2Fhttptrap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnawoot%2Fhttptrap/lists"}