Changeset 58cad21 in Klonkt for src/routes/openwebauth.js


Ignore:
Timestamp:
08/19/2026 07:44:50 PM (3 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
598f090
Parents:
5869b1f
git-author:
Robin <roboburr@…> (08/19/2026 07:30:37 PM)
git-committer:
Robin <roboburr@…> (08/19/2026 07:44:50 PM)
Message:

OpenWebAuth: PKCS#1 v1.5 zelf uitpakken, met een grens op het aantal pogingen

Node weigert privateDecrypt met RSA_PKCS1_PADDING sinds de mitigatie voor
CVE-2023-46809 (Marvin). Daarmee was gastlogin stuk: vier tests rood, en
in bedrijf een geworpen TypeError midden in de inlogstroom.

De revert-vlag was geen uitweg. Die bestaat alleen op de lijnen 18/20/21
-- Node voegt een security-revert alleen toe aan wat ondersteund was toen
de fix kwam -- en 20 is sinds 30 april 2026 EOL. Node 22+ heeft hem nooit
gehad. FEP-61cf schrijft v1.5 voor, dus OAEP repareert de test en breekt
de interop met Hubzilla. Blijft over: het omhulsel zelf afhalen via
RSA_NO_PADDING.

Dat is precies het stuk dat de CVE veroorzaakte, dus met de zorg erbij:

  • Geen vroege uitgang en geen worp. De scan loopt altijd het hele blok af. Dat is geen echte constant-time -- die krijg je in JavaScript met JIT en GC niet -- maar het haalt het waarneembare verschil weg.
  • Implicit rejection: bij een ongeldig omhulsel een afgeleide waarde in plaats van een fout. DETERMINISTISCH, uit sleutel + ciphertext. Vers willekeurig zou slechter zijn: dezelfde ciphertext twee keer aanbieden gaf dan twee antwoorden, en juist dat verschil wilden we verbergen.
  • Een teller van 20/uur op POST /magic, per SITE-SLUG want daar hangt het sleutelpaar aan. Hij telt ALLE pogingen, niet alleen de mislukte: een teller die alleen faalt meetelt is zelf weer een orakel, en dan staat de vertakking die we bij de ontsleuteling weghaalden aan de achterdeur terug. Een orakel heeft honderdduizenden pogingen nodig; twintig per uur is voor een mens onzichtbaar.

Onderweg bleek een aanname in de bestaande code niet te kloppen: het
commentaar bij decryptToken en bij de test leunden op OpenSSL's eigen
implicit rejection. Die kwam pas in 3.2; Node 20 brengt 3.0.19 mee en
daar WERPT hij. Die meting was dus op een andere machine gedaan dan waar
het draait. Nu maken we het zelf, dus de eigenschap staat vast ongeacht
de OpenSSL eronder.

Suite 1160/1160. Van de drie eigenschappen bijten er twee bij een
controleproef (de PS-ondergrens en het determinisme); de nep-uitkomst
niet, want de andere tak geeft dan een lege string die net zo goed
sneuvelt. Dat staat zo in het commentaar in plaats van dat ik doe alsof
alle drie dragend zijn.

Co-Authored-By: Claude Opus 5 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/openwebauth.js

    r5869b1f r58cad21  
    1616import db from '../config/database.js';
    1717import { renderPage } from '../middleware/render.js';
     18import { owaMagicLimiter } from '../middleware/rate-limit.js';
    1819
    1920const router = express.Router();
     
    166167 * foutpagina geeft en geen redirect.
    167168 */
    168 router.post('/magic', async (req, res) => {
     169router.post('/magic', owaMagicLimiter, async (req, res) => {
    169170  const bdest = OWA.fromBdest(req.body && req.body.bdest);
    170171  if (!bdest) return res.status(400).type('text/plain').send('bad bdest');
Note: See TracChangeset for help on using the changeset viewer.