It took a year to ship WebAssembly in Anubis (anubis.techaro.lol)

280 points by xena 14 hours ago

vintagedave 13 hours ago

> In my experience the kinds of people who run this exact combination of circumstances also tend to be the kind of people that have a wide variance in the level of kindness they display to the authors of open source programs that happen to be in their way.

Love this. There’s been past discussion on HN re how OSS maintainers are treated, and this is such a wry sentence. I really appreciate the tone / attitude to the problem.

skrebbel 3 hours ago

Can you translate the American for me? “Wide variance”, does that they’re being assholes?

st_goliath 26 minutes ago

> Can you translate the American for me?

I'd say "wide variance in the level of kindness" is a rather British way to describe some of the opinions that have been voiced.

afavour 3 hours ago

Well a little translation would be that some are very kind, some are total assholes, and everything in between. But your reading is probably more accurate.

strken 3 hours ago

skrebbel 3 hours ago

doctor_radium 8 hours ago

I have every copy of Firefox here configured with webassembly disabled...because I don't tend to do what Webassembly was designed for, i.e. online games, video/audio editing, emulation, etc. [1] and because I dislike things running in the background without my knowledge.

So this is going to be interesting.

My plea (in a small voice) to the OP: just as many sites still do for JavaScript, please add a "This captcha required Webassembly to continue" message to your code when Webassembly is disabled. And, incidentally, for smaller platforms/browsers that don't offer a Webassembly engine at all.

[1] https://webassembly.org/docs/use-cases/

evnp 7 hours ago

The second half of this post chronicles the author's Herculean efforts to make everything work well in the cases you describe.

> One of the big things that blocked this shipping for so long was not having an escape hatch of some kind to allow clients that disable WebAssembly by policy to get through the gate. [...] This combination of factors means that there would need to be another implementation of the proof of work code in JavaScript that would actually execute the number crunching.

doctor_radium 5 hours ago

Thanks. You're right; it was a very thorough article and I trailed off about halfway through. I still say there are many improper uses of Webassembly out there, but I credit the developer for a highly thoughtful approach to the project. I really wonder if Cloudflare et al. does as much due diligence?

swiftcoder 2 hours ago

> because I dislike things running in the background without my knowledge

Point of order: WASM doesn't let things run in the background. To do that you need WebWorkers (a javascript feature, not WASM-specific).

noduerme 2 hours ago

It's amusing (although disheartening to me as someone who builds online games) that wasm is now being treated like a flash plugin by sysadmins. You're not entirely wrong, but it's just funny to me that we took a full ten years to get back to roughly the same place. Now with Ruffle running Flash in wasm, no less! We build shit that doesn't work in the DOM, search engines hate it, walled gardens try to block it, admins fear it, they shut it down and the whole thing starts over.

xena 6 hours ago

I don't mean to be rude, but please search "wasm2js" in the article.

jonkoops 3 hours ago

I really don't see why you'd disable WebAssembly and allow JavaScript instead. Expecting developers to make a fallback for a baseline-supported feature for any reason but backwards compatibility with runtimes that do not so support WASM is extremely silly.

well_ackshually 3 hours ago

"I disable things and expect others to do things for me, in their own time, without being paid, to bring solutions to my paranoia"

You do see how selfish it is, right? While the author did introduce such a solution, it's such a massive waste of time.

kccqzy 12 hours ago

Hats off to Xe for spending so much time on backwards compatibility, especially the tidbit about targeting Chrome 66.

I have a Mac from 2014 running Yosemite that I occasionally use to test for backwards compatibility in my own frontend code (for fun!). But IMO the best way to ensure compatibility is to use period-correct toolchains or toolchains where the pace of change is slower, like ClojureScript.

nxobject 7 hours ago

In the non-webdev realm, it's gobsmacking that you can put "FROM debian/eol:buzz" in a Dockerfile, and it will do what it says...

Aachen 13 hours ago

Is there a place where I can try out if my browser is compatible? Easier to find out now than when I'm trying to get work done and a million websites now have it deployed

