Ga direct naar de inhoud
DedicatedPHP Contact

Vertrouwensgrenzen tussen PHP-modules ontwerpen zonder regels te dupliceren

Bepaal wat elke PHP-module mag aannemen, wat ze bij ontvangst van gegevens moet valideren en hoe u test of autorisatie en eigenaarschap behouden blijven.

Conceptueel diagram van PHP-modules gescheiden door contracten en autorisatiecontroles

In een modulaire PHP-applicatie is een grens niet alleen een scheiding tussen mappen, klassen of namespaces. Ze bepaalt ook welke gegevens een module mag accepteren, welke bewerkingen ze mag uitvoeren en wie verantwoordelijk is voor het controleren van elke voorwaarde. Als die beslissingen impliciet blijven, kunnen modules elkaar te veel vertrouwen, validaties dupliceren of gegevens blootleggen waarover ze geen controle zouden mogen hebben.

Vertrouwensgrenzen tussen PHP-modules ontwerpen betekent die verantwoordelijkheden expliciet maken en ervoor zorgen dat ze verifieerbaar blijven terwijl het systeem verandert. Dat betekent niet dat elke interne aanroep als vijandig verkeer moet worden behandeld of dat alle regels in elke laag moeten worden herhaald. Het betekent dat u vaststelt waar de bevoegdheid verandert, duidelijke contracten definieert en elke bewerking valideert in de module die bevoegd is om die uit te voeren.

Waarom een grens tussen modules ook een vertrouwensgrens is

Waarom een grens tussen modules ook een vertrouwensgrens is — guía visual de DedicatedPHP

Een module kan gegevens van een andere module gebruiken via een interne interface, een event, een API of een gedeelde query. In al die gevallen is het verstandig om na te gaan welke garanties de verzender biedt en welke de ontvanger moet controleren. De locatie van de code volstaat niet om die vraag te beantwoorden: een rechtstreeks aangeroepen PHP-methode kan gegevens ontvangen die afkomstig zijn van een extern verzoek, een achtergrondtaak of een andere module die zich onafhankelijk ontwikkelt.

Maak onderscheid tussen formaatvalidatie, bedrijfsinvarianten en autorisatie. Formaatvalidatie controleert of een identifier of datum een acceptabele representatie heeft. Een invariant waarborgt bijvoorbeeld dat een bewerking geen negatieve hoeveelheid bevat. Autorisatie bepaalt of de actor die bewerking op die resource mag uitvoeren. Deze controles hangen met elkaar samen, maar zijn niet onderling uitwisselbaar.

De vertrouwensgrens wordt vooral belangrijk wanneer de actor, het eigenaarschap van de gegevens of het invoerkanaal verandert. Een facturatiemodule kan bijvoorbeeld een opdracht van een andere module ontvangen, maar mag niet afleiden dat de persoon die het verzoek heeft gestart, toestemming heeft om elke factuur te wijzigen. De identiteit en context moeten expliciet en verifieerbaar worden meegegeven.

De gegevens en bewerkingen inventariseren die elke grens overschrijden

Begin met het in kaart brengen van de relevante interacties, niet met een herontwerp van de volledige applicatie. Documenteer voor elke grens wie de aanroep doet, wie eigenaar is van de bewerking, welke gegevens worden uitgewisseld en of de aanroep synchroon of asynchroon is. Neem ook minder zichtbare paden mee: consolecommando's, geplande processen, consumenten van wachtrijen en beheertaken.

  • Gegevens: identificeer de overgedragen velden, hun herkomst en of ze persoonsgegevens, gevoelige gegevens of gegevens uit een ander domein bevatten.
  • Bewerkingen: registreer welke wijzigingen worden aangevraagd en welke module ze moet uitvoeren.
  • Context: bepaal welke actor, organisatie, tenant of welk doel met het verzoek moet worden meegestuurd.
  • Resultaten: specificeer welke informatie de module mag teruggeven en welke fouten ze mag melden.

