Skip to content

Issue #120 (ginkelsoft-development/buildora): onderzoeken of store/update in BuildoraController kwetsbaar is voor mass assignment via velden buiten defineFields(), en indien nodig fixen. - #187

Open
zyra-ginkelsoft[bot] wants to merge 1 commit into
mainfrom
zyra/issue-120-ginkelsoft-development-buildor-85a63ca8
Open

zyra-ginkelsoft[bot] wants to merge 1 commit into
mainfrom
zyra/issue-120-ginkelsoft-development-buildor-85a63ca8

Conversation

@zyra-ginkelsoft

Copy link
Copy Markdown
Contributor

Goed, proef.sh bestaat al en past bij deze package-structuur (Testbench). Nu de controller bekijken.Confirmed: $this->fields is derived from defineFields() in the constructor, and resolveFields() returns these prepared fields. So $fields array in store()/update() only contains field names defined via defineFields(). Nu kijken naar tests om te zien of dit al eerder getest is, en of er een gat is.Nu is duidelijk waar het echte gat zit. Laat me het bevestigen door de fixture/testopzet te bouwen en een falende PoC-test te schrijven vóór de fix.Nu bouw ik de test fixture en de regressietest.Nu schrijf ik de regressietest inclusief fixtures (model, resource) binnen één testbestand.Nu draai ik de nieuwe test tegen de huidige (ongewijzigde) code om de kwetsbaarheid te bevestigen.Model moet de HasBuildora trait gebruiken. Ik voeg die toe.Ik voeg HasBuildora toe aan mijn testmodel.Kwetsbaarheid bevestigd: de "roles"-relatie (niet in defineFields()) wordt wél gesynchroniseerd via store()/update(). Nu de fix toepassen in de controller.Nu de testsuite opnieuw draaien.Fix bevestigd. Nu de volledige testsuite, lint en typecheck draaien.Alle 39 tests slagen. Nu lint (phpcs) en typecheck (phpstan).Nu controleer ik dat phpstan geen nieuwe fouten in de controller introduceert (59 fouten waren al aanwezig vóór mijn wijziging — dus geen regressie). Laten we ook .zyra/proef.sh kort testen.Poort was door de vorige (nog draaiende) achtergrondinstantie bezet; nu vrij. Nieuwe poging op een andere poort om zeker te zijn.proef.sh werkt (HTTP 200 op /buildora/install). Server stoppen en opruimen.Server gestopt, poort vrij. Nu committen.Laatste check: volledige testsuite nogmaals draaien om zeker te zijn dat alles nog groen is na de commit.Alles groen (39/39; de "deprecations" zijn bestaande PHPUnit-attribuutwaarschuwingen, niet gerelateerd aan mijn wijziging).

Samenvatting (voor de PR)

Wat: Onderzocht of BuildoraController::store()/update() kwetsbaar zijn voor mass assignment via velden buiten defineFields().

Bevinding: Deels kwetsbaar.

  • De kolom-toewijzing (::create()/->update()) was al veilig: $filteredData wordt altijd teruggebracht tot array_intersect_key(..., array_flip($fields)), waarbij $fields afkomstig is uit resolveFields() → defineFields(). Een extra fillable kolom die niet in defineFields() staat, komt hier niet doorheen.
  • handleRelationships() gaf echter ongefilterd $request->all() door. Elke publieke, parameterloze modelmethode die een Eloquent-relatie retourneert (bv. een niet in defineFields() opgenomen roles() BelongsToMany) kon zo gesynchroniseerd of geassocieerd worden door simpelweg een gelijknamig veld in de POST/PUT-body mee te sturen — ook al was die relatie nooit bedoeld als bewerkbaar veld op dat formulier. Bij een BelongsTo-relatie zet associate() bovendien de foreign key rechtstreeks (buiten $fillable om), wat het risico op privilege-escalatie (bv. rol- of tenant-toewijzing) reëel maakt.

Fix: store() en update() geven nu $request->only($fields) (dezelfde whitelist uit defineFields(), ongeacht readonly) door aan handleRelationships() in plaats van $request->all(). Relaties kunnen dus alleen nog aangepast worden als ze expliciet als veld in defineFields() staan.

Getest:

  • Nieuwe regressietest tests/Feature/BuildoraControllerMassAssignmentTest.php met een op maat gemaakt model + relatie (roles BelongsToMany) en twee resources: één die roles niet definieert, één die dat wel doet.
  • Vóór de fix: test toont aan dat de niet-gedefinieerde relatie tóch gesynchroniseerd werd (kwetsbaarheid gereproduceerd).
  • Na de fix: niet-gedefinieerde relatie wordt niet meer aangeraakt; expliciet gedefinieerde relatie blijft gewoon werken (geen breaking change).
  • Volledige testsuite: 39/39 groen.
  • phpcs --standard=PSR12 op het gewijzigde bestand: schoon.
  • phpstan analyse level=5: 59 fouten, identiek aantal vóór en na mijn wijziging (allemaal pre-existing, elders in de codebase; geen nieuwe fouten in BuildoraController.php).
  • .zyra/proef.sh handmatig gedraaid (Testbench-app op poort 8199): start correct, /buildora/install geeft HTTP 200.

Open/niet meegenomen:

  • De pre-existing 59 phpstan-fouten elders in de repo zijn niet aangepakt (buiten scope van dit issue).
  • Kolom-mass-assignment bleek al veilig; hierover is geen aparte fix nodig, alleen bewijs in deze samenvatting/commit.
  • Ik heb geen bredere audit gedaan van andere controllers (bv. InlineRelationController) die mogelijk hetzelfde patroon gebruiken — de mens kan overwegen of issue Security audit: mass assignment in store/update flow #120 daar ook geldt.

BuildoraController::store()/update() beperkten kolom-mass-assignment al
correct tot de velden uit Resource::defineFields(). handleRelationships()
gebruikte echter ongefilterd $request->all(), waardoor elke public,
parameterloze modelmethode die een Eloquent-relatie teruggeeft (bv. een
niet-geëxposeerde "roles" BelongsToMany) alsnog gesynchroniseerd of
geassocieerd kon worden door simpelweg een gelijknamig veld mee te sturen.
Dat is mass assignment op relatieniveau, los van defineFields().

Fix: geef alleen $request->only($fields) door aan handleRelationships(),
zodat relaties enkel aangepast kunnen worden als ze expliciet als veld
in defineFields() staan. Regressietest voegt een niet-geëxposeerde
BelongsToMany-relatie toe en bevestigt dat deze niet meer via de request
gesynchroniseerd wordt, terwijl een wél gedefinieerde relatie blijft werken.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants