Zum Inhalt springen

Blog ·

White-Label-Panels: was der Kunde sieht

Den eigenen Namen auf ein Reseller-Panel zu setzen ist die leichte Hälfte. Die schwere: entscheiden, welche Bildschirme für den Kunden überhaupt existieren.

Von Provibr

Wer VPS oder Hosting weiterverkauft, dessen Kunden wollen irgendwann ein Panel. Sie wollen ihre eigene Maschine um zwei Uhr nachts neu starten, statt ein Ticket zu eröffnen, und Sie wollen genau das auch.

Daraus werden zwei Fragen, die wie eine aussehen und keine sind. Wessen Name steht auf dem Panel, und welche Teile des Panels existieren für diese Person überhaupt. Das Erste ist Markenauftritt und im Wesentlichen Darstellung. Das Zweite ist eine Grenze, und wenn man sie falsch zieht, liest ein Kunde von Ihnen am Ende Ihre Lieferantenrechnung.

Der Markenauftritt endet dort, wo die Papiere anfangen

Ein Panel umzubenennen heißt, die Rahmung zu ändern: die Wortmarke in der Seitenleiste, den Seitentitel, das Favicon, den Namen im Kontoblock. Das ist eine nützliche Menge, und dort hören die meisten White-Label-Funktionen auf.

Der interessante Teil ist die Liste der Dinge, die niemals den Namen des Resellers tragen dürfen.

BildschirmWessen Namen er trägtWarum
Panel-Rahmung, Titel, FaviconDer ResellerDie Beziehung, in der der Kunde steht
DatenschutzerklärungDie PlattformEin Verarbeitungshinweis beschreibt, wer tatsächlich verarbeitet
Allgemeine GeschäftsbedingungenDie PlattformEs ist die Vereinbarung der Plattform, nicht die des Resellers
AuftragsverarbeitungsvertragDie PlattformDasselbe, und er benennt Unterauftragsverarbeiter
Rechnung und ProformadokumenteDie PlattformEs ist der Beleg eines echten Geschäftsvorgangs
Die Zeile auf einem KontoauszugDie PlattformEin dauerhafter Eintrag, den niemand später kommentieren kann

Die Begründung ist ein Satz: Ein Kunde Ihres Kunden darf niemals zu der Überzeugung kommen, er habe einen Vertrag mit jemand anderem als der Partei, mit der er ihn wirklich hat. Alles mit rechtlichem oder finanziellem Charakter trägt den Namen der Gegenpartei in diesem Dokument, und das ist keine gestalterische Vorliebe.

Wichtiger als die Regel ist, wo sie wohnt. In unserer Codebasis ist sie eine Liste von Dateipfaden, und ein Test läuft von jedem dieser Pfade aus den transitiven Importbaum ab und schlägt in dem Moment fehl, in dem einer davon das Markenmodul überhaupt erreichen kann. Er sucht in der Breite, damit der Fehler die kürzeste Kette nennt, denn das ist die, die man durchtrennt.

Eine Prüfung auf direkte Importe umgeht man zu leicht: die Markenabfrage in eine Hilfsfunktion legen, die Hilfsfunktion importieren, fertig. Und die Absicherung prüft sich in beide Richtungen. Ein gelisteter Pfad, der verschwindet, ist ein Fehler statt eines stillen Übersprungs, und getrennt davon wird behauptet, dass das Panel-Layout das Markenmodul sehr wohl erreicht, denn ein Auflöser, der still nichts auflöst, würde jede Datei grün färben.

Der eigene Login des Resellers wird nie umbenannt

Es gibt eine zweite Regel, die weniger offensichtlich ist und die wir ohne sie auszusprechen falsch gemacht hätten: Der Markenauftritt gilt ausschließlich auf der eigenen Domain des Kunden.

Meldet sich der Reseller auf dem eigenen Host der Plattform an, sieht er die Plattform und nicht seine eigene Marke. Dort leben Rechnungen, das Abonnement und die Beziehung zu uns. Die Markenabfrage fällt in dem Augenblick auf schlicht zurück, in dem eine Anfrage nicht an eine Kontodomain gebunden ist, es entscheidet also genau eine Stelle, und kein Bildschirm muss sich etwas merken.

Der Bildschirm zur Markenverwaltung zeigt eine Vorschau der kundenseitigen Rahmung, statt selbst umbenannt zu sein. Das klingt pedantisch, bis man sich überlegt, was die Alternative beibringt: Ein Reseller, der sein eigenes Logo über seiner eigenen Rechnung sieht, wird vernünftigerweise schließen, dass seine Kunden etwas Ähnliches sehen.

Ein weißes Logo auf einer weißen Seitenleiste

Der Hintergrund unseres Panels ist weiß, ein Logo mit durchsichtigem Hintergrund und weißer Tinte ist dort also unsichtbar, und wer es hochlädt, erfährt es nicht: Er betrachtet es in einem Gestaltungswerkzeug auf einer grauen Zeichenfläche.