Deze inventarisatie helpt risicosignalen op te sporen: een module raadpleegt tabellen van een andere module om een interface te omzeilen; ontvangt een resource-identifier zonder het eigenaarschap te controleren; of accepteert een veranderlijk domeinobject dat door een andere module is aangemaakt. Ze brengt ook duplicatie aan het licht: meerdere consumenten geven elk hun eigen interpretatie aan een regel waarvoor één domein verantwoordelijk is.

Expliciete contracten definiëren: formaat, invarianten en compatibiliteit

Een contract beschrijft wat de ontvanger nodig heeft om een bewerking uit te voeren en welke garanties die biedt bij het antwoord. In PHP kan dit, afhankelijk van de architectuur, worden uitgedrukt met onveranderlijke DTO's, interfaces, goed gedefinieerde types of berichtschema's. De concrete vorm is minder belangrijk dan de duidelijkheid: geef geen volledige entiteiten door als de consument slechts enkele waarden nodig heeft.

Het contract moet verplichte velden, grenzen en betekenis vastleggen. Een customerId geeft op zichzelf bijvoorbeeld niet aan of het om een globale klant gaat, een klant die bij een organisatie hoort of een klant die voor een bepaalde gebruiker zichtbaar is. Als de context bepalend is voor de bewerking, neem die dan op of definieer hoe de verantwoordelijke module eraan komt.

Spreek ook af welke fouten van elkaar te onderscheiden zijn. Een verkeerd gevormde invoer is niet hetzelfde als een niet-geautoriseerde bewerking, een niet-bestaande resource of een conflict met de huidige status. De details die aan de aanroeper worden getoond, moeten voldoende zijn om het resultaat af te handelen, zonder gegevens prijs te geven waarmee resources kunnen worden opgesomd of informatie over derden kan worden achterhaald.

Contracten moeten bewust compatibel evolueren. Een optioneel veld toevoegen kan minder ingrijpend zijn dan de betekenis van een bestaand veld wijzigen, maar vereist nog steeds dat producenten en consumenten worden gecontroleerd. Houd er bij asynchrone berichten rekening mee dat een oudere versie kan blijven circuleren nadat nieuwe code is uitgerold. Verwar de code-uitrol niet met het activeren van nieuw gedrag: gebruik een gecontroleerde overgang wanneer producenten en consumenten niet tegelijkertijd veranderen.

Autorisatie en eigenaarschap valideren waar de bewerking wordt uitgevoerd

Syntactische validatie kan dicht bij de ingang plaatsvinden, maar autorisatie moet worden gecontroleerd in de context die de resource kent en de handeling beheert. De module die eigenaar is van een factuur beschikt bijvoorbeeld over de informatie om te bepalen of die mag worden uitgegeven of gewijzigd. Die beslissing mag niet worden gedelegeerd aan een aanroepende module die alleen de identiteit van de gebruiker kent.

Een bruikbare controle koppelt actor, actie, resource en context aan elkaar: wie vraagt welke bewerking aan, op welke resource en binnen welke organisatie of tenant? Ga er niet van uit dat een ontvangen identifier toestemming verleent. Controleer het eigenaarschap op de grens waar de bewerking wordt uitgevoerd, ook als het verzoek afkomstig is van interne code die als betrouwbaar wordt beschouwd. Zo voorkomt u dat een alternatieve route of een latere architectuurwijziging autorisatie omzeilt die alleen in de webinterface wordt toegepast.

Vermijd echter dat u het volledige beleid in alle modules dupliceert. Centraliseer de beslissing in de bevoegde module en stel een bewerking of service beschikbaar met een duidelijk contract. Consumerende modules kunnen voor het gemak controles uitvoeren om de gebruikerservaring te verbeteren, maar mogen niet de enige beveiligingsbarrière vormen.

Voorkomen dat gedeelde entiteiten geprivilegieerde toegang creëren

ORM-entiteiten tussen modules delen lijkt praktisch, maar kan verborgen afhankelijkheden creëren. Als meerdere modules dezelfde entiteit laden en wijzigen, kan elke module de bewerkingen omzeilen die de invarianten zouden moeten beschermen. Bovendien hebben wijzigingen in schema of gedrag gevolgen voor consumenten die het model niet beheren.