On https://wasm-feature-detect.surma.technology it shows that I don't have 3 of all these features but I'm not sure if Anubis needs any of them to not kick me back to the pure JS solution

Which would apparently be bad because

> The WebAssembly that's shipped with this flow is ridiculously performant. This may mean you need to adjust the difficulty [upward, to avoid that bots solve it trivially when they support wasm, I assume this means]

combined with

> The wasm2js flow doesn't currently have a way to update the progress bar [so you have no clue about remaining time]

(wouldn't be the first time that I gave up on a page because it was stuck on 0 hashes per second)

adrian17 2 hours ago

> something I was doing with my "strict MVP" build of Anubis' WASM wasn't in fact sticking to just the MVP features of WebAssembly

Fun fact, this _used_ to be the case - wasm32-unknown-unknown had extra non-mvp features added later, which in my eyes has been a breaking change on stable. You're not the first person to have been bitten by this, there's [1] and a similar story in Ruffle [2].

Weirdly, the response from the rustc side (IIRC we also talked with one of the devs of wasm component on discord a bit around 2024) has contained a lot of (paraphrasing) "in retrospect we think wasm32-unknown-unknown target was designed badly*, so we'd prefer if you either dealt with it or switched to another wasm target <with its different set of downsides> than us fixing it". (*I acknowledge that the way std was implemented on that target was unusual and "not clean", but it works _really well_ for a lot of people.)

> I looked into the process involved for rebuilding the standard library twice: once with only MVP wasm features enabled and once with an "all yes config" like usual. Based on some research I did this seemed like a massive pain.

That's what Ruffle does [3], it's a bit unfortunate but wouldn't call it a massive pain.

[1] https://internals.rust-lang.org/t/can-we-have-either-a-new-t...

[2] https://github.com/ruffle-rs/ruffle/pull/18397

[3] See lines 55 and 117-127 in https://github.com/ruffle-rs/ruffle/blob/6890c618daab3153343...

JoshTriplett an hour ago

> Weirdly, the response from the rustc side (IIRC we also talked with one of the devs of wasm component on discord a bit) has contained a lot of (paraphrasing) "in retrospect we think wasm32-unknown-unknown target was designed badly, so we'd prefer if you either dealt with it or switched to another wasm target <with its different set of downsides> than us fixing it". (I acknowledge that the way std was implemented on that target was unusual and "not clean", but it works _really well_ for a lot of people.)

That's about right. Specifically, wasm32-unknown-unknown is serving multiple targets, which aren't very compatible, and it implements std by panicking in all the bits that can't work.

One target is "you truly have absolutely nothing, and don't really have much of `std` at all". Another target is "you're in a browser, and can do anything a typical browser can provide" (ideally targeting the future where wasm has full browser APIs without going through javascript). Another target is "hosted environment that isn't a browser, and which capabilities you have depends on the environment". Those are three very different things.

I would argue that we need at least two new targets, possibly three:

- `wasm32-none` or similar (by analogy with `x86_64-unknown-none`), a target where you don't have anything except for what you bring with you. The equivalent of writing kernel code.

- `wasm32-wasi-hosted` (or pick another name), where you the hoster of the wasm can supply whatever capabilities you have available.

- `wasm32-wasi-browser`.

It's possible that `none` could be a special case of `hosted`, where the services you provide are "none".

Georgelemental 9 hours ago

You can use Rust's `wasm32v1-none` target to get baseline WASM with no extra target features. (This restricts you to `#[no_std]`, however.) https://doc.rust-lang.org/rustc/platform-support/wasm32v1-no...

0x696C6961 14 hours ago

It would be cool if the POW could be done ahead of time. That way I don't get stuck waiting while I'm working. Some type of credit/tokens that my browser could then spend.

xena 14 hours ago

I'm working on this with a private prototype. I'm probably going to lean towards using a Service Worker (https://developer.mozilla.org/en-US/docs/Web/API/Service_Wor...) to renew challenges at a reduced difficulty. Stay tuned!

gruez 13 hours ago

That just creates another problem: if you're taking any measures to reduce tracking (ie. clearing cookies on shutdown or using temporary containers), this won't work. If anubis was being deployed on a site that a user visits often (eg. HN), the user might be convinced to whitelist it, but most anubis deployments are on random blogs or fediverse instances that I might not visit again in months. I'm certainly am not going to whitelist those sites, nor am I going to enable cookies wholesale just to avoid solving challenges.

xena 11 hours ago

lxgr 13 hours ago

Or something that shadier websites could calculate ahead of time in your browser, then spend on your behalf.

I feel like Anubis is ironically speedrunning a lot of discoveries the crypto folks have already made several years ago...

Terr_ 4 hours ago

What if the work output was bound to a particular source IP? That'd stop most "theft" at the expense of discards when your device switches networks.

xena 4 hours ago

tomodachi94 11 hours ago

Privacy Pass does something similar to what you describe: https://developers.cloudflare.com/waf/tools/privacy-pass/

packetlost 13 hours ago

I wonder if you could convince the Anubis author to implement x402 payments to bypass the PoW

JsonCameron 9 hours ago

This could be done at the web server level, not requiring changes to Anubis

dist-epoch 13 hours ago

Then we could implement an exchange, so that if you generate too much Anubis POW, you could exchange it with others.

We could link it to a site, you generate for HN, I for Reddit, but it so happens that you visited Reddit more and I HN, so we depleted our Anubis POW, so we could exchange some Reddit Anubis with some HN Anubis.

ssl-3 13 hours ago

And then, we can inextricably link it to a new cryptocurrency -- let's call it BotCoin -- and make Sam Altman pay for it!

kelvinjps10 13 hours ago

Basically reinventing crypto one step at the time.

omoikane 12 hours ago

> This means that adding one (1) to the difficulty of a challenge makes it 1024 (one thousand twenty-four) times as hard to solve in the worst case.

I don't understand the units here, wouldn't a bit versus nibble difference make the multiplier 16, instead of 1024?

xena 12 hours ago

Oops, there's your proof I didn't write this with AI! Fixing, sorry.

miraline 12 hours ago

The interesting part is that bots mitigation is actually an economic problem. You don't need to make scraping impossible, you only need to just make it expensive enough so that abusive traffic stops being worth it.

mitxela 12 hours ago

Scrapers scrape all sorts of nonsense, notably every possible git diff from git hosts. They clearly aren't concerned with rationality.

XorNot 11 hours ago

Scrapers scrape every link they can find.

The git host example is probably the one which Anubis is the dumbest defense for: the main reason to have those links is for easy machine interaction. So that's dead when you implement it.

So why even host the links? It's a git repo: send them a local got client and let them clone the repo in browser or something.

mitxela 11 hours ago

utopiah 4 hours ago

dspillett 9 hours ago

> It also means that the "hey Claude vibeslop me a CUDA Anubis solver" route is on its way to being fundamentally dead.

I assume that the previous challenges will still be available for circumstances where WASM is not available (unless we are just working on the basis that it is available if JS is?) or perhaps as a fallback. TFA explicitly mentions “smart” TVs, and I'm sure there are plenty of those out there that run browsers old enough to not know what WASM is. TBH these would not be a priority for me, but they obviously are for this project given they (well, TVs generally, not specifically elderly ones) get specific mention in this write-up.

If so, what is to stop scrapers from just forcing the fallback POW option instead of trying to run the new memory-hard algorithm at all?

Lyrex 8 hours ago

the answer to this is in the post: where wasm is not available, he transpiles the wasm binary back to Javascript

dspillett 7 hours ago

Ah I must have skipped by that bit. And presumably the memory-hard algorithm is CPU-easy enough that this won't be a problem. That leaves me wondering "why not just use a JS memory-hard routine in the first place, but maybe I've shouted over that too. I'll give TFA a reread later.

trickypr 6 hours ago

tyre 6 hours ago

tangential fyi: the author is not a he

arjie 13 hours ago

Anubis is fine if you want to block bots that are bothering you, but I never understood why they don't have robots.txt at the root level too. I happily obey that for my private crawler. I suppose you don't want to duplicate implementations. Fair enough. I guess I should add an Anubis detector so I can just blacklist because that person clearly doesn't want bots.

mitxela 12 hours ago

In this day and age, only good bots, the ones you actually want, obey robots.txt. You obtain no benefit by having a restrictive one.

arjie 11 hours ago

That is true, but if you have Anubis you presumably do intend to `Disallow` all bots.

xena 13 hours ago

One of the standard library rules enables robots.txt passthrough by default. I can't control people not choosing to use it.

arjie 11 hours ago

That makes sense, Xe, but you don't enable it at:

- https://techaro.lol/robots.txt

- https://anubis.techaro.lol/robots.txt

and the latter (at least) is Anubis protected. It could be just an omission. But if it's intentional, I am just curious why so that as a bot author I can be well-behaved.

andai 6 hours ago

Tangential but all the pages I see protected by Anubis are just static HTML. But bot traffic is only harmful on dynamic pages right?

JodieBenitez 6 hours ago

I'm not a fan of Anubis for various reasons but the idea that bot traffic in only harmful with dynamic pages must die. CPU (yes, even to serve static pages) is not free, bandwidth is definitely not free. There's an idea that serving a static page to a bot has a marginal cost tending to zero, but it's never really zero and serving them by millions definitely has a cost.

Also, while some pages may look like static HTML pages, they may be generated on the fly by an expensive and/or slow backend, which adds to the cost. I happen to maintain servers for academics and some content management systems are slow and have an expensive CPU cost. While it's OK for the low number of humans interested in the subjects they deal with, it's definitely not fit for massive bot scrapping. And before you ask, no, it's not always practical to have cache upfront or to pre-generate all pages.

arcfour 4 hours ago

There are numerous services that will let you host static pages for free or nearly free. There are also numerous services that sit in front of your website that can block bots and reduce load on your origin server, many of which are also free, or very low cost relative to the service they provide.

The situation you are in is far less dire sounding when you consider that you have these options available to you.

JodieBenitez 3 hours ago

Nnnes 2 hours ago

Others have answered your question. A lot of the sites listed here https://anubis.techaro.lol/docs/user/known-instances/ have dynamic content; Git web interfaces in particular (Codeberg, the Linux kernel, FFMPEG, and more are on the list) are vulnerable to poorly or maliciously configured scrapers.

jeroenhd 5 hours ago

Shitty scrapers hitting images over and over again is also a problem. Not just /pic/1.webp - /pic/2.webp, but in practice I've seen three AI scrapers that would request things like /pic/1.webp?version=webp&foo=bar and other random query parameters that none of my domains even use. It's just stuck brute-forcing files or something, sucking up loads of bandwidth downloading the same image for no reason.

It also depends on if you want your content to be scraped. Any bot ignoring robots.txt should be considered potentially malicious and worth considering such mechanisms for.

trickypr 6 hours ago

The anubis docs website is used as an example of how anubis works.

Also, if you are not using a big CDN (e.g. Cloudflare), you still need to pay for the traffic (even if you don't pay as much for the CPU). This is doubly true for smaller CDNs like Bunny.

xena 6 hours ago

Not only is it an example, it specifically is one of the first things I use to test experimental features so I get data back instantly.

tyre 6 hours ago

some people don't want to be scrapped at all, and most bots ignore `robots.txt`

kiicia 4 hours ago

no, absolutely not, any malicious or dishonest bot traffic is harmful, generating unnecessary transfer and literally stealing data

tefkah 12 hours ago

thanks for trying to make the web suck a little less these days xena!

evmar 12 hours ago

I think the Rust feature you’re looking for regarding recompiling the standard library is called “build-std”, that should be enough for you to search for it. (For similar reasons you also need that flag if you are trying to use Rust to build multithreaded wasm binaries, so it might come up for you!)

jezek2 11 hours ago

Great article, WebAssembly is such a good technology when you have use case for it.

I've just finished creating a WASM 1.0 implementation (simple JIT on x86 and x86_64) for plugin usage and I'm looking on how to support more languages beyond C (for which I have "micro-libc" to create really small binaries). In particular C++ and Rust so the article contains useful info for that. C++ that would be more problematic I think, would have to resort to full Emscripten or something... I've tried to compile standalone C++ stdlib but wasn't much sucessful yet.

BTW, I see in the screenshots you also test Firefox, I think it would make sense to test the latest two ESR versions (these are often used by Linux distributions).

Dwedit 5 hours ago

How much data does it download off the server to run the challenge? I've made some tiny webassembly binaries before, but I've never seen Rust generate something tiny.

xena 5 hours ago

It's in the range of 32-40Ki before compression. After compression it gets to be completely negligible.

raincole 13 hours ago

It's still very unclear to me how Anubis is supposed to work in the long term or even the medium term. The assumption is that scrappers, a.k.a. AI companies, a.k.a. those who hog all the RAM, are short of memory...?

solid_fuel 13 hours ago

The assumption is that requiring 1 second of compute before allowing a page load will have more impact on the people requesting 1000 pages/sec than it will on consumers requesting 1 page every minute.

Personally I don’t understand where this confusion comes from - it’s a simple economic tactic. Yes the large scale scrapers won’t run out of compute but putting anubis in front of a website demonstrably reduces the amount of crawling and that is the entire goal.

Aachen 13 hours ago

> requiring 1 second of compute before allowing a page load

After 1 solve, you get a cookie and can load tons of pages with it. Scrapers and user agents alike will need to spend the compute only once to get a valid session for themselves

Seems to be working so far though. Fwiw, lots of silly things stop bots until someone puts their mind (or tokens) to bypassing it, and then the blocking mechanism has to adapt. We'll see how it plays out, for now it's a lot better than begging big brother (cloudflare, google, or amazon captcha) for access, so I'm quite appreciative of what Techaro is doing

jdlshore 12 hours ago

__s 10 hours ago

mitxela 12 hours ago

drum55 13 hours ago

It’s not seconds though, it’s in the order of tens of milliseconds of work, it’s faster to complete the challenge than most http requests will take.

last difficulty 5 nonce 645376 in 9 ms (101.6MH/s, avx512-x16)

This takes many minutes to solve on a cellphone, 9 milliseconds on a cheap VPS. It’s not stopping anyone.

bombela 13 hours ago

Jtariiiii 13 hours ago

gruez 13 hours ago

>The assumption is that requiring 1 second of compute before allowing a page load will have more impact on the people requesting 1000 pages/sec than it will on consumers requesting 1 page every minute.

Which doesn't hold. A 1s delay, despite being inperceptible is still a cost to human users. After all, 3600 x 1s delay adds up to an hour. Worse yet, the typical human visitor will always have to solve a challenge, because chances are it's the first time they're visiting your blog or whatever. Someone scraping reuse a valid session for at least a few more pages.

There's also the problem of time. It might be tempting to think the cost of a challenge is 1M cpu cycles or whatever, but the cost is better modeled as two parts, a time cost (for the human) and a cpu cost (for the computer). A scraper might have to pay the cpu cost, but not the time cost, because they can have their scraper solve challenges in their sleep. Unless the user is utterly destitute, their time is worth far more than whatever the compute cost is.

fc417fc802 13 hours ago

The assumption is that there will always be some population distribution in terms of effort expended as well as in terms of problems caused. At present it's the lowest effort actors that are causing the highest number of problems. So an 80% (or even just a 20%) solution largely solves the practical problem faced by site operators.

If against all odds it turns out that skiddies (or agents or AI billionaires or what have you) are willing to burn inordinate amounts of RAM and CPU just to scrape autogenerated cgit pages that are of approximately zero value to them to begin with then I guess we'll just have to cross that bridge when we come to it.

XorNot 11 hours ago

Okay but it's like no RAM at all. Thats the problem: you've got stupid bots causing a bunch of issues - these can be stopped.

And then regular users: who now can't really browse your site.

And then smart bots - anyone with even a moderate amount of funding in the AI space, who aren't even slightly slowed down.

The solution basically makes the favored customer well funded AI scrapers, not users.

jeroenhd 5 hours ago

fc417fc802 11 hours ago

Retr0id 14 hours ago

See also:

https://github.com/eternal-flame-AD/pow-buster - Browser extension that already used WASM to accelerate the anubis solver, among others.

https://github.com/kasper93/anubis_webgpu - Browser extension that uses webgpu, for another order-of-magnitude speedup (depending on your GPU of course).

throawayonthe 13 hours ago

afaik argon2 should make the GPU less helpful

dist-epoch 13 hours ago

Argon2 is already GPU-accelerated.

anthoniks 12 hours ago

I think the idea is to just raise marginal costs for scraping high enough to make it expensive and non-profitable.

chews 14 hours ago

It's wild to me that PoW systems are how we sort the bot problem... the bummer is that all this "work" is just wasted cycles, at least in crypto there is a token you can sell.

Levitating 14 hours ago

> at least in crypto there is a token you can sell

That would defeat the purpose. The goal is to make scraping costly, not profitable.

articulatepang 13 hours ago

Scraping would be costly in this world: scrapers would have to spend tokens in order to get the webpage.

But, in this world, the website owner would receive tokens that they can then use to do whatever they want, including paying for servers and bandwidth. This is the sense in which the cycles aren’t wasted: the website owner now has cash to spend.

Effectively, both scrapers and ordinary users would be paying for the privilege of getting website bytes.

This also solves the problem of having to wait for your phone to solve the challenge while you’re browsing: you can buy or mine some tokens ahead of time and pay them as soon as challenged. So can the scrapers, but because they’re accessing enormous numbers of pages it’s hopefully prohibitively expensive for them.

cozzyd 14 hours ago

I guess it could in principle be profitable for the website, not the client?

xosc 13 hours ago

TacticalCoder 14 hours ago

saagarjha 13 hours ago

Sure, then just replace it with something that is useful to society but not immediately profitable to a scraper, like science research

xena 13 hours ago

odo1242 13 hours ago

Well, there was CoinHive which did this exact thing 6-7 years ago, but that system got abused a bit much

CarVac 13 hours ago

PoW was originally anti-spam technology.

stephenlf 12 hours ago

Comparatively, this is what it's like getting all of this working across browser versions, platforms, and so many other things:

…<img not found/>…

I don’t know what this picture was supposed to be, but a 404 demonstrates your point perfectly well.

xena 12 hours ago

Refresh, the Anubis docs site regenerates its cookie secret on every deploy as part of the "holy shit did I break everything?" verification step.

initramfs 9 hours ago

the enemy of my phone's temperature is my friend.

kingstnap 13 hours ago

> hey Claude vibeslop me a CUDA Anubis solver" route is on its way to being fundamentally dead.

Lmao yeah no. I don't think a little argon2 is going to change shit all.

I mean the thesis of Anubis itself is "scrappers are compute limited (in ways that consumer devices are not)" which has its own massive flaws.

Jtariiiii 13 hours ago

The goal isn't to eliminate scrapers, its to prevent a distributed scraping network from requesting 10000 pages a second each from 10000 different websites.

lxgr 13 hours ago

Yes, I also strongly suspect that this is only going to move more parts of scrapers onto consumer devices. The egress proxies are already there, why not use a little bit of the compute as well?

fwip 11 hours ago

When you force a low end device to burn CPU or fill ram constantly, the owner throws it out and buys a new one.

bakugo 8 hours ago

shevy-java 3 hours ago

Somehow WebAssembly does not want to become as popular as HTML, CSS or JavaScript. Very disappointing to see.