Mein Platz in der WordPress-Community
- Mein wordpress.org-Konto besteht seit 2006.
- Ich habe zum WordPress-Core in den Versionen 7.0 und 7.1 beigetragen.
- Ich betreue 30 Plugins auf wordpress.org.
- Ich organisiere WordCamps und trete dort als Speaker auf.
- Ich war bei jedem WordCamp Europe von 2017 bis 2026 dabei.
Next.js in Bonn: Formulare, die jeder per POST erreicht
Die Bundesstadt Bonn beschreibt sich als deutsche Stadt der Vereinten Nationen. Mit dem Klimasekretariat UNFCCC und weiteren UN-Einrichtungen kamen viele international arbeitende Organisationen in die Stadt, dazu nennt die Stadt rund 150 Nichtregierungsorganisationen (bonn.de, UNO und Internationales). Wer für einen Verband, eine Stiftung oder ein Unternehmen im Bundesviertel ein Portal baut, landet schnell bei Formularen mit echten Daten: Anmeldungen zu Veranstaltungen, Mitgliederbereiche, Bewerbungen, Änderungen an einem Profil.
In Next.js laufen solche Formulare heute meist über Server Actions. Das ist bequem, denn das Formular ruft direkt eine Funktion auf dem Server auf. Genau hier liegt aber ein Missverständnis, das ich in Code-Durchsichten oft sehe: Die Funktion wirkt wie ein interner Baustein der Seite, ist aber ein Endpunkt, den jeder mit dem passenden POST-Request aufrufen kann.
Ich bin Mariusz Szatkowski, ein einzelner Entwickler in Gdynia, und arbeite seit 2006 mit WordPress, heute auch mit Next.js und Headless-Architekturen. Für Bonner Auftraggeber arbeite ich remote und schriftlich, ohne Termine vor Ort. Gestaltung, Entwürfe und Wireframes kommen von Ihnen, ich setze sie um. Diese Seite zeigt, wie ich Server Actions absichere, und enthält eine Prüfliste, die Sie auch ohne mich verwenden können.

