Someone has to make an effort at reconciliation if these conflicts are ever going to end.
In this release, we finally fix the odd number of CPU cores bug, pave the way for lighter weight challenges, make Anubis more adaptable, and more.
Big ticket items
Proof of React challenge
A new "proof of React" has been added. It runs a simple app in React that has several chained hooks. It is much more lightweight than the proof of work check.
Smaller features
- The
segments
function was added for splitting a path into its slash-separated segments. - Added possibility to disable HTTP keep-alive to support backends not properly handling it.
- When issuing a challenge, Anubis stores information about that challenge into the store. That stored information is later used to validate challenge responses. This works around nondeterminism in bot rules. (#917)
- One of the biggest sources of lag in Firefox has been eliminated: the use of WebCrypto. Now whenever Anubis detects the client is using Firefox (or Pale Moon), it will swap over to a pure-JS implementation of SHA-256 for speed.
- Proof of work solving has had a complete overhaul and rethink based on feedback from browser engine developers, frontend experts, and overall performance profiling.
- Optimize the performance of the pure-JS Anubis solver.
- Web Workers are stored as dedicated JavaScript files in
static/js/workers/*.mjs
. - Pave the way for non-SHA256 solver methods and eventually one that uses WebAssembly (or WebAssembly code compiled to JS for those that disable WebAssembly).
- Legacy JavaScript code has been eliminated.
- When parsing Open Graph tags, add any URLs found in the responses to a temporary "allow cache" so that social preview images work.
- The hard dependency on WebCrypto has been removed, allowing a proof of work challenge to work over plain (unencrypted) HTTP.
- The Anubis version number is put in the footer of every page.
- Add a default block rule for Huawei Cloud.
- Add a default block rule for Alibaba Cloud.
- Added support to use Traefik forwardAuth middleware.
- Add X-Request-URI support so that Subrequest Authentication has path support.
Fixes
Odd numbers of CPU cores are properly supported
Some phones have an odd number of CPU cores. This caused interesting issues. This was fixed by using Math.trunc
to convert the number of CPU cores back into an integer.
Smaller fixes
- A standard library HTTP server log message about HTTP pipelining not working has been filtered out of Anubis' logs. There is no action that can be taken about it.
- Added a missing link to the Caddy installation environment in the installation documentation.
- Downstream consumers can change the default log/slog#Logger instance that Anubis uses by setting
opts.Logger
to your slog instance of choice (#864). - The Thoth client is now public in the repo instead of being an internal package.
- Custom-AsyncHttpClient's default User-Agent has an increased weight by default (#852).
- Add option for replacing the default explanation text with a custom one (#747)
- The contact email in the LibreJS header has been changed.
- Firefox for Android support has been fixed by embedding the challenge ID into the pass-challenge route. This also fixes some inconsistent issues with other mobile browsers.
- The default
favicon
pattern indata/common/keep-internet-working.yaml
has been updated to permit requests for png/gif/jpg/svg files as well as ico. - The
--cookie-prefix
flag has been fixed so that it is fully respected. - The default patterns in
data/common/keep-internet-working.yaml
have been updated to appropriately escape the '.' character in the regular expression patterns. - Add optional restrictions for JWT based on the value of a header (#697)
- The word "hack" has been removed from the translation strings for Anubis due to incidents involving people misunderstanding that word and sending particularly horrible things to the project lead over email.
- Bump AI-robots.txt to version 1.39
- Inject adversarial input to break AI coding assistants.
- Add better logging when using Subrequest Authentication.
Security-relevant changes
- Add a server-side check for the meta-refresh challenge that makes sure clients have waited for at least 95% of the time that they should.
Fix potential double-spend for challenges
Anubis operates by issuing a challenge and having the client present a solution for that challenge. Challenges are identified by a unique UUID, which is stored in the database.
The problem is that a challenge could potentially be used twice by a dedicated attacker making a targeted attack against Anubis. Challenge records did not have a "spent" or "used" field. In total, a dedicated attacker could solve a challenge once and reuse that solution across multiple sessions in order to mint additional tokens.
This was fixed by adding a "spent" field to challenges in the data store. When a challenge is solved, that "spent" field gets set to true
. If a future attempt to solve this challenge is observed, it gets rejected.
With the advent of store based challenge issuance in #749, this means that these challenge IDs are only good for 30 minutes. Websites using the most recent version of Anubis have limited exposure to this problem.
Websites using older versions of Anubis have a much more increased exposure to this problem and are encouraged to keep this software updated as often and as frequently as possible.
Thanks to @taviso for reporting this issue.
Breaking changes
- The "slow" frontend solver has been removed in order to reduce maintenance burden. Any existing uses of it will still work, but issue a warning upon startup asking administrators to upgrade to the "fast" frontend solver.
- The legacy JSON based policy file example has been removed and all documentation for how to write a policy file in JSON has been deleted. JSON based policy files will still work, but YAML is the superior option for Anubis configuration.
New Locales
What's Changed
- build(deps): bump on-headers and compression in /docs by @dependabot[bot] in #910
- chore: expose thoth in lib by @Xe in #911
- test(lib): add a test for the X-Forwarded-For middleware by @Xe in #912
- build(deps): bump brace-expansion from 1.1.11 to 1.1.12 in /docs by @dependabot[bot] in #909
- test: add automated Pale Moon tests by @Xe in #903
- feat(expressions): add segments function to break path into segments by @Xe in #916
- feat(default-rules): add weight to Custom-AsyncHttpClient by @Xe in #914
- build(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #929
- fix(anubis): store the challenge method in the store by @Xe in #924
- build(deps): bump the gomod group in #931
- Update is.json by @sveinki in #935
- fix: polish Turkish translations by @bitigchi in #897
- fix(lib): add the ability to set a custom slog Logger by @Xe in #915
- fix: allow social preview images by @Xe in #934
- refactor(web): redo proof of work web worker logic by @Xe in #941
- Add HackLab.TO to known instances by @lillian-b in #936
- fix(web/sha256-browserjs): fix function name by @Xe in #943
- Add swedish local by @axellse in #913
- docs: remove JSON examples from policy file docs by @Xe in #945
- fix(internal): silence unsolicited response log lines by @Xe in #950
- fix(web): embed challenge ID in pass-challenge invocations by @Xe in #944
- build(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #952
- Revert "build(deps): bump the github-actions group with 2 updates" by @JasonLovesDoggo in #962
- Fix capitalisation in bokmål and nynorsk translations by @turtlegarden in #959
- Added Dutch translation by @SecularSteve in #937
- fix(localization): Improve Czech language translation by @Medvidek77 in #895
- feat(checker): allow png/gif/jpg/jpeg/svg favicons as well as ico by @arcayr in #961
- default pattern fixes by @arcayr in #963
- feat: support HTTP redirect for forward authentication middleware in Traefik by @phoval in #368
- Update known-instances.md: add lab.civicrm.org by @mlutfy in #971
- feat(lib): Add optional restrictions for JWT based on a specific header value by @Earl0fPudding in #697
- add Lithuanian locale by @rimas-kudelis in #972
- fix(locales): remove the word "hack" from the description of Anubis by @Xe in #973
- feat(web): Add option for customizable explanation text by @Earl0fPudding in #747
- Bump ai.robots.txt to v1.39 by @Dryusdan in #982
- feat(blog): add short funding update post by @Xe in #994
- fix(lib): ensure issued challenges don't get double-spent by @Xe in #1003
- fix(default-config): block Huawei Cloud by @Xe in #1004
- fix(default-config): also block alibaba cloud by @Xe in #1005
- Update installation.mdx to include a link to the Caddy docs by @juliankrieger in #993
- s/Wordpress/WordPress in docs by @bradp in #1020
- docs: fix "stored" typo in CHANGELOG.md by @Krinkle in #1008
- lib/checker: Implement X-Original-URI support by @samip5 in #1015
- Add XOriginal to allowed words by @JasonLovesDoggo in #1031
- build(deps-dev): bump the npm group across 1 directory with 3 updates by @dependabot[bot] in #1032
- fix(worker): constrain nonce value to be a whole integer by @Xe in #1045
- fix: middleware traefik redirect url by @phoval in #1040
- docs(blog): add post about the odd CPU core count bug by @Xe in #1058
- docs: Fix broken link by @phuzion in #1059
- Allow to disable keep-alive for the targets not supporting it properly by @samm-git in #1049
- Alienbob: add Slackware URLs that are now protected by Anubis by @alienbob in #1051
- docs: document client IP headers and interop with cloudflare by @TinyServal in #1034
- Update nginx.mdx - needs port_in_redirect off setting by @own3mall in #1018
- internal/log: Implement logging of HOST when using subrequest auth by @samip5 in #1027
- feat: add 'proof of React' challenge by @Xe in #1038
- add Lithuanian locale by @rimas-kudelis in #998
- chore: introduce issue templates by @Xe in #939
- feat(localization): Add Vietnamese translation by @ninfia in #926
- fix(challenge/metarefresh): ensure that clients have waited long enough by @Xe in #1068
- ci: fix tests by @Xe in #1069
- chore: break AI agents in this code tree by @Xe in #1065
- Updates to lt.json by @rimas-kudelis in #1075
- test: ensure FORCED_LANGUAGE works by @Xe in #1083
- feat: glob matching for redirect domains by @Xe in #1084
New Contributors
- @bitigchi made their first contribution in #897
- @lillian-b made their first contribution in #936
- @axellse made their first contribution in #913
- @SecularSteve made their first contribution in #937
- @Medvidek77 made their first contribution in #895
- @arcayr made their first contribution in #961
- @phoval made their first contribution in #368
- @mlutfy made their first contribution in #971
- @rimas-kudelis made their first contribution in #972
- @juliankrieger made their first contribution in #993
- @bradp made their first contribution in #1020
- @Krinkle made their first contribution in #1008
- @samip5 made their first contribution in #1015
- @phuzion made their first contribution in #1059
- @samm-git made their first contribution in #1049
- @alienbob made their first contribution in #1051
- @TinyServal made their first contribution in #1034
- @own3mall made their first contribution in #1018
- @ninfia made their first contribution in #926
Full Changelog: v1.21.3...v1.22.0