it-swarm-eu.dev

Bessere Techniken als die Verschlüsselung von URL-Parametern

Ich bin ein Programmierer, der an einer Anwendung arbeitet, bei der die einzige Wahl/vs/Frist darin bestand, eine symmetrische Verschlüsselung für URL-Parameterwerte zu implementieren. Die Daten sind von Natur aus unempfindlich, aber wir mussten verhindern, dass Vertriebsmitarbeiter sich gegenseitig die Leads ansehen. (Schlüssel werden bei der Sitzungserstellung generiert und sind kryptografisch stark.) Es wird erwartet, dass Sitzungen häufig enden.

Die Rollenhierarchie war Manager--> Supervisor--> Agents. Die Datenstrukturen berücksichtigen diese Rollen derzeit nicht, um strikt durchzusetzen, wer was sehen kann. Das Abrufen dieser Informationen aus der Datenbank war NICHT annähernd einfach. (Rekursive Datenbank.)

Ich weiß, dass diese Technik als Verteidigung gegen Parametermanipulation ganz unten auf der Liste steht. Was wäre eine bessere Technik gewesen?

Einschränkungen:
Rollenbasierte Überprüfung ist keine Option.

[Zusätzliche Informationen] Die URLs, die erstellt und an den Client gesendet wurden, bevor ich Änderungen vorgenommen habe, sahen folgendermaßen aus:

https://www.example.com/agent/?producerId=12345

Die spezifische Bedrohungsoberfläche ist hier die Manipulation von Parametern gegen ?agentId=12345. Agenten-IDs werden jedem Agenten eindeutig zugewiesen. Wenn Agent A also die Statistiken von Agent B anzeigen möchte, hätte er agentId = 22222 eingeben können, um die Angebote und aktuellen Verkaufsstatistiken dieses Agenten anzuzeigen.

Auch hier war die rollenbasierte Überprüfung für mich keine Option: Ich konnte keine Änderungen an der Datenbank vornehmen OR die Persistenzschicht.

Meine Lösung bestand darin, einen von einer Sitzung erstellten Verschlüsselungsschlüssel (unter Verwendung der KeyGenerator-Klasse von Java) zu verwenden und die an den Client gesendeten ausgehenden URLs zu verschlüsseln. Die URL sieht nun so aus:

https://www.example.com/agent/?producerId=<ciphertext>

Wenn jemand agentId = 22222 versucht, entschlüsselt der Server das, was er denkt ist, Chiffretext und erstellt letztendlich eine ungültige Zeichenfolge.

(Dies lässt die Möglichkeit offen, dass eine vorhandene agentId könnte gefunden wird, aber es ist ziemlich unwahrscheinlich, dass sie für die Person, die den Angriff ausführt, relevant ist.

Ich möchte betonen, dass es bei dieser Frage nicht um optimale Sicherheit geht (was eine rollenbasierte Überprüfung wäre, um den Ressourcenzugriff sicherzustellen) und um den Versuch, die Sicherheit in einer Grauzone zu verringern.

Die Parameterverschlüsselungslösung hier wurde mir von einem unserer Sicherheitsleute empfohlen. Ich habe einen Imbiss bekommen, den ich bei dieser Lösung nicht in Betracht gezogen hatte - defekte URLs - und werde that sowie das durch diese Lösung verursachte Wartungsproblem verwenden, um für die Zeit zu argumentieren, in der die Zugriffsregeln durchgesetzt werden sollen in einer weniger Notlösung.

21
avgvstvs

Gute Frage! Vielen Dank, dass Sie auf die Bedrohung eingegangen sind, gegen die Sie sich verteidigen möchten. Ich habe meine Antwort entsprechend bearbeitet.

Zusammenfassung. Ihre primäre Verteidigung sollte Zugangskontrolle sein. Sie müssen einschränken, welche Benutzer welche Seiten anzeigen können. Details unten.

Zugriffskontrolle in Webanwendungen. Sie müssen lediglich überprüfen, ob der Benutzer berechtigt ist, auf die Daten zuzugreifen, die auf einer Seite angezeigt werden sollen. bevor sie diese Daten sehen können. Dies hängt im Wesentlichen von der Zugriffskontrolle ab: Sie möchten Kontrollen, die einschränken, welche Benutzer welche Daten anzeigen können, basierend auf einer Autorisierungsrichtlinie.

Es hört sich so an, als hätten Sie eine Folge von Seiten, eine für jeden Agenten:

http://www.example.com/agent/?producerId=12345
http://www.example.com/agent/?producerId=12346
http://www.example.com/agent/?producerId=12347
...

wo die ProducerIds (AgentIds) möglicherweise erraten oder vorhersehbar sind. Sie möchten sicherstellen, dass Agent 12345 http://www.example.com/agent/?producerId=12345 Anzeigen kann, jedoch keine der anderen Seiten. OK.

Dies ist eine Moor-Standard-Situation, und die Moor-Standard-Verteidigung lautet: Zugangskontrolle.

Um die Zugriffssteuerung zu implementieren, codieren Sie die Webanwendung so, dass jede Seite prüft, ob der Benutzer zum Anzeigen dieser Seite berechtigt ist, bevor der Benutzer diese Seite anzeigen kann. Für die oben aufgeführte Seite würde die Logik, die diese Seite implementiert, beispielsweise die Identität des aktuell angemeldeten Benutzers überprüfen. Wenn die ID des angemeldeten Benutzers mit der ProducerId des Seitenparameters übereinstimmt, zeigen Sie ihm die Informationen an. Wenn die ID nicht übereinstimmt, werden ihnen die Informationen nicht angezeigt: Wenn es sich um einen anderen Benutzer handelt, wird eine Fehlerseite (mit Informationen zum Zugriff) angezeigt, oder wenn sich der Benutzer noch nicht angemeldet hat, leiten Sie weiter sie auf eine Anmeldeseite.

Dadurch werden Lesezeichen nicht beschädigt. Es sind keine Änderungen an der Datenbank, Änderungen an der Persistenzschicht oder rollenbasierte Zugriffssteuerung erforderlich. Sie müssen die Möglichkeit haben, die Identität des aktuell angemeldeten Benutzers nachzuschlagen und diese mit seiner Anbieter-ID zu verknüpfen. Wenn Sie es Manager und Vorgesetzten ermöglichen möchten, die Daten für alle anderen Agenten anzuzeigen, müssen Sie den aktuell angemeldeten Benutzer nachschlagen und feststellen, ob er Manager oder Vorgesetzter ist oder nicht. Wenn Sie nur dem Manager/Supervisor des Agenten erlauben möchten, seine Seite anzuzeigen (nicht allen anderen Managern/Supervisoren), müssen Sie eine Möglichkeit haben, den Manager/Supervisor jedes Agenten zu bestimmen. Dies sind ziemlich grundlegende, minimale Anforderungen; Es ist schwer zu erkennen, wie man sie vermeiden könnte.

Wie @symbcbean richtig hervorhebt, ist dies ein sehr häufiger Fehler, der häufig in Webanwendungen auftritt. Ein typisches Beispiel könnte eine Site sein, die einen erratenen Parameterwert verwendet, um eine Ressource zu identifizieren, und den Benutzer nicht angemessen authentifiziert. Angenommen, Bestellungen erhalten eine fortlaufende Bestellnummer:

https://www.example.com/show_order.php?id=1234
https://www.example.com/show_order.php?id=1235
https://www.example.com/show_order.php?id=1236
...

und nehmen wir an, dass jeder, der die URL kennt, die Bestellung anzeigen kann. Das wäre schlecht, denn es bedeutet, dass jeder, der die Bestellnummer kennt (oder errät), die Bestellung anzeigen kann, auch wenn er nicht dazu berechtigt ist. Dies ist eines von OWASPs Top Ten Sicherheitsrisiken für Webanwendungen: nsichere direkte Objektreferenzen . Für weitere Informationen empfehle ich, die auf OWASP verfügbaren Ressourcen zu lesen. OWASP verfügt über viele hervorragende Ressourcen zur Sicherheit von Webanwendungen.

Andere Kommentare. Andere haben die Verwendung von SSL vorgeschlagen. Dies verhindert zwar nicht die Manipulation von Parametern, ist jedoch eine allgemein bewährte Sicherheitspraxis, die sich gegen andere Probleme schützt. Die Verwendung von SSL ist unkompliziert: Konfigurieren Sie Ihre Website einfach so, dass https anstelle von http verwendet wird (und aktivieren Sie im Idealfall HSTS und setzen Sie das Bit secure für alle Cookies).

Außerdem ist es oft besser, das Speichern vertraulicher Informationen in URL-Parametern zu vermeiden, da alle anderen gleich sind. Sie können die vertraulichen Informationen im Sitzungsstatus oder in der Datenbank speichern.

16
D.W.

Kurz gesagt: RL-Parameter nicht verschlüsseln, separate Suche verwenden .

Die Verwendung von HTTPS ist grundsätzlich nicht verhandelbar, wenn Sie ein gewisses Maß an Sicherheit für Webanwendungen wünschen. Dies ist für 2015 obligatorisch. Machen Sie sich mit TLS 1.1+ vertraut.


Was Entwickler tun wollen

(What developers want to do

Was Entwickler stattdessen tun sollten

(enter image description here

7

aber wir mussten verhindern, dass Handelsvertreter sich gegenseitig die Leads ansehen

Dies impliziert eher, dass der Client ein Browser ist - senden Sie den Schlüssel irgendwann als Klartext?

Polynom ist korrekt, Sie sollten SSL verwenden. Dies wird das Problem nicht lösen, dass Benutzer benachbarte Werte in eine URL eingeben, die ungefähr so ​​aussieht:

https://www.example.com/show_order.php?id=1234
https://www.example.com/show_order.php?id=1235
https://www.example.com/show_order.php?id=1236
...

Es ist durchaus möglich, serverseitig ein Authentifizierungstoken basierend auf den Parametern zu generieren, die zur Validierung der Anforderung angegeben werden müssen. Idealerweise würden Sie hierfür einen Nachrichtenauthentifizierungscode (MAC) verwenden, aber ein Hash würde auch funktionieren, wenn Sie vorsichtig sind. z.B. in PHP ...

 print "<a href='show_order.php?id=" . $id . "&valid=" . md5($id . crypto_key()) . "'>...

Was einfach bestätigt wird durch:

if ($_GET['valid'] != md5($_GET['id'] . crypto_key()) {
   die('not authorized');
}

Hier gibt crypto_key() einen statischen kryptografischen Schlüssel zurück (generieren Sie ihn, indem Sie beispielsweise 128 Bit aus /dev/urandom Ziehen und in der Datenbank speichern).

Sie müssen jedoch weiterhin den Zugriff auf den Code steuern, der die URL generiert.

3
symcbean

Hier ist meine Lösung

$id=1234;
$en_id = encrypString( $id);

und ich erstelle die URL wie

https://www.example.com/show_order.php?id=$en_id

die URL wird so aussehen

https://www.example.com/show_order.php?id=9muEYh4lShFDeCnXqoNpxucs42Fuz5Nexq1IUGWYEffffe88yRbJu

und auf der anderen Seite entschlüssele ich

$en_id= decryptString($_GET['id']);

die Funktionen zum Verschlüsseln und Entschlüsseln sind

function encrypString($plaintext) {
         # --- ENCRYPTION ---

        $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");//change this

        # show key size use either 16, 24 or 32 byte keys for AES-128, 192
        # and 256 respectively
        $key_size =  strlen($key);
        //echo "Key size: " . $key_size . "\n";


        # create a random IV to use with CBC encoding
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);

        # creates a cipher text compatible with AES (Rijndael block size = 128)
        # to keep the text confidential 
        # only suitable for encoded input that never ends with value 00h
        # (because of default zero padding)
        $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
                                     $plaintext, MCRYPT_MODE_CBC, $iv);

        # prepend the IV for it to be available for decryption
        $ciphertext = $iv . $ciphertext;

        # encode the resulting cipher text so it can be represented by a string
        $ciphertext_base64 = base64_encode($ciphertext);

        return  rawurlencode($ciphertext_base64);//important rawurlencode for + symbol in url

    }


decryptString($ciphertext_base64) {
        # --- DECRYPTION ---

        $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");//change this

        # show key size use either 16, 24 or 32 byte keys for AES-128, 192
        # and 256 respectively
        $key_size =  strlen($key);
        //echo "Key size: " . $key_size . "\n";

        # create a random IV to use with CBC encoding
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);

        $ciphertext_dec = base64_decode($ciphertext_base64);

        # retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
        $iv_dec = substr($ciphertext_dec, 0, $iv_size);

        # retrieves the cipher text (everything except the $iv_size in the front)
        $ciphertext_dec = substr($ciphertext_dec, $iv_size);

        # may remove 00h valued characters from end of plain text
        $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,
                                    $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

        return rawurldecode($plaintext_dec);
    }
2

Um Manipulationen an Parametern zu verhindern, habe ich immer nur einen Hash mit den Klartextwerten gesendet.

z.B. Nehmen Sie diese URL, die Sie sichern möchten

https://www.mysite.com/somepage?param1=abc&param2=xyz

Auf dem Server würde Ihr Modell alle URL-Werte mit einem geheimen Salt hashen

string salt = "A1B2C3D4...";
string param1 = "abc";
string param2 = "xyz";
string hash = YourFavoriteHashingAlgorithm(param1 + param2 + salt);
// result hash = "Y83YMB38DX83YUHFIEIGKDHSEUG"

dann senden Sie diesen Hash zusammen mit den anderen URL-Werten

https://www.mysite.com/somepage?param1=abc&param2=xyz&hash=Y83YMB38DX83YUHFIEIGKDHSEUG

Wenn Sie nun eine Anfrage an diese URL erhalten, nehmen Sie die angezeigten Parameter erneut und hashen sie über denselben Algorithmus. Der soeben generierte Hash sollte mit dem präsentierten Hash übereinstimmen, andernfalls senden Sie ihnen ein 400 "Bad Request" -Ergebnis!.

Das Schöne ist, dass Ihre Parameter immer noch für Menschen lesbar sind und Ihre gesamte vorhandene Validierungslogik gleich bleiben kann.

1
raterus

Nicht verwenden Benutzereingaben

(weil du nicht vertraue es cam)

Diese Antwort erweitert das akzeptiert um eine für mich signifikante Vereinfachung.

Nun, aus Ihrer Beschreibung und aus meinem besten Verständnis haben Sie gesagt, dass Sie verhindern möchten, dass Sales Agent A (Nämlich 12345) hineinschaut Die Daten von Sales Agent B (Nämlich 54321).

Beenden Sie einfach den Parameter agentId aus der Abfragezeichenfolge und rufen Sie ihn aus der Sitzung ab

Die URL wird zu https://example.org/show_order.php

Intern muss die Anwendung die Vertriebsagenten-ID aus dem in der Sitzung gespeicherten Principal extrahieren. Ich bin in PHP] übermäßig verrostet, daher werde ich Pseudocode verwenden

SELECT * FROM sales where salesman_id = ?1;
[1 = getPrincipalSalesId()]

Diese Abfrage ignoriert einfach alles, was vom Client kommt. Es sind keine Änderungen an der Persistenzschicht erforderlich. Es ist nicht einmal erforderlich, RBAC (rollenbasierte Zugriffssteuerung) zu implementieren, aber alles dreht sich um diese Funktion getPrincipalSalesId.

Es ist im Grunde derselbe Code, den Sie verwenden, um die URL zu generieren , aber dieses Mal hämmern Sie diesen Wert in die Abfrage und machen sie implizit .