it-swarm-eu.dev

Lepší techniky než šifrování parametrů URL

Jsem programátor pracující na aplikaci, kde jedinou volbou/vs/lhůta bylo implementovat symetrické šifrování na hodnoty parametrů url. Data jsou ve své podstatě necitlivá, ale potřebovali jsme zabránit tomu, aby obchodní agenti navzájem sledovali potenciální zákazníky. (Klíče jsou generovány při vytváření relací a jsou kryptograficky silné.) Očekává se, že relace budou často ukončeny.

Hierarchie rolí byla Manager--> Supervisor--> Agents. Datové struktury v současné době tyto role nezohledňují způsobem, který by přesně vynucoval, kdo může co vidět. Získání těchto informací z databáze nebylo nikde blízko přímočaré. (Rekurzivní databáze.)

Vím, že tato technika je na seznamu jako obrana proti manipulaci s parametry. Co by bylo lepší technikou?

Omezení:
Kontrola založená na roli není možnost.

[Další informace] Webové adresy vytvořené a odeslané klientovi před provedením jakýchkoli změn vypadaly takto:

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

Konkrétním povrchem hrozeb je manipulace s parametry proti ?agentId=12345. ID agentů jsou každému agentovi přiřazeny jedinečně. Pokud se tedy agent A chce podívat na statistiky agenta B, mohl zadat agentId = 22222, aby se podíval na nabídky agenta a aktuální statistiky prodeje.

Opět nebyla pro mě kontrola založená na roli možnost: Nebyl jsem schopen provést změny v databázi OR úroveň vytrvalosti).

Mým řešením bylo použití šifrovacího klíče vytvořeného relací (pomocí třídy Java KeyGenerator) a šifrování odchozích adres URL odeslaných klientovi. Takže nyní adresa URL vypadá takto:

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

Nyní, pokud se někdo pokusí agentId = 22222, server dešifruje, co myslí je ciphertext a nakonec vytvoří neplatnou posloupnost znaků.