Wir haben gemessen statt geraten und jedes Logo in einem Browser ohne Fenster auf die tatsächliche Flächenfarbe komponiert:

LogoKontrast gegen die Panelfläche
Dunkle Tinte, durchsichtiger Hintergrund16,46:1
Weiße Tinte, durchsichtiger Hintergrund1,00:1
Weiße Tinte auf eigener undurchsichtiger Platte17,74:1
Hellgraue Tinte1,24:1

Die Zeile mit 1,00:1 heißt nicht „schwer zu lesen“. Jedes Pixel ist mit dem Hintergrund identisch. Das Logo wird gezeichnet, und es gibt nichts zu sehen.

Daraus wurden zwei Entscheidungen. Es liegt absichtlich keine Platte unter dem Logo, denn das würde die Marke des Kunden neu zeichnen und jedem normalen Logo einen Rahmen geben, nur um eine Ausnahme zu retten. Und der Hochladebildschirm warnt, statt abzulehnen, denn eine Marke darf hellgrau sein.

Die Messung zählt Tinte, nicht Überdeckung. Ein Logo mit großem durchsichtigem Rand fällt über den größten Teil seiner Fläche mit dem Hintergrund zusammen und ist trotzdem einwandfrei sichtbar; worauf es ankommt, ist, wie viel davon gezeichnet wird und wie weit diese Tinte von der Flächenfarbe entfernt liegt.

Abwesenheit ist kein Recht

Nun die schwerere Hälfte. Welche Bildschirme sollten für den Kunden eines Resellers existieren?

Der Reflex ist, das als Rechte abzubilden: dem Subkunden eine Rolle geben, weniger Kästchen ankreuzen. Das ist die falsche Form, und zwar aus einem Grund, der sich erst an den Rändern zeigt. Rechte beantworten „darf dieses Mitglied das“. Die Frage hier lautet „existiert dieser Bildschirm auf dieser Domain“, und die beiden fallen in dem Moment auseinander, in dem ein Kontoinhaber sich anmeldet, um sein eigenes Kundenpanel anzusehen. Er ist der Eigentümer. Jede Rechteprüfung winkt ihn durch.

Das Modell ist also eine Umkehrung und kein Recht. Eine feste Liste sagt, welche Oberflächen auf einer Kontodomain abwesend sind: Abrechnung, Kontoeinstellungen, Tickets, Agenten, Integrationen, das Kontoprotokoll, die Topologieansicht, der Plattformverwaltungsbereich sowie die Seiten für Registrierung und vergessenes Passwort. Abwesend für jeden, den Eigentümer eingeschlossen.

Drei davon brauchen eine Begründung, denn der Grund ist nicht der naheliegende.

Tickets sind abwesend, weil der Kunde eines Resellers eine Supportbeziehung zum Reseller hat und nicht zu uns. Gäbe es diesen Bildschirm, läse er eine Antwort, die eine Firma nennt, die es laut seinem eigenen Panel gar nicht gibt.

Das Kontoprotokoll ist abwesend, weil es das Protokoll des Kontos ist und nicht das des Lesers. Das ehrliche Ergebnis ist kein gefiltertes Protokoll, sondern „diesen Bildschirm gibt es hier nicht“. Der Aktivitätsreiter je Server bleibt, denn der ist wirklich auf eine Maschine begrenzt, die dem Leser gehört.

Die Topologieansicht belegt das Modell. Sie läuft auf dem Servermodul, und das Servermodul ist genau das eine, das ein Subkunde sehr wohl hat. Ein Rechtegatter würde hier überhaupt nichts aussieben.

Drei Verschlüsse, denn eine Seite ist keine Grenze

Eine Prüfung reicht nicht, und jeder der drei fängt ab, was die anderen nicht können.

Der erste sitzt in der Rechtefunktion selbst, wo die Reihenfolge zweier Zeilen der ganze Punkt ist:

  1. Existiert dieses Modul auf dieser Oberfläche? Wenn nicht, ablehnen.
  2. Hat diese Rolle vollen Zugriff? Wenn ja, erlauben.

Die Oberflächenprüfung nach vorn zu ziehen ist das, was „existiert nicht“ über „darf alles“ stellt, und es ist das, was die Umkehrung überall gelten lässt statt nur in den Bildschirmen, an die sich jemand erinnert hat.

Der zweite ist eine Absicherung in jeder Seite unter diesen Pfaden, die eine gewöhnliche 404 erzeugt. Sie nimmt absichtlich kein Argument entgegen: Ein Aufruf, der seinen eigenen Bildschirm benennt, würde einen Tippfehler zu einer still offenen Tür machen.