Foto: Dietmar Rabich, CC BY-SA 4.0, Wikimedia Commons.
Was eine Server Action technisch ist
Die Anleitung Server Actions and Mutations beschreibt den Mechanismus nüchtern. Beim Build ersetzt der Compiler die Funktion im Browser-Bundle durch eine Referenz, also eine Action-ID und einen Dispatcher, der per POST an den Server zurückschickt. Der Code bleibt auf dem Server. Erreichbar ist die Action trotzdem für jeden, der denselben POST senden kann. Die Dokumentation zieht daraus den Schluss, jede Action als nicht vertrauenswürdigen Einstiegspunkt zu behandeln.
Die Anleitung Data Security geht noch einen Schritt weiter: Eine exportierte Server Action ist auch dann von außen aufrufbar, wenn sie nirgends im eigenen Code importiert wird. Next.js entfernt zwar unbenutzte Actions beim Build aus dem Client-Bundle, aber darauf baue ich keine Sicherheit. Eine Action, die es gibt, wird geprüft, als würde sie morgen jemand gezielt aufrufen.
Was Next.js von sich aus schützt
Das Framework bringt einige Schutzmechanismen mit. Die Dokumentation nennt sie einzeln, und jeder hat eine Grenze, die man kennen sollte.
| Schutz | Was er leistet | Wo er aufhört |
|---|---|---|
| Nur POST | Actions lassen sich nur per POST aufrufen; zusammen mit SameSite-Cookies verhindert das die meisten CSRF-Angriffe | Schützt nicht vor einem Angreifer mit eigener gültiger Sitzung |
| Origin-Vergleich | Der Host aus dem Origin-Header muss zum Host der Anwendung passen, sonst bricht Next.js ab | Eine Anfrage ganz ohne Origin-Header wird laut Konfigurationsreferenz mit Warnung durchgelassen |
| Verschlüsselte Action-IDs | IDs sind nicht vorhersagbar und werden zwischen Builds neu berechnet | Eine bekannte ID ist kein Geheimnis, sie steht im Browser-Bundle |
| Body-Grenze | Standardmäßig 1 MB je Anfrage | Begrenzt die Größe, nicht die Zahl der Anfragen |
| Verschlüsselte Closures | Mitgenommene Variablen reisen verschlüsselt zum Browser | Die Dokumentation rät, sich nicht allein darauf zu verlassen |
Der zweite Punkt verdient einen eigenen Satz, weil er in vielen Zusammenfassungen fehlt. Der Origin-Vergleich ist ein Schutz gegen fremde Webseiten, die den Browser Ihrer Nutzer missbrauchen. Gegen ein Skript, das Anfragen direkt baut und den Header einfach weglässt, hilft er nicht. Die eigentliche Prüfung muss deshalb in der Action stehen.
allowedOrigins hinter Proxy und CDN
Viele Bonner Organisationen betreiben ihre Anwendungen hinter einem Reverse Proxy oder einem CDN. Solange der Proxy den öffentlichen Host in x-forwarded-host weitergibt, braucht es laut Dokumentation keinen Eintrag. Reicht er stattdessen seinen eigenen Host durch, sieht der Server etwa localhost:3000, während der Browser den öffentlichen Namen sendet. Dann gehört der Host aus der Adresszeile in die Liste, nicht der interne.
// next.config.js
module.exports = {
experimental: {
serverActions: {
allowedOrigins: ['portal.example.org', '**.example.org'],
},
},
}Die Regeln für Platzhalter sind enger, als man vermutet. Ein * steht für genau einen Teil des Hostnamens, ** für einen oder mehrere und ist nur am Anfang erlaubt. *.example.org trifft example.org selbst nicht, deshalb stehen in der Liste meist zwei Einträge. Teilersetzungen wie app-*.example.org funktionieren nicht, und ein Port lässt sich nicht per Platzhalter angeben. Die Prüfung läuft in der Entwicklung wie in Produktion. Eine zu großzügige Liste schwächt den Schutz, deshalb trage ich nur Hosts ein, die Sie tatsächlich betreiben.
Anmeldung und Berechtigung in jeder Action
Der häufigste Fehler in Next.js-Projekten, die ich durchsehe: Die Seite prüft den Login, die Action darin nicht. Die Dokumentation zeigt genau diesen Fall und hält fest, dass eine Weiterleitung auf Seitenebene nur steuert, welche Oberfläche gerendert wird. Die Action ist ein eigener Einstiegspunkt und muss die anfragende Person selbst prüfen.
Danach kommt die zweite Frage: Darf diese Person diesen Datensatz ändern? Die Anleitung empfiehlt ein Muster, das ich in jedem Projekt verwende. Der Browser schickt nur eine Referenz, meist eine ID, und die gewünschte Änderung. Alles andere, vor allem der Besitz, wird aus der Sitzung und der Datenbank neu gelesen.
'use server'
import { z } from 'zod'
import { auth } from '@/lib/auth'
import { db } from '@/lib/db'
const Eingabe = z.object({
anmeldungId: z.string().uuid(),
personen: z.coerce.number().int().min(1).max(4),
})
export async function anmeldungAendern(prevState: unknown, formData: FormData) {
const session = await auth()
if (!session?.user) return { fehler: 'Bitte melden Sie sich an.' }
const geprueft = Eingabe.safeParse({
anmeldungId: formData.get('anmeldungId'),
personen: formData.get('personen'),
})
if (!geprueft.success) return { fehler: 'Bitte prüfen Sie Ihre Angaben.' }
const anmeldung = await db.anmeldung.findFirst({
where: { id: geprueft.data.anmeldungId, userId: session.user.id },
})
if (!anmeldung) return { fehler: 'Anmeldung nicht gefunden.' }
await db.anmeldung.update({
where: { id: anmeldung.id },
data: { personen: geprueft.data.personen },
})
return { ok: true }
}Drei Dinge sind an diesem Beispiel wichtig. Die Sitzung wird in der Action geholt, nicht von der Seite übernommen. Die Abfrage sucht den Datensatz mit ID und Nutzer-ID zugleich, sodass eine fremde ID einfach nichts findet. Und die Rückgabe enthält nur einen Status, keinen Datenbankdatensatz, denn Rückgabewerte werden serialisiert und an den Browser geschickt. Der erste Parameter prevState ist nötig, weil das Formular die Action über useActionState aufruft und so die Fehlermeldung anzeigen kann (Forms).
Für Löschungen und andere endgültige Vorgänge schlägt die Dokumentation strengere Prüfungen vor, etwa eine frische Anmeldung, und ein lautes Scheitern, wenn die Prüfung nicht greift. In einem Mitgliederbereich heißt das bei mir: Wer sein Konto löschen will, gibt das Passwort erneut ein.
Eingaben prüfen: die Form ist nicht der Besitz
Die Anleitung zu Server Actions formuliert einen Satz, den ich jedem Team ans Herz lege: Eine Schema-Prüfung mit Zod oder ähnlichen Bibliotheken prüft nur die Form der Eingabe. Ein sauber geformtes Objekt kann trotzdem auf eine Zeile zeigen, die der anfragenden Person nicht gehört. Validierung und Berechtigung sind zwei getrennte Schritte, und beide gehören in die Action oder in eine Datenzugriffsschicht dahinter.
Als Eingabe zählt dabei alles, was vom Client kommt: FormData, Suchparameter, Header und die Werte in Ordnern mit eckigen Klammern wie [id]. Die Prüfliste der Dokumentation nennt diese Ordner ausdrücklich, weil ihr Inhalt aus der Adresse stammt und frei änderbar ist. HTML-Attribute wie required helfen dem Nutzer beim Ausfüllen, schützen aber den Server nicht.
Closures, Geheimnisse und Quelltext
Eine Action, die direkt in einer Komponente steht, kann Variablen aus deren Umgebung mitnehmen. Die Dokumentation zeigt das an einem Versionsstand, der beim Rendern festgehalten und beim Absenden verglichen wird. Damit das funktioniert, reisen die Variablen zum Browser und zurück. Next.js verschlüsselt sie und erzeugt bei jedem Build einen neuen Schlüssel je Action. Trotzdem rät die Anleitung, sich nicht allein auf diese Verschlüsselung zu verlassen. Ich halte es einfach: In eine Closure kommt kein Geheimnis und keine personenbezogene Angabe, die der Browser nicht ohnehin sehen darf.
Für zusätzliche Sicherheit nennt die Dokumentation die Taint-APIs von React, die über experimental.taint aktiviert werden. Damit lässt sich ein Objekt oder ein einzelner Wert markieren, sodass React ihn nicht an Client-Komponenten weitergibt. Die Anleitung bezeichnet das als zusätzliche Schicht; das Filtern der Daten in der Datenzugriffsschicht ersetzt es nicht.
Wie wichtig der Ort von Geheimnissen ist, zeigte der Dezember 2025. Unter CVE-2025-55183 konnte eine präparierte Anfrage eine Server Function dazu bringen, den kompilierten Quelltext anderer Server Functions zurückzugeben. Laut Next.js-Team konnten dabei auch Geheimnisse sichtbar werden, wenn sie direkt im Code standen statt zur Laufzeit aus Umgebungsvariablen gelesen zu werden. API-Schlüssel für CRM, Newsletter oder Zahlungsanbieter stehen bei mir deshalb nie im Quelltext, und nur die Datenzugriffsschicht liest process.env.
Warum proxy.ts allein nicht reicht
Seit Next.js 16 heißt die frühere Middleware proxy.ts. Die Anleitung zur Authentifizierung beschreibt sie als Ort für optimistische Prüfungen: Sie liest die Sitzung aus dem Cookie und leitet Nicht-Angemeldete weiter. Datenbankabfragen soll sie vermeiden, weil sie bei jeder Route läuft, auch bei vorab geladenen. Die Dokumentation sagt deutlich, dass Proxy nicht die einzige Verteidigungslinie sein soll; die meisten Prüfungen gehören so nah wie möglich an die Datenquelle.
Für die Durchsicht bedeutet das: proxy.ts und jede route.ts bekommen besondere Aufmerksamkeit, weil sie viel können. Die Next.js-Dokumentation empfiehlt dafür klassische Methoden bis hin zu regelmäßigen Penetrationstests. Ebenso wichtig ist der Gegenfall: Ein Abmelden über einen Link mit ?logout=1 ist eine Änderung beim Rendern, die die Dokumentation ausdrücklich ablehnt. Änderungen laufen über Actions mit POST.
Doppeltes Absenden und Anfragen in Serie
Next.js schickt Actions aus einem Browser nacheinander, nicht parallel. Die Dokumentation betont aber, dass das eine Eigenschaft des Clients ist: Der Server stellt nichts in eine Warteschlange, jede Anfrage läuft, sobald sie ankommt. Ein Skript, das dieselbe Action hundertmal aufruft, wird also hundertmal ausgeführt.
Für teure Vorgänge wie den Versand einer Bestätigungsmail empfiehlt die Anleitung eine Begrenzung der Anfragen. Ein Detail aus dem Backend-for-Frontend-Leitfaden wird oft übersehen: Ein Zähler im Arbeitsspeicher zählt je Server-Instanz und beginnt nach einem Neustart bei null. Läuft die Anwendung auf mehreren Instanzen, gehören die Zähler in einen gemeinsamen Speicher oder in die Begrenzung des Hosters. Bei Anmeldeformularen für Veranstaltungen prüfe ich außerdem, dass ein zweites Absenden keine doppelte Anmeldung erzeugt.
Sicherheitsupdates: was React2Shell gezeigt hat
Am 3. Dezember 2025 veröffentlichte das Next.js-Team die Warnung zu CVE-2025-66478, der unter dem Namen React2Shell bekannt wurde. Die Lücke im Protokoll der React Server Components war mit CVSS 10,0 bewertet und konnte in ungepatchten Anwendungen mit App Router Code auf dem Server ausführen lassen. Eine Umgehung gab es nicht, nur das Update. Drei Tage später kam die Empfehlung, alle Geheimnisse einer Anwendung zu tauschen, wenn sie am 4. Dezember noch ungepatcht online war.
Daraus folgen zwei Zeilen, die in jedem Betriebskonzept stehen sollten: wer Updates einspielt und auf Staging prüft, und wie sich alle Schlüssel einer Anwendung ohne Ausfall tauschen lassen. Das geplante Sicherheitsrelease vom 3. November 2026 brachte die Versionen 16.4.5 und 15.5.29 (Next.js-Blog); laut npm-Registry ist 16.4.6 vom 9. November 2026 die aktuelle Version.
Was das deutsche Recht und die LDI NRW dazu sagen
§ 19 Abs. 4 TDDDG verpflichtet Anbieter digitaler Dienste, soweit technisch möglich und wirtschaftlich zumutbar, durch technische und organisatorische Vorkehrungen sicherzustellen, dass kein unerlaubter Zugriff auf ihre technischen Einrichtungen möglich ist und diese auch gegen äußere Angriffe gesichert sind. Die Vorkehrungen müssen den Stand der Technik berücksichtigen. Eine Server Action ohne Berechtigungsprüfung ist genau so ein unerlaubter Zugang. Rechtsberatung leiste ich nicht; die Einordnung für Ihr Haus trifft Ihre Datenschutzberatung.
Für Unternehmen in Nordrhein-Westfalen ist die Landesbeauftragte für Datenschutz und Informationsfreiheit zuständig. Die LDI NRW verweist auf das Standard-Datenschutzmodell der Datenschutzkonferenz, das die Anforderungen der DSGVO in Gewährleistungsziele übersetzt. Ich nutze diese Ziele als Raster für die Durchsicht:
| Gewährleistungsziel | Was es in einer Server Action bedeutet |
|---|---|
| Vertraulichkeit | Sitzung und Berechtigung in jeder Action, Geheimnisse nur aus Umgebungsvariablen |
| Integrität | Eingaben auf dem Server prüfen, Besitz aus Sitzung und Datenbank ableiten |
| Verfügbarkeit | Body-Grenze bewusst setzen, Anfragen begrenzen, Zähler gemeinsam speichern |
| Datenminimierung | Rückgabewerte und Props auf das beschränken, was die Oberfläche anzeigt |
Der Maßnahmenkatalog zum Modell enthält unter anderem die Bausteine 43 „Protokollieren“ und 51 „Zugriffe auf Daten, Systeme und Prozesse regeln“. Abgelehnte Aufrufe einer Action schreibe ich deshalb ins Protokoll, ohne die Formulardaten selbst mitzuschreiben.
Prüfliste für jede Server Action
- Die Action prüft die Sitzung selbst, unabhängig von Seite, Layout und
proxy.ts. - Die Action prüft, ob die Person genau diesen Datensatz ändern darf, und liest den Besitz aus der Datenbank.
- Jede Eingabe aus
FormData, Adresse, Header und Suchparametern wird auf dem Server geprüft. - Die Rückgabe enthält nur Status und Felder, die die Oberfläche anzeigt.
- Kein Geheimnis steht im Quelltext oder in einer Closure.
- Module mit Datenbankzugriff sind mit
server-onlymarkiert. - Teure Actions sind begrenzt, und die Zähler liegen bei mehreren Instanzen in einem gemeinsamen Speicher.
allowedOriginsenthält nur öffentliche Hosts, die Sie selbst betreiben.- Bei mehreren eigenen Servern teilen alle Instanzen denselben
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY. - Die Next.js-Version ist auf dem Stand des letzten Sicherheitsreleases.
So läuft ein Auftrag aus Bonn bei mir
- Sie schreiben mir, worum es geht: neue Anwendung, Durchsicht einer bestehenden oder ein einzelnes Formular.
- Ich stelle Rückfragen schriftlich und schicke einen Umfang mit Annahmen und Ausschlüssen.
- Bei einer Durchsicht gehe ich alle Dateien mit
use server, die Routen mit Parametern,proxy.tsundroute.tsdurch und liefere einen Bericht mit Fundstellen. - Korrekturen und neue Funktionen entstehen auf einer Testumgebung, die Sie prüfen und abnehmen.
- Danach betreuen Sie die Anwendung selbst, oder ich spiele die Sicherheitsreleases nach Absprache ein.
Für den Start brauche ich Lesezugriff auf das Repository oder eine Kopie, Zugang zur Testumgebung und die Liste Ihrer Formulare. Wenn ein neues Frontend entsteht, liefern Sie das Layout, zum Beispiel als Tabelle, in der Sie markieren, welche Elemente auf welcher Ansicht stehen.
Verwandte Seiten für Bonn
- WordPress Wartung in Bonn: wenn neben der Anwendung eine WordPress-Seite regelmäßig gepflegt werden soll.
- PHP Entwickler in Bonn: wenn ein Laravel- oder Symfony-Backend die Daten für das Frontend liefert.
- Migration zu Astro und Next.js in Bonn: wenn ein bestehendes CMS-Frontend abgelöst werden soll.
- Next.js Entwickler in Berlin: Betrieb ohne Vercel, Container und gemeinsame Schlüssel für mehrere Instanzen.
- Headless CMS Entwickler: wenn Inhalte aus einem eigenständigen Redaktionssystem in die Next.js-Anwendung fließen.
Häufige Fragen zu Server Actions
Reicht es, die Seite mit dem Formular hinter einen Login zu legen?
Nein. Die Next.js-Dokumentation sagt ausdrücklich, dass eine Prüfung auf Seitenebene nicht für die Server Actions auf dieser Seite gilt. Die Seite entscheidet nur, welche Oberfläche jemand sieht. Die Action selbst ist per POST erreichbar und muss Sitzung und Berechtigung selbst prüfen.
Schützt eine Zod-Prüfung meine Server Action?
Nur zum Teil. Zod oder Valibot prüfen, ob die Eingabe die erwartete Form hat. Ob die übergebene ID zu einem Datensatz gehört, den die anfragende Person ändern darf, prüft das Schema nicht. Dafür lese ich den Datensatz mit der ID und der Nutzer-ID aus der Sitzung neu aus der Datenbank.
Brauche ich die Einstellung allowedOrigins?
Nur, wenn der Host in der Adresszeile des Browsers nicht bei Next.js ankommt, etwa weil ein Proxy seinen eigenen Host weiterreicht statt X-Forwarded-Host zu setzen. Dann gehört der öffentliche Host in die Liste, nicht der interne. Ein Platzhalter steht dabei für genau einen Teil des Hostnamens, zwei Sterne für einen oder mehrere.
Sind Werte in einer Closure sicher, weil Next.js sie verschlüsselt?
Next.js verschlüsselt Variablen, die eine Action aus der umgebenden Komponente mitnimmt, und erzeugt dafür bei jedem Build einen neuen Schlüssel. Die Dokumentation rät trotzdem davon ab, sich allein darauf zu verlassen. Geheimnisse und personenbezogene Daten gehören gar nicht in eine Closure, die zum Browser und zurück reist.
Prüfen Sie auch eine bestehende Next.js-Anwendung?
Ja. Ich gehe alle Dateien mit use server, die Routen mit Parametern in eckigen Klammern sowie proxy.ts und route.ts durch, so wie es die Prüfliste der Next.js-Dokumentation vorschlägt. Sie bekommen einen schriftlichen Bericht mit Fundstellen und Vorschlägen; die Korrekturen setze ich auf Wunsch auf Ihrer Testumgebung um.
Was soll in Ihrer ersten Nachricht an mich stehen?
Die Adresse der Anwendung, die Next.js-Version aus der package.json, den Hoster oder die Server-Umgebung, die Art der Anmeldung und eine Liste der Formulare mit personenbezogenen Daten. Lesezugriff auf das Repository beschleunigt die Einschätzung, ist für den ersten Schritt aber keine Voraussetzung.
Ihr Next.js-Vorhaben in Bonn
Ob ein Mitgliederbereich für einen Verband, ein Anmeldeportal für Veranstaltungen oder eine bestehende Anwendung, bei der Sie wissen wollen, wie offen ihre Formulare sind: Schreiben Sie mir über das Kontaktformular. Nennen Sie die Adresse der Anwendung, Ihr Ziel, den gewünschten Termin und den Stack, mit dem Sie heute arbeiten. Ich antworte an Werktagen schriftlich, und die erste Einschätzung zu Ihrem Vorhaben ist kostenlos.
Ausgewählte Projekte
Beispiele aus meiner Arbeit.
LEARNETIC - E-Publishing-Plattform | WPPoland
Effective e-Publishing ist ein innovatives Projekt, das sich auf die Erstellung, den Import, die Veröffentlichung und die Distribution digitaler Inhalte konz...
lifetree.pl - WordPress Projekt | WPPoland
Die Website lifetree.pl ist eine Plattform, die sich den Themen persönliche Entwicklung, ein gesunder Lebensstil und Inspiration aus der Natur widmet. Das Pr...
linkr.pl - WordPress Projekt | WPPoland
Linkr.pl ist ein Online-Portal, das 2007 als Alternative zu Wykop.pl gestartet wurde, welches damals den polnischen Markt der „social news“-Portale dominiert...
WordPress Support & Entwicklung in Bonn
Brauchen Sie die Leistung: Next.js-Entwickler in Bonn?
Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.
Projekt beschreibenWeitere WordPress-Dienste und Wissensbasis entdecken
Migration zu Astro, Next.js und Headless WordPress.
WooCommerce-Synchronisierung mit ERP und Großhandel.
Geschäftsprozessautomatisierung rund um WordPress und Firmensysteme.
Bibliothek konkreter Automatisierungsfälle.
Headless WordPress, Sanity, Strapi und Contentful mit Astro oder Next.js.
Astro, MDX, Edge Delivery und an echtem Traffic gemessene Core Web Vitals.
Individuelle WordPress-Entwicklung und Architektur.
Skalierbare Headless-, ERP- und KI-Architektur für Enterprise.
Verwandte Kategorien
Unterstützende Artikel

Sechs bis sechzehn Wochen für typische Projekte, in vier Phasen: Analyse, Scoping, Build und Umstellung, Tuning. Die Variablen sind Katalogumfang, Anzahl der Integrationen, URL-Erhalt und die Bereitschaft des Redaktionsteams, nicht die Wahl des Frameworks.

Umfassende 4-Jahres-TCO-Analyse (Total Cost of Ownership), reale Core-Web-Vitals-Benchmarks, Astro 7 GraphQL APQ-Architektur und eine 10-Punkte-Entscheidungsmatrix für Enterprise-Entscheider zwischen entkoppeltem und traditionellem WordPress.

Die Entscheidung Shopify Plus vs WooCommerce headless im Jahr 2026 ist kein binärer "Plattform vs Custom"-Kompromiss mehr. Beide laufen headless, beide integrieren KI, beide liefern am Edge aus. Die echten Achsen sind Kontrolle, Gesamtkosten über fünf Jahre und Exit-Strategie. Dieser Artikel durchläuft die Entscheidungsmatrix mit bestätigten Plattformfakten.