Geef bij voorkeur de benodigde gegevens door via commando's, queries of DTO's. De module die eigenaar is, blijft verantwoordelijk voor het opslaan van gegevens en het valideren van haar invarianten; de consument heeft geen algemene toegang tot de repositories of tabellen nodig. Als een leesbewerking nodig is, ontwerp dan een query die de minimale gegevensset retourneert en de vastgelegde machtigingen en reikwijdte respecteert.

Een gedeelde database verplicht u niet om bevoegdheden te delen. Zelfs voordat gegevens fysiek worden gescheiden, kunt u vastleggen dat slechts één module naar bepaalde tabellen schrijft en dat de andere modules gedocumenteerde interfaces gebruiken. Die regel verlaagt de kosten van een toekomstige scheiding en maakt toegang buiten het contract gemakkelijker te detecteren.

Testen of de isolatie behouden blijft wanneer het systeem verandert

Tests moeten zowel het geldige pad als pogingen om zonder toestemming een grens over te steken omvatten. Unit-tests controleren de regels van de module die eigenaar is; integratietests verifiëren contracten, persistentie en autorisatieconfiguratie tussen componenten. Neem gevallen op waarin een geldige actor probeert te werken met een resource van een andere tenant, met een niet-bestaande resource en met een onvolledige context.

  • Controleer dat een geldige identifier op zichzelf geen toegang verleent.
  • Verifieer dat autorisatiefouten geen gegevens van de beschermde resource teruggeven.
  • Test dat consumenten invarianten niet kunnen wijzigen via gedeelde entiteiten of rechtstreekse toegang tot repositories.
  • Voer contracttests uit wanneer producenten en consumenten onafhankelijk van elkaar worden uitgerold.

Tests moeten het daadwerkelijke beleid weerspiegelen, niet alleen controleren of er een exception wordt gegooid. Zorg ervoor dat de wijziging niet wordt opgeslagen, dat er geen ongewenst event wordt gepubliceerd en dat een herhaalde bewerking geen gedeeltelijke effecten veroorzaakt. Definieer voor flows met meerdere stappen wat er gebeurt als een stap mislukt en hoe de status wordt gereconcilieerd.

Grenzen herzien wanneer u een service afsplitst of het eigenaarschap wijzigt

Grenzen herzien wanneer u een service afsplitst of het eigenaarschap wijzigt — guía visual de DedicatedPHP

Wanneer u een service afsplitst, worden aannames zichtbaar die voorheen in het geheugen verborgen bleven: identiteit, machtigingen, latency, retries, duplicaten en beschikbaarheid. Het contract moet voldoende context overdragen en rekening houden met netwerkstoringen. Maak van een remote call niet zomaar een kopie van een lokale aanroep zonder time-outs, idempotentie en foutafhandeling te herzien.

Herzie de grenzen ook wanneer verandert wie verantwoordelijk is voor gegevens, wanneer een tenant wordt toegevoegd, een nieuw kanaal wordt geïntroduceerd of nieuwe consumenten verschijnen. Vraag wie mag schrijven, wie mag lezen, welke module over autorisatie beslist en welke garanties tijdens de migratie behouden blijven. Houd deze antwoorden bij de contractdocumentatie en de bijbehorende tests.

Een bruikbare vertrouwensgrens hangt er niet van af of alle modules in hetzelfde proces blijven draaien of dat het team informele afspraken onthoudt. De grens is herkenbaar doordat de bevoegdheid is toegewezen, de gegevens die eroverheen gaan zijn afgebakend, machtigingen worden gecontroleerd waar de bewerking wordt uitgevoerd en tests ongeautoriseerde toegang detecteren. Zo beschermt u de isolatie zonder van elke module een kopie van de regels van de andere modules te maken.

Wil je deze ideeën toepassen op je project?Laten we uw PHP-platform bespreken.
Bekijk gerelateerde service