it-swarm-id.com

Teknik yang lebih baik daripada enkripsi parameter url

Saya seorang programmer yang bekerja pada aplikasi di mana satu-satunya pilihan/vs/batas waktu adalah untuk mengimplementasikan enkripsi simetris pada nilai parameter url. Data pada dasarnya tidak sensitif, tetapi kami perlu mencegah agen penjualan mengintip satu sama lain. (Kunci dihasilkan pada pembuatan sesi dan kuat secara kriptografis.) Sesi diharapkan akan sering berakhir.

Hirarki peran adalah Manager--> Supervisor--> Agents. Struktur data saat ini tidak menjelaskan peran ini dengan cara menegakkan secara ketat siapa yang dapat melihat apa. Mendapatkan informasi ini dari database TIDAK langsung mendekati apa pun. (Database Rekursif.)

Saya tahu bahwa teknik ini masuk daftar sebagai pertahanan terhadap manipulasi parameter. Apa teknik yang lebih baik?

Kendala:
Pemeriksaan berbasis peran bukanlah suatu opsi.

[Informasi tambahan] Url dibuat dan dikirim ke klien sebelum saya melakukan perubahan tampak seperti:

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

Permukaan ancaman spesifik di sini adalah manipulasi parameter terhadap ?agentId=12345. Id agen ditugaskan secara unik untuk setiap agen. Jadi jika Agen A ingin melihat statistik Agen B, ia bisa memasukkan agentId = 22222 untuk melihat kutipan agen dan statistik penjualan saat ini.

Sekali lagi, pengecekan Berbasis Peran bukanlah pilihan bagi saya: Saya tidak dapat membuat perubahan ke database OR tingkat persistensi.

Solusi saya adalah menggunakan kunci enkripsi yang dibuat sesi (menggunakan kelas KeyGenerator Java) dan mengenkripsi url keluar yang dikirim ke klien. Jadi sekarang, urlnya seperti:

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

Sekarang, jika seseorang mencoba agentId = 22222, server akan mendekripsi apa itu berpikir adalah ciphertext dan pada akhirnya akan membuat urutan karakter yang tidak valid.