Der dritte sitzt im Reverse Proxy, denn eine Seite kann keine Anfrage abfangen, die nie eine Seite erreicht. Ein POST auf einen abwesenden Pfad wird abgelehnt, bevor irgendein Seitencode läuft. Navigationen werden durchgelassen, damit die eigene 404 der Anwendung erscheint statt eines nackten Proxyfehlers.

Das ist der Befund, den mitzunehmen sich lohnt, selbst wenn Sie nichts von alledem bauen.

Unsere Sitzungscookies sind hostgebunden. Kein Domain-Attribut, eine Sitzung auf einer Kundendomain wird also nicht an eine andere gesendet und auch nicht an den Host der Plattform. Das ist richtig und es ist getestet, samt dem negativen Fall, in dem das Einschalten domainübergreifender Cookies ein Domain erscheinen lässt.

Es ist trotzdem keine Grenze. Der Subkunde hält seinen eigenen Sitzungstoken in der Hand und kann ihn mit einem HTTP-Werkzeug auf der Kommandozeile schicken, wohin er will. Nur ein Browser hätte abgelehnt.

Wir haben gemessen, was das erlaubte, und es war schlimmer als erwartet: Ein Subkunde konnte eine brandneue Organisation mit sich selbst als Eigentümer anlegen, samt eigenem Probeabonnement, und das über zwei voneinander unabhängige Codepfade, erreichbar über vier verschiedene Einstiegspunkte. Vier Organisationen, hinterher in der Datenbank gezählt. Auf seiner eigenen Domain wurde dieselbe Anfrage vom Proxy abgelehnt, die Tür war also auf der einen Seite zu und auf der anderen offen.

Die Reparatur bestand nicht darin, diesen beiden Pfaden Prüfungen hinzuzufügen. Sie bestand darin, die Grenze an den einen Punkt zu legen, an dem jede authentifizierte Anfrage vorbeikommt, und die Invariante „ein Subkunde wird niemals Eigentümer einer Organisation“ in die eine Funktion, die alle Anlegewege teilen.

Dieselbe Runde fand die allgemeine Fassung des Problems an anderer Stelle. Ein API-Schlüssel trägt eine Rolle, aber keine Oberfläche. Ausnutzbar war das nicht, denn den Reiter, auf dem ein Schlüssel angelegt wird, gibt es auf einer Kontodomain nicht. Aber das ist eine versteckte Schaltfläche und keine Grenze, und der Unterschied zählt an dem Tag, an dem jemand einen zweiten Weg zum Anlegen von Schlüsseln hinzufügt. Die Behebung lehnt den Handelnden ab, statt den Schlüssel zu kennzeichnen.

Keine Spalte sagt „das ist ein Subkunde“

Noch eine Entwurfsnotiz zum Schluss, denn es ist die Art Entscheidung, die sich still auszahlt.

Ein Subkunde ist eine gewöhnliche Benutzerzeile mit einer reservierten E-Mail-Adresse der Form username@<organisation-id>.invalid, dazu eine gewöhnliche Mitgliedschaftszeile mit einem schmalen Rechteprofil. Es gibt absichtlich keine Boolean-Spalte, die ihn markiert: Eine zweite Quelle der Wahrheit kann gegenüber der Adresse aus dem Tritt geraten, und dann sind sich zwei Teile des Systems uneinig darüber, wer jemand ist.

Weil die Organisationskennung in der Adresse steckt, kommt die Eindeutigkeit umsonst aus dem Index, der ohnehin schon da war, und derselbe Benutzername kann unter zwei Resellern existieren. Das Anmeldeformular fragt nach einem Benutzernamen und nimmt die Organisationskennung aus dem Host statt aus dem Formular, niemand meldet sich also durch Raten einer Kennung bei einem fremden Konto an.

Und seine Adresse wird nie als bestätigt markiert, denn niemand kann sie bestätigen. Diese Spalte bedeutet „diese Adresse gehört nachweislich dieser Person“, und sie für eine Adresse auf wahr zu setzen, die kein Postfach erreicht, würde die Unwahrheit an eine weniger sichtbare Stelle verschieben.

Was es nicht leistet

Der Markenauftritt deckt die Rahmung ab. Die Texte der Oberfläche lesen sich weiterhin wie unser Produkt, in der Sprache, die der Besucher benutzt, und etwas anderes zu behaupten hieße, das Vokabular eines Resellers stellvertretend in neun Sprachen zu übersetzen. Die Liste der abwesenden Oberflächen ist eine Entscheidung über die Form des Produkts und für sich allein kein Sicherheitsmodell: Sie funktioniert, weil die drei Verschlüsse dahinter es tun.

So funktionieren Kontodomains bei Provibr, wo der Agent auf Ihrer eigenen Hardware läuft und sich ausschließlich nach außen verbindet.

Fangen Sie mit einem Host und einem Agenten an

Konto erstellen, den Agenten mit einem einzigen Befehl installieren und Ihren ersten Proxmox-Host verbinden. Die Testphase läuft 14 Tage und fragt nicht nach Zahlungsdaten.