← Toate cazurile

Cazul 001 · Platformă SaaS B2B multi-tenant · Controlul accesului

Orice client putea seta parola oricărui utilizator.

Paginile de cont găseau utilizatorul doar după ID, în toate companiile client.

Un monitor întunecat cu un formular: „Set a new password”, „For: another company’s admin”, o parolă mascată și, cu roșu, „Not your company”.
Înainte
Orice client logat putea prelua orice cont.
După
Recomandat: serverul verifică tenantul; test cu doi tenanți în CI.

Cazul în jumătate de minut.

Un film fără sunet, cu subtitrare. Ecranele din el sunt ilustrative.Ilustrativ

Bug-ul

O platformă SaaS B2B multi-tenant ține facturile și datele clienților pentru multe companii, iar fiecare companie ar trebui să le vadă doar pe ale ei. Paginile de cont aveau în adresă ID-ul de tenant al clientului, care arată ca o graniță, dar serverul nu-l verifica. Găsea utilizatorul țintă doar după ID-ul lui, iar ID-urile erau numere mici, consecutive.

Cum se vede

Fiecare client își vedea utilizatorii și datele lui, așa că nimic nu părea în neregulă. Dar dacă schimbai ID-ul utilizatorului cu unu, pagina arăta un utilizator din altă companie, cu un formular de setare a parolei adresat e-mailului lui. Editorul de permisiuni avea aceeași problemă și afișa e-mailul și drepturile de acces ale acelui utilizator. Împreună, cele două pagini îi permiteau oricărui client logat să vadă toți utilizatorii platformei și să aleagă cui îi setează parola, inclusiv administratorilor altor companii.

app.example.com/tenants/company-a/users/1043/account

403 · Acces interzis

  • Utilizatorul nu face parte din compania ta.

Refuzat de server

app.example.com/tenants/company-a/users/1043/account

Setează o parolă nouă

  • Pentru: admin@company-b.example
  • Companie: Company B

Afișat unui cont din company A

Trage ca să compari înainte și dupăIlustrativ

Cum l-am găsit

Într-un audit de securitate ne-am logat ca un client și am schimbat ID-ul pe fiecare pagină care primește unul. Am dovedit problema cu o singură înregistrare din altă companie, doar citind, și ne-am oprit acolo. N-am trimis niciun formular și n-am schimbat nicio parolă.

Paginile cu înregistrări erau limitate corect la compania fiecăruia, iar raportul o spune: raportăm și ce funcționează.

Reparația

Ce am recomandat: serverul verifică dacă utilizatorul țintă e din compania celui care face cererea și dacă acesta are voie să-l administreze. Schimbarea parolei cere parola curentă sau o nouă autentificare. ID-urile consecutive se înlocuiesc cu ID-uri imposibil de ghicit.

Testul care îl prinde

Te loghezi ca firma A și ceri fiecare pagină de administrare a conturilor cu ID-ul unui utilizator din firma B. Testul așteaptă 403 sau 404 și verifică faptul că e-mailul lui B nu apare în răspuns. Rulează în CI pe fiecare rută care primește un ID.

two-tenant.spec.tsIlustrativ
import { test, expect } from "@playwright/test";
import { accountRoutes, seed, signInAs } from "./fixtures";

// Every account page that takes a user ID, asked for another company's user.
for (const route of accountRoutes) {
  test(`company A can't open a company B user: ${route}`, async ({ page }) => {
    await signInAs(page, seed.companyA.admin);
    const userB = seed.companyB.admin;
    const response = await page.goto(route.replace(":userId", userB.id));

    expect([403, 404]).toContain(response?.status());
    await expect(page.getByText(userB.email)).toHaveCount(0);
  });
}

Ce pune în pericol

Fiecare cont de pe platformă și, prin aceste conturi, facturile și datele clienților fiecărei companii. Conform GDPR, o astfel de preluare e o încălcare a securității datelor personale pentru fiecare companie afectată.

Spune-ne ce lansezi.

O aplicație nouă sau rescrisă, un agent AI, o automatizare sau o versiune care trebuie testată. Un apel gratuit de 30 de minute, apoi un preț în scris. Dacă încă nu ai nevoie de noi, îți spunem.

Programează un apel gratuit