(Ini membuka kemungkinan bahwa agentId yang ada dapat ditemukan, tetapi sangat tidak mungkin bahwa itu akan relevan dengan orang yang melakukan serangan.

Saya akan menekankan bahwa pertanyaan ini bukan tentang keamanan optimal (yang akan menjadi pemeriksaan berbasis peran untuk memastikan akses sumber daya) dan tentang mencoba untuk memeras keamanan di wilayah abu-abu.

Solusi enkripsi parameter di sini direkomendasikan kepada saya oleh salah satu petugas keamanan kami. Saya punya satu takeaway yang tidak saya pertimbangkan pada solusi ini - url rusak - dan akan menggunakan it serta masalah pemeliharaan yang dibuat oleh solusi ini untuk berdebat tentang waktu untuk menegakkan aturan akses dengan cara yang sementara.

21
avgvstvs

Pertanyaan bagus! Terima kasih telah menguraikan ancaman yang ingin Anda lawan. Saya telah mengedit jawaban saya sesuai dengan itu.

Ringkasan. Pertahanan utama Anda harus kontrol akses. Anda perlu membatasi pengguna mana yang dapat melihat halaman mana. Detail di bawah.

Kontrol akses dalam aplikasi web. Yang perlu Anda lakukan adalah memeriksa apakah pengguna berwenang untuk mengakses data yang akan Anda perlihatkan pada halaman, sebelum mengizinkan mereka untuk melihat data itu. Ini pada dasarnya turun ke kontrol akses: Anda ingin kontrol yang membatasi pengguna mana yang dapat melihat data mana, berdasarkan pada beberapa kebijakan otorisasi.

Sepertinya Anda memiliki urutan halaman, satu untuk setiap agen:

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

di mana producerIds (agentIds) berpotensi dapat ditebak atau diprediksi. Anda ingin memastikan bahwa agen 12345 dapat melihat http://www.example.com/agent/?producerId=12345 tetapi tidak ada halaman lain. BAIK.

Ini adalah situasi rawa standar, dan pertahanan rawa standar adalah: kontrol akses.

Untuk menerapkan kontrol akses, Anda membuat kode aplikasi web sehingga setiap halaman memeriksa apakah pengguna berwenang untuk melihat halaman itu sebelum mengizinkan pengguna untuk melihat halaman itu. Misalnya, untuk halaman yang tercantum di atas, logika yang mengimplementasikan halaman itu akan memeriksa identitas pengguna yang saat ini masuk. Jika id pengguna login cocok dengan ID produser dari parameter halaman, maka Anda menunjukkan kepada mereka informasinya. Jika id tidak cocok, Anda tidak menunjukkan informasi kepada mereka: jika itu adalah pengguna lain, Anda menunjukkan kepada mereka halaman kesalahan (dengan informasi tentang cara mendapatkan akses), atau jika pengguna belum login, Anda mengarahkan ulang mereka ke halaman login.

Ini tidak akan merusak bookmark. Itu tidak memerlukan perubahan ke database, perubahan ke lapisan kegigihan, atau kontrol akses berbasis peran. Itu mengharuskan Anda memiliki cara untuk mencari identitas pengguna yang saat ini masuk dan mengaitkannya dengan ID penyedia mereka. Juga, jika Anda ingin mengizinkan manajer dan penyelia melihat data untuk semua agen lain, maka Anda perlu cara untuk mencari pengguna yang saat ini masuk dan menentukan apakah mereka seorang manajer atau penyelia atau tidak. Jika Anda hanya ingin mengizinkan manajer/penyelia agen untuk melihat halaman mereka (tidak semua manajer/penyelia lain), maka Anda harus memiliki cara untuk menentukan manajer/penyelia dari masing-masing agen. Ini cukup mendasar, persyaratan minimal; sulit untuk melihat bagaimana Anda bisa menghindarinya.

Seperti yang ditunjukkan @symbcbean dengan benar, ini adalah kesalahan yang sangat umum yang sering ditemukan dalam aplikasi web. Contoh khas mungkin situs yang menggunakan beberapa nilai parameter yang dapat ditebak untuk mengidentifikasi sumber daya, dan tidak mengotentikasi pengguna secara memadai. Misalnya, misalkan pesanan diberikan nomor urut berurutan:

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

dan anggap bahwa siapa pun yang mengetahui URL dapat melihat pesanan. Itu akan menjadi buruk, karena itu berarti bahwa siapa pun yang tahu (atau menebak) nomor pesanan dapat melihat pesanan, bahkan jika mereka tidak berwenang untuk melakukannya. Ini adalah salah satu dari Sepuluh Teratas OWASP risiko keamanan aplikasi web: Referensi Objek Langsung Tidak Aman . Untuk informasi lebih lanjut, saya sarankan membaca sumber daya yang tersedia di OWASP. OWASP memiliki banyak sumber daya hebat tentang keamanan aplikasi web.

Komentar lain. Yang lain menyarankan menggunakan SSL. Meskipun itu tidak akan mencegah kerusakan parameter, itu adalah praktik keamanan umum yang baik yang membela terhadap jenis masalah lainnya. Menggunakan SSL sangat mudah: cukup konfigurasikan situs web Anda untuk menggunakan https, alih-alih http (dan idealnya, aktifkan HSTS dan atur bit secure pada semua cookie).

Juga, sering kali lebih baik untuk menghindari menyimpan informasi rahasia dalam parameter URL, semua yang lain dianggap sama. Anda dapat menyimpan informasi rahasia dalam status sesi atau dalam database.

16
D.W.

Singkatnya: Jangan mengenkripsi parameter URL, gunakan pencarian terpisah .

Juga, menggunakan HTTPS pada dasarnya tidak dapat dinegosiasikan jika Anda menginginkan segala ukuran keamanan aplikasi web. Ini wajib pada tahun 2015. Dapatkan nyaman dengan TLS 1.1+.


Apa yang ingin dilakukan pengembang

What developers want to do

Apa yang seharusnya dilakukan oleh pengembang

enter image description here

7

tetapi kami perlu mencegah agen penjualan mengintip dari petunjuk masing-masing

Ini agak menyiratkan bahwa klien adalah browser - apakah Anda mengirim kunci sebagai cleartext di beberapa titik?

Polinomial benar, Anda harus menggunakan SSL. Itu tidak akan menyelesaikan masalah pengguna mengetikkan nilai yang berdekatan ke URL yang terlihat seperti:

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

Sangat mungkin untuk menghasilkan token otentikasi sisi-server berdasarkan parameter yang harus disajikan untuk memvalidasi permintaan. Idealnya Anda akan menggunakan kode otentikasi pesan (MAC) untuk ini, tetapi hash juga akan berfungsi jika Anda berhati-hati. misalnya dalam PHP ...

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

Yang divalidasi hanya dengan:

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

Di sini crypto_key() mengembalikan kunci kriptografi statis (menghasilkannya dengan menarik, katakanlah, 128 bit dari /dev/urandom Dan menyimpannya dalam database).

Tetapi Anda masih perlu mengontrol akses ke kode yang menghasilkan URL.

3
symcbean

Ini solusinya

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

dan saya membuat url seperti

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

url akan terlihat seperti

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

dan di sisi lain saya mendekripsi

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

fungsi untuk crypt dan decrypt adalah

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

Untuk mencegah kerusakan parameter, saya selalu mengirim hash dengan nilai teks biasa.

misalnya ambil url ini yang ingin Anda amankan

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

Di server, model Anda akan hash semua nilai url dengan garam rahasia

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

kemudian Anda mengirim hash ini bersama dengan nilai url lainnya

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

Sekarang, ketika Anda menerima permintaan untuk URL ini, Anda kembali mengambil parameter yang disajikan dan hash melalui algoritma yang sama. Hash yang baru saja Anda hasilkan harus cocok dengan hash yang disajikan, jika tidak, kirimkan kepada mereka hasil 400 "Permintaan Buruk" !.

Yang menyenangkan adalah parameter Anda masih dapat dibaca oleh manusia, dan semua logika validasi Anda yang ada dapat tetap sama.

1
raterus

Jangan gunakan input pengguna

(karena kamu tidak dapat kepercayaan itu)

Jawaban ini memperluas diterima dengan apa yang menurut saya penyederhanaan yang signifikan.

Sekarang, dari deskripsi Anda dan dari pemahaman saya terbaik , Anda telah mengatakan bahwa Anda ingin mencegah Sales Agent A (yaitu 12345) untuk mengintip Sales Agent B's (yaitu 54321) data.

Cukup, bunuh parameter agentId dari string kueri dan dapatkan dari sesi

URL menjadi https://example.org/show_order.php

Secara internal, aplikasi harus mengekstrak id agen penjualan dari kepala sekolah yang disimpan dalam sesi. Saya sangat berkarat di PHP jadi saya akan menggunakan kode pseudo

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

Permintaan ini hanya akan mengabaikan segala sesuatu yang berasal dari klien. Itu tidak memerlukan modifikasi pada lapisan ketekunan. Bahkan tidak memerlukan implementasi RBAC (kontrol akses berbasis peran), tetapi semuanya tentang fungsi itu getPrincipalSalesId.

Ini pada dasarnya adalah kode yang sama yang Anda gunakan untuk menghasilkan URL, tetapi kali ini Anda memalu nilai itu ke dalam kueri, membuatnya implisit .