Rupanya, serangan ReDos mengeksploitasi karakteristik dari beberapa ekspresi reguler (yang berguna) ... pada dasarnya menyebabkan ledakan jalur yang mungkin melalui grafik yang ditentukan oleh NFA.
Apakah mungkin untuk menghindari masalah seperti itu dengan menulis regex 'non-evil' yang setara? Jika tidak (dengan demikian, tata bahasa tidak dapat ditangani di ruang / waktu praktis oleh NFA), pendekatan penguraian apa yang lebih baik? Mengapa?
regular-expressions
parsers
David Bullock
sumber
sumber
Jawaban:
Itu tergantung pada apakah Anda memiliki ekspresi reguler atau regexp: regexps itu jahat, tetapi ekspresi reguler adalah sesuatu yang indah dan tidak akan pernah mengubah kejahatan pada Anda.
Dengan regexp, maksud saya ekspresi reguler modern: yaitu, ekspresi reguler dengan fitur modern tambahan seperti backreferences - misalnya, ekspresi reguler Perl-kompatibel. Ini lebih kuat daripada ekspresi reguler klasik dari buku teks teori bahasa / automata formal, karena ekspresi reguler klasik tidak mengizinkan referensi, melihat ke belakang, melihat ke belakang, dan sebagainya.
Untuk ekspresi reguler klasik, jika Anda memiliki implementasi yang baik untuk pencocokan, maka tidak ada ekspresi reguler yang terlalu jahat. Secara khusus, algoritma standar untuk pencocokan adalah untuk mengubah ekspresi reguler ke NFA dan kemudian mengeksekusi NFA pada string input. Untuk algoritma ini, waktu menjalankan kasus terburuk untuk menguji string -character adalah O ( n ) , ketika ekspresi reguler diperbaiki. Ini berarti waktu berjalan tidak dapat meledak terlalu cepat. Tidak ada string yang akan menyebabkan peningkatan waktu berjalan yang eksponensial. Jadi, jika Anda menggunakan pencocokan yang menggunakan algoritme ini, tidak ada ekspresi reguler klasik yang akan jahat.n O ( n )
Ini tergantung pada implementasi pencocokan ekspresi reguler. Jika Anda memiliki implementasi korek yang naif atau buruk, maka pencocokan dapat membutuhkan waktu yang eksponensial; pasti ada algoritma dengan properti itu. Tetapi jawaban terbaik untuk itu mungkin tidak mengubah ekspresi reguler; mungkin lebih baik untuk memilih pencocokan yang lebih baik, jika Anda khawatir tentang serangan penolakan layanan.
Sebagai perbandingan, beberapa regexps modern tidak bisa dihindari jahat. Jika Anda memiliki regexp modern, maka pencocokan dapat memerlukan waktu eksponensial. Secara khusus, regexps dengan backreferences dapat mengenali bahasa NP-hard. Akibatnya, di bawah asumsi yang masuk akal, ada kelas regexps jahat di mana pengujian untuk pertandingan membutuhkan waktu yang eksponensial. Dengan demikian, beberapa regexps modern tidak terhindarkan jahat: tidak ada cara yang layak untuk menemukan regexp setara yang tidak akan menyebabkan ledakan eksponensial dalam menjalankan waktu untuk mencocokkan.
(Setara seperti itu mungkin ada dan bahkan mungkin dapat ditemukan dalam teori, tetapi di bawah asumsi yang masuk akal, menemukan regexp yang setara akan memakan waktu eksponensial, yang dalam praktiknya tidak layak. Jika Anda memiliki prosedur sistematis untuk menemukan regexp yang setara dalam waktu polinomial , maka Anda dapat memecahkan masalah NP-hard dalam waktu polinomial, membuktikan bahwa P = NP. Tidak ada gunanya bagi di sana untuk memiliki regexp yang setara jika tidak ada cara yang benar-benar menemukannya dalam masa hidup Anda.)
Latar belakang dan sumber:
Bahasa apa yang dikenali oleh ekspresi reguler yang kompatibel dengan Perl? dan Ekspresifitas dari ekspresi reguler modern memberikan referensi untuk membenarkan bahwa regexps modern dapat mengenali bahasa NP-hard.
Bagaimana cara mensimulasikan backreferences, lookaheads, dan lookbehinds di automata state yang terbatas? dan Kapan regexp bukan Ekspresi Reguler? dapat membantu untuk memahami perbedaan antara ekspresi reguler dan regexps.
Artikel dari Russ Cox ini memiliki penjelasan yang bagus tentang dua cara yang berbeda untuk membangun pencocokan ekspresi reguler, dan menjelaskan mengapa waktu berjalan jika Anda menggunakan algoritma yang tepat adalah linier dalam panjang string input (ketika ekspresi reguler dipertahankan tetap dan panjangnya diperlakukan sebagai konstanta). Secara khusus, algoritma berbasis NFA - juga dikenal sebagai algoritma Thompson - memiliki linier waktu berjalan terburuk. Ini juga menunjukkan bagaimana beberapa bahasa populer memiliki implementasi regexp yang bisa eksponensial pada beberapa regexps, dan itu membahas aspek mana dari regexps modern yang dapat memperkenalkan waktu running eksponensial.
Dalam posting ini saya menganggap P! = NP. Lebih tepatnya, ketika saya merujuk pada "asumsi yang masuk akal", saya merujuk pada hipotesis waktu eksponensial .
sumber
Jawaban ini akan mengambil pandangan yang lebih menyeluruh tentang situasi lintas sektor yang tidak biasa ini, di mana teori kompleksitas berlaku untuk cybersecurity dan contohnya berisi beberapa nuansa / kehalusan signifikan yang dapat terjadi di area ini. Ini pada dasarnya mirip dengan "serangan injeksi" di mana input tak terduga tertentu menyebabkan perilaku patologis menabrak sistem atau menyebabkannya memakan waktu lama secara tidak normal.
Wikipedia memiliki 15 kategori serangan Denial of Service dan serangan ini termasuk dalam "banjir tingkat aplikasi" dalam daftar itu. Contoh lain yang agak mirip adalah serangan yang mengisi log aplikasi.
Salah satu perbaikan untuk serangan injeksi adalah "membersihkan input". Perancang aplikasi dapat mengevaluasi ulang jika perlu mengkompilasi regexps sewenang-wenang yang disediakan oleh pengguna yang berpotensi jahat. Hanya dengan menghilangkan ekspresi bersarang di regexp atau batasan serupa lainnya mungkin cukup untuk menghindari serangan ini. Walaupun mereka intrinsik bagi banyak perangkat lunak modern, sejumlah besar fungsi dapat disediakan tanpa mengevaluasi ekspresi reguler. Konteksnya penting, beberapa aplikasi tidak memerlukan keamanan seperti itu.
Pendekatan lain untuk meningkatkan toleransi kesalahan / ketahanan yang berlaku di sini adalah batas waktu ditentukan pada berbagai tingkat tumpukan / hierarki perangkat lunak. Idenya adalah untuk menentukan waktu / cpu atau batas instruksi pada evaluasi ekspresi reguler "rata-rata" dan berakhir lebih awal jika terlampaui. Mereka dapat diimplementasikan dengan solusi khusus tetapi tidak terlalu banyak perangkat lunak atau bahasa pemrograman memiliki batas waktu atau kerangka kerja bawaan untuk tujuan ini.
Berikut adalah contoh yang bagus dari penggunaan timeout untuk meningkatkan toleransi kesalahan dan menunjukkan desain / arsitektur / pov tingkat tinggi untuk mengurangi masalah seperti: Toleransi Kesalahan dalam Volume Tinggi, Sistem Terdistribusi / Netflix. Ini tidak ada yang secara khusus terhubung ke ekspresi reguler tetapi itulah intinya di sini: hampir semua logika level aplikasi dapat masuk ke dalam kerangka kerja ini atau sesuatu yang serupa.
Artikel ini menunjukkan bagaimana melacak kembali secara khusus dapat menyebabkan pencocokan regexp lambat. Regexps memiliki banyak fitur berbeda dan seseorang dapat mencoba untuk mengevaluasi mana yang mengarah pada perilaku terburuk.
Berikut ini adalah survei ilmiah yang bagus tentang topik khusus ini dengan solusi analisis statis yang diajukan:
Analisis Statis untuk Ekspresi Runtime Eksponensial Reguler melalui Logika Substruktural / Rathnayake, Thielecke
sumber