Beveiliging
Deze pagina beschrijft in gewone taal wat er is ingebouwd om je gegevens van die van anderen gescheiden te houden en misbruik af te remmen. Het gaat over hoe Muntar draait, niet over beloftes.
Scheiding per werkruimte
Link naar de kop “Scheiding per werkruimte”Elke tabel met gegevens van een werkruimte staat onder de scheidingsregel van de database zelf: een rij is alleen zichtbaar voor de werkruimte waar hij bij hoort. Die regel wordt afgedwongen door PostgreSQL, niet alleen door de applicatie.
De verbinding waarmee Muntar je aanvragen afhandelt heeft niet het recht om die regel te omzeilen. Ook als er een fout in een query zou zitten, kan die dus niet over de grens van een werkruimte heen lezen. Een API-key hoort ook bij precies één werkruimte, dus een gekoppelde assistent ziet er nooit meer dan één.
Je account staat een laag hoger dan de werkruimtes: het draagt je naam, je adres en je wachtwoord, en het hangt via een lidmaatschap aan elke werkruimte waar je in werkt. Wissel je van werkruimte, dan wissel je van lidmaatschap en dus ook van rol. Zie Account en werkruimtes.
De boeken zelf
Link naar de kop “De boeken zelf”Twee controles in de database bewaken de administratie, los van de applicatiecode.
- Elke boeking moet op nul sluiten en al haar regels moeten bij dezelfde entiteit horen. Klopt dat niet, dan gaat de hele boeking terug.
- Een geboekte boeking verwijderen wordt geweigerd. Corrigeren gaat via een tegenboeking. Zie Boekhouden onder de motorkap.
Wachtwoorden en inloggen
Link naar de kop “Wachtwoorden en inloggen”Wachtwoorden worden gehasht opgeslagen met argon2id, met de minima die OWASP aanraadt. Het wachtwoord zelf wordt nergens bewaard en de hash gaat nooit terug naar de browser.
Een nieuw wachtwoord wordt getoetst aan een openbare lijst van wachtwoorden uit bekende datalekken. Daarvoor gaan alleen de eerste vijf tekens van een onomkeerbare afdruk van je wachtwoord de deur uit; de lijst met mogelijke treffers wordt op de server zelf doorzocht. Je wachtwoord, de hele afdruk en je e-mailadres blijven binnen. Staat je keuze in zo’n lek, dan zie je “Dit wachtwoord staat in een bekend datalek. Kies er een dat je nergens anders gebruikt.” Is die lijst even niet bereikbaar, dan blokkeert dat niets: een dienst buiten de deur bepaalt niet of je een account kunt maken.
Bestaat een e-mailadres niet, dan controleert Muntar het wachtwoord alsnog tegen een vaste hash. Een onbekend adres wordt daardoor niet meetbaar sneller afgewezen dan een bestaand adres met een fout wachtwoord. Zonder die stap kun je uit de reactietijd afleiden welke adressen een account hebben.
Op inloggen zit een rem: tien pogingen per kwartier. Er tellen twee dingen apart mee, je e-mailadres en het IP-adres waarvandaan je inlogt. De teller op het adres beschermt één account tegen een woordenboekaanval, ook als de aanvaller van netwerk wisselt. De teller op het IP-adres beschermt tegen een aanval die zich over veel accounts verspreidt. Wie de grens raakt, krijgt “Te veel inlogpogingen. Wacht een kwartier en probeer het opnieuw.” Een geslaagde inlog zet beide tellers weer op nul.
Passkeys en de tweede stap
Link naar de kop “Passkeys en de tweede stap”Naast een wachtwoord kent Muntar twee andere manieren om te bewijzen dat jij het bent: een passkey en een code uit een authenticator-app.
Een passkey is een sleutelpaar. Het geheime deel blijft in je apparaat of in de sleutelhanger van je browser en komt daar niet uit. Muntar bewaart alleen het publieke deel en een teller, en daarmee valt niet in te loggen. Bij elk gebruik controleert Muntar de handtekening en die teller. Loopt de teller niet op, dan wijst dat op een kopie van de sleutel: de poging wordt geweigerd en vastgelegd.
Een passkey hoort bij precies één webadres. Die binding komt niet uit de pagina zelf maar uit de instelling van de omgeving: TiemanIT zet de domeinnaam en het webadres van jouw omgeving vast, en de browser weigert alles wat daar niet bij hoort. Een nagemaakte inlogpagina op een ander adres krijgt je passkey dus niet in beweging. Draait een omgeving zonder domeinnaam, dan staat de browser passkeys helemaal niet toe en zijn de knoppen weg; inloggen met wachtwoord werkt daar gewoon.
Bij elke passkey-handeling geeft de server een eenmalige uitdaging mee die je browser ondertekent. Die uitdaging gaat versleuteld mee in een cookie, is vijf minuten geldig en draagt waarvoor hij bedoeld is: inloggen, de tweede stap, een bevestiging of het toevoegen van een sleutel. Een uitdaging uit de ene stap werkt daardoor niet in een andere.
Het geheim van je authenticator-app staat versleuteld in de database, met dezelfde AES-256-GCM als de sleutel van je AI-provider. Het is nergens in de schermen terug te lezen; je ziet het één keer, bij het instellen. Een code geldt per tijdvak van dertig seconden en telt maar één keer: dezelfde code een tweede keer invoeren werkt niet, ook niet als twee pogingen tegelijk binnenkomen. Van je herstelcodes bewaart Muntar alleen een onomkeerbare afdruk, en elke code vervalt zodra hij gebruikt is.
Een eigenaar kan de tweede stap verplicht stellen voor iedereen in zijn werkruimte, zie Inloggen. Die eis hangt aan het account: wie in één werkruimte onder de plicht valt, wordt overal om de tweede stap gevraagd. Raakt een lid zijn tweede stap kwijt, dan vraagt een eigenaar een reset aan en bevestigt het lid die zelf met een link uit zijn eigen mailbox. De eigenaar kan de tweede stap dus niet in zijn eentje weghalen, wat uitmaakt omdat een reset het hele account raakt en niet alleen deze werkruimte. Beide stappen komen in beide logboeken te staan. Zie Leden.
Bevestigen vóór een gevoelige handeling
Link naar de kop “Bevestigen vóór een gevoelige handeling”Sommige handelingen raken de toegang tot je account zelf: je e-mailadres wijzigen, een sessie of alle andere sessies intrekken, een passkey of een tweede factor toevoegen of weghalen, een API-key aanmaken, het inlogbeleid van de werkruimte wijzigen en een reset van de tweede stap van een lid aanvragen. Daarvoor vraagt Muntar een verse bevestiging, ook als je sessie nog dagen geldig is.
Je bevestigt met wat je hebt: je wachtwoord, een code of je passkey. De bevestiging geldt tien minuten en hoort bij het apparaat waarop je werkt, niet bij je account. Op een ander apparaat bevestig je dus opnieuw. De schermen tonen de knoppen pas als er bevestigd is, en de serverkant weigert de handeling los daarvan nog een keer: een verzoek dat het scherm omzeilt komt er niet doorheen.
Na elke bevestiging krijgt je sessie een nieuwe token. Dat gebeurt ook bij het inloggen en na de tweede stap. Een cookie dat vóór zo’n stap in verkeerde handen viel, draagt daarna dus geen sessie meer die gevoelige handelingen mag doen.
Formulieren die niets over adressen verraden
Link naar de kop “Formulieren die niets over adressen verraden”Aanmelden, een herstellink aanvragen, de bevestigingsmail opnieuw sturen en een nieuw e-mailadres aanvragen antwoorden allemaal hetzelfde, of het opgegeven adres nu bestaat of niet. Ze doen er ook even lang over, zodat het verschil niet uit de reactietijd te halen is.
Bestaat het adres al, dan wordt er niets aangemaakt en krijgt de eigenaar van dat adres een mail dat er een account op zijn naam staat. Wie een lijst adressen door zo’n formulier haalt, leert er dus niets uit en laat wel een spoor achter bij de mensen zelf.
Op elk van die formulieren zit een eigen rem:
| Formulier | Grens |
|---|---|
| Aanmelden | 5 per uur per internetverbinding |
| Herstellink aanvragen | 3 per uur per e-mailadres |
| Nieuw wachtwoord instellen | 10 per kwartier per internetverbinding |
| Bevestigingsmail opnieuw sturen | 3 per uur per e-mailadres |
| Nieuw e-mailadres aanvragen | 3 per uur per account |
| Uitnodigingen versturen | 50 per dag per werkruimte |
| Code bij de tweede stap | 5 per vijf minuten per inlogpoging |
| Bevestigen vóór een gevoelige handeling | 5 per vijf minuten per sessie |
| Een passkey gebruiken | 10 per vijf minuten per internetverbinding |
Links uit een mail
Link naar de kop “Links uit een mail”Elke link die Muntar mailt draagt een willekeurig token. Van dat token bewaart Muntar alleen een onomkeerbare afdruk, net als bij een wachtwoord: het token zelf staat nergens anders dan in die ene link. Een lek van de database levert dus geen bruikbare links op.
Een link werkt precies één keer en verloopt vanzelf.
| Link | Geldig |
|---|---|
| Je e-mailadres bevestigen | 24 uur |
| Een nieuw wachtwoord instellen | 1 uur |
| Een nieuw e-mailadres bevestigen | 1 uur |
| Een aangevraagde adreswijziging tegenhouden | 48 uur |
| De reset van je tweede stap bevestigen | 1 uur |
| Een uitnodiging aannemen | 7 dagen |
Vraag je iets opnieuw aan, dan vervalt de vorige link van dezelfde soort. Achter elke link zit een knop; alleen het openen van de link doet niets. Zo brandt een linkscanner in een mailserver de link niet op vóór jij hem gebruikt.
Sessies
Link naar de kop “Sessies”Na het inloggen krijg je een sessiecookie met een eigen token van 32 willekeurige bytes. Dat is geen nummer uit de database, dus een identifier die ergens anders opduikt is nooit vanzelf een geldige sessie. Het cookie is niet uit te lezen door scripts in je browser en is dertig dagen geldig.
- Op “Profiel & beveiliging” zie je elke actieve sessie, met apparaat, IP-adres en wanneer die voor het laatst iets deed. Je trekt er een in met “Intrekken”, of alle andere in één keer met “Overal uitloggen”.
- Log je opnieuw in in dezelfde browser, dan wordt de sessie die het cookie tot dan toe droeg eerst ingetrokken.
- Uitloggen zet de sessie op ingetrokken. De rij blijft bestaan, zodat het spoor van wie wanneer inlogde klopt. Dat geldt ook voor een ingetrokken sessie.
- Wijzig je je wachtwoord, of stel je er een in via een herstellink, dan worden alle sessies van je account ingetrokken, ook die van het apparaat waarop je dat deed. Je krijgt daar meteen een verse sessie.
- Verlopen sessies worden elke nacht opgeruimd.
Wat er van je toegang wordt vastgelegd
Link naar de kop “Wat er van je toegang wordt vastgelegd”Muntar houdt een apart logboek bij van alles wat met toegang te maken heeft: geslaagde en mislukte inlogpogingen, uitloggen, een gewijzigd of hersteld wachtwoord, een aangevraagde en een doorgevoerde adreswijziging, ingetrokken sessies, verstuurde en aangenomen uitnodigingen, gewijzigde rollen, verwijderde leden en het wisselen van werkruimte. Daar horen ook de tweede stap en de passkeys bij: een geslaagde en een mislukte tweede stap, een gebruikte herstelcode, een toegevoegde of verwijderde passkey, een teller die niet opliep, een bevestiging vóór een gevoelige handeling, een gewijzigd inlogbeleid, een aangevraagde reset van een tweede stap en de bevestiging daarvan. Bij elke regel staan het tijdstip, het IP-adres en de browser.
Bij een wijziging aan de beveiliging van je account krijg je ook een mail: een passkey erbij of eraf, de tweede stap aan of uit, een bevestigde reset van je tweede stap, en een login vanaf een apparaat waarvandaan je nog niet eerder binnenkwam. Vraagt een eigenaar zo’n reset aan, dan krijg je eerst een mail die je erom vraagt; die draagt de link waarmee je hem bevestigt. Die mails noemen geen tijdstip en geen IP-adres, want dat lekt zodra je zo’n mail doorstuurt; wat er wel staat vind je terug op je accountscherm.
Wachtwoorden, tokens en e-mailadressen komen daar nooit in te staan. Wordt een account later verwijderd, dan blijven die regels bestaan zonder nog naar een persoon te wijzen.
Wat er ín een werkruimte gebeurt, staat in het auditlogboek van die werkruimte. Daar horen ook het uitnodigen, het wijzigen van een rol en het verwijderen van een lid bij, zie Leden.
API-keys
Link naar de kop “API-keys”Een API-key maak je aan onder “API-keys & MCP”. Van de key zelf bewaart Muntar alleen een onomkeerbare afdruk en een kort voorvoegsel om hem in een lijst te herkennen. De key in leesbare vorm zie je precies één keer, direct na het aanmaken, met de waarschuwing “Kopieer deze key nu. Je ziet ’m hierna nooit meer terug.” Daarna is hij niet meer op te vragen.
Per key kies je de scopes: “Lezen”, “Importeren”, “Import bevestigen” en “Schrijven”. Een key krijgt precies wat je aanvinkt en niets meer. Intrekken doe je met “Intrekken” op dezelfde pagina. Een ingetrokken key wordt bij de eerstvolgende aanroep geweigerd, want die controle gaat elke keer naar de database.
Op het verkeer van een gekoppelde assistent staan twee remmen: 120 verzoeken per minuut per agent-identiteit en 300 verzoeken per minuut per IP-adres. Wie een grens raakt, krijgt een melding die zegt na hoeveel seconden het opnieuw kan.
Elke schrijvende aanroep via MCP komt in het auditlogboek, met de naam van de tool erbij. Een import van een bestandspad staat uit.
De sleutel van je AI-provider
Link naar de kop “De sleutel van je AI-provider”De API-sleutel van je AI-provider wordt versleuteld opgeslagen met AES-256-GCM. Het opgeslagen formaat draagt een versienummer, zodat de sleutel waarmee dat gebeurt later te vervangen is zonder dat bestaande waarden dubbelzinnig worden. GCM controleert ook op knoeien: een aangepaste waarde geeft een fout en nooit stilletjes verkeerde gegevens.
Het instellingenscherm geeft de sleutel nooit terug. Het toont alleen “Sleutel ingesteld” of “Geen sleutel ingesteld”.
De schakelaar “Cloud-provider toestaan” wordt niet alleen in het scherm afgedwongen, maar ook in de laag die de provider aanmaakt. Staat hij uit en wordt er toch een provider gekozen die niet lokaal draait, dan volgt “Deze provider is niet lokaal. Zet ‘Cloud-provider toestaan’ aan of kies een lokale server.”
Er zijn vier rollen: eigenaar, bewerker, meelezer en AI-agent. De controle zit op één plek in de code, niet verspreid over de schermen.
- Elke schrijfactie loopt langs dezelfde poort. Een meelezer wordt daar geweigerd; bewerker, eigenaar en AI-agent mogen door.
- Voor handelingen die de werkruimte zelf herinrichten geldt een strengere poort: alleen de eigenaar mag leden beheren, API-keys uitgeven of intrekken, de AI-provider instellen en entiteiten aanmaken of archiveren. Een AI-agent wordt daar bewust ook geweigerd, want anders kan hij zijn eigen toegang uitbreiden en zijn eigen uitvoer omleiden.
- Een werkruimte houdt altijd minstens één eigenaar. De laatste is niet te degraderen en niet te verwijderen.
Een gekoppelde assistent werkt met de echte rol achter de gebruikte key. Een key op een leesrol kan dus niet meer dan die rol in de webapp mag. Zie Rollen.