(To ponechává otevřenou možnost, že existující agentId mohl by byl nalezen, ale docela nepravděpodobné, že by to bylo relevantní pro osobu provádějící útok.

Zdůrazním, že tato otázka se netýká optimálního zabezpečení (což je kontrola založená na rolích, aby se zajistil přístup ke zdrojům), a pokusu o stlačení nějaké bezpečnosti v šedé oblasti.

Řešení šifrování parametrů mi zde doporučil jeden z našich bezpečnostních chlapů. Dostal jsem jednu cestu s sebou, kterou jsem nebral v úvahu pro toto řešení - zlomené adresy URL - a budu používat to, jakož i problém údržby vytvořený tímto řešením, abych se hádal za čas pro vynucení přístupových pravidel v méně stopgapové módě.

21
avgvstvs

Dobrá otázka! Děkujeme za rozpracování hrozby, proti které se snažíte bránit. Odpovídajícím způsobem jsem upravil svou odpověď.

Shrnutí Vaše primární obrana by měla být kontrola přístupu. Musíte omezit, kteří uživatelé mohou zobrazit, které stránky. Podrobnosti níže.

Řízení přístupu ve webových aplikacích. Co musíte udělat, je zkontrolovat, zda je uživatel oprávněn k přístupu k datům, která se zobrazí na stránce, před tím, než jim umožní vidět tato data. V zásadě jde o řízení přístupu: chcete, aby na základě některých zásad autorizace omezovaly, kteří uživatelé mohou zobrazit, která data mohou zobrazit.

Zní to, jako byste měli posloupnost stránek, jednu pro každého agenta:

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

kde producentIds (agentIds) jsou potenciálně hádatelné nebo předvídatelné. Chcete zajistit, aby agent 12345 mohl zobrazit http://www.example.com/agent/?producerId=12345 ale žádná z ostatních stránek. OK.

Toto je bažina-standardní situace a bažina-standardní obrana je: kontrola přístupu.

Chcete-li implementovat řízení přístupu, zakódujte webovou aplikaci tak, aby každá stránka zkontrolovala, zda je uživatel oprávněn tuto stránku zobrazit, než umožní uživateli tuto stránku zobrazit. Například pro výše uvedenou stránku by logika implementující tuto stránku zkontrolovala identitu aktuálně přihlášeného uživatele. Pokud se ID přihlášeného uživatele shoduje s výrobcemId parametru stránky, zobrazí se jim informace. Pokud se ID neshoduje, nezobrazíte jim informace: pokud je to nějaký jiný uživatel, zobrazí se jim chybová stránka (s informacemi o tom, jak získat přístup), nebo pokud se uživatel dosud nepřihlásil, přesměrujete na přihlašovací stránku.

To nezruší záložky. Nevyžaduje změny v databázi, změny vrstvy perzistence nebo řízení přístupu na základě rolí. Vyžaduje, abyste měli způsob, jak vyhledat identitu aktuálně přihlášeného uživatele a spojit ji s jejich ID poskytovatele. Pokud také chcete povolit správci a supervizorům, aby viděli data pro všechny ostatní agenty, pak budete potřebovat způsob, jak vyhledat aktuálně přihlášeného uživatele a zjistit, zda jsou či nejsou manažerem nebo supervizorem. Pokud chcete povolit zobrazení jejich stránky pouze správci/nadřízenému agenta (ne všem ostatním správcům/nadřízeným), musíte mít způsob, jak určit manažera/nadřízeného každého agenta. To jsou docela základní, minimální požadavky; je těžké pochopit, jak se jim můžete vyhnout.

Jak @symbcbean správně upozorňuje, jedná se o velmi častou chybu, která se často vyskytuje ve webových aplikacích. Typickým příkladem může být web, který používá určitou hádatelnou hodnotu parametru k identifikaci zdroje a neadekvátně autentizuje uživatele. Předpokládejme například, že objednávkám je přiřazeno pořadové číslo objednávky:

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
...

a předpokládejme, že objednávku může zobrazit kdokoli, kdo zná adresu URL. To by bylo špatné, protože to znamená, že každý, kdo zná (nebo hádá) číslo objednávky, může zobrazit objednávku, i když k tomu není oprávněn. Toto je jedno z deset nejlepších OWASP bezpečnostních rizik webových aplikací: Nezabezpečené přímé odkazy na objekty . Pro více informací doporučujeme přečíst zdroje dostupné na OWASP. OWASP má spoustu skvělých zdrojů na zabezpečení webových aplikací.

Další komentáře Ostatní navrhli použití SSL. Ačkoli to nezabrání manipulaci s parametry, je to obecně dobrá bezpečnostní praxe, která brání proti jiným druhům problémů. Používání SSL je jednoduché: stačí nakonfigurovat web tak, aby používal https, místo http (a v ideálním případě povolte HSTS a nastavte bit secure na všech cookies).

Často je také lepší vyhnout se ukládání důvěrných informací do parametrů adresy URL, všechny ostatní jsou stejné. Důvěrné informace můžete uložit ve stavu relace nebo do databáze.

16
D.W.

Stručně řečeno: Nešifrujte parametry adresy URL, použijte samostatné vyhledávání .

Používání protokolu HTTPS je v zásadě také neřešitelné, pokud si přejete jakoukoli míru zabezpečení webových aplikací. Je to povinné v roce 2015. Získejte pohodlí s TLS 1.1+.


Co vývojáři chtějí dělat

What developers want to do

Co by měli vývojáři místo toho dělat

enter image description here

7

ale potřebovali jsme zabránit tomu, aby obchodní agenti navzájem koukali

To spíše znamená, že klientem je prohlížeč - posíláte klíč jako jasný text v určitém okamžiku?

Polynom je správný, měli byste používat SSL. To problém nevyřeší, když uživatelé zadají sousední hodnoty na adresu URL, která vypadá jako:

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
...

Je docela možné vygenerovat autentizační token na straně serveru na základě parametrů, které musí být předloženy k ověření požadavku. V ideálním případě byste pro tento účel použili kód pro ověřování zpráv (MAC), ale hash by také fungoval, pokud budete opatrní. např. v PHP ...

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

Což je potvrzeno jednoduše:

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

Zde crypto_key() vrací statický kryptografický klíč (vygenerujte jej vytažením, řekněme 128 bitů z /dev/urandom A jeho uložením do databáze).

Stále však musíte řídit přístup k kódu, který generuje URL.

3
symcbean

Tady je moje řešení

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

a vytvořím URL jako

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

uRL bude vypadat

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

a na druhé straně dešifruji

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

funkce pro kryptu a dešifrování jsou

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

Abychom zabránili manipulaci s parametry, vždy jsem právě poslal hash s hodnotami prostého textu.

např. vezměte tuto adresu URL, kterou chcete zabezpečit

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

Na serveru by váš model hashoval všechny hodnoty URL tajnou solí

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

pak zašlete tento hash spolu s ostatními hodnotami adresy URL

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

Nyní, když obdržíte požadavek na tuto adresu URL, znovu vezmete parametry, které jsou uvedeny, a hash je provede stejným algoritmem. Hash, který jste právě vygenerovali, by se měl shodovat s haši, které jste právě prezentovali, jinak jim pošlete výsledek 400 „Bad Request“!.

Dobrá věc je, že vaše parametry jsou stále čitelné lidmi a veškerá vaše existující validační logika může zůstat stejná.

1
raterus

Nepoužívejte použijte uživatelský vstup

(protože to camnot důvěryhodně )

Tato odpověď rozšiřuje přijato s tím, co mi připadá významné zjednodušení.

Nyní z vašeho popisu az mého nejlepšího porozumění jste řekl, že chcete zabránit tomu, aby se Sales Agent A (Konkrétně 12345) nahlédlo do Sales Agent B (Konkrétně 54321).

Jednoduše zabijte parametr agentId z řetězce dotazu a získejte jej z relace

Adresa URL se stane https://example.org/show_order.php

Interně musí aplikace extrahovat ID obchodního agenta z principu uloženého v relaci. Jsem příliš rezavý v PHP, takže budu používat pseudo kód)

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

Tento dotaz jednoduše ignoruje vše, co pochází od klienta. Nevyžaduje úpravy vrstvy perzistence. Nevyžaduje ani implementaci RBAC (řízení přístupu na základě rolí), ale vše se týká této funkce getPrincipalSalesId.

Je to v podstatě stejný kód, jaký používáte k generování adresy URL, ale tentokrát tuto hodnotu do dotazu zatlačíte, čímž ji vytvoříte implicitní .