Menggunakan WP 4.8.2
Apa cara terbaik untuk memeriksa URL yang meminta ketika memproses permintaan dengan api sisanya?
Misalnya, sebuah situs menerima permintaan dan Anda ingin memeriksa apakah itu berasal dari URL yang 'diizinkan'. Dan gagal jika URL tidak diizinkan.
Ini tidak bekerja:
function my_check_request_url( $request, $url ) {
$bits = parse_url( $url );
if ( $bits['host'] != 'example.com' )
$request = false;
return $request;
}
add_filter( 'rest_request_from_url', 'my_check_request_url', 10, 2 );
$request
dan$url
vars melaluivar_dump
atau serupa, saya menemukan bahwa memeriksa input dan output selalu mengarah ke jawaban yang tepat.Jawaban:
Filter itu jelas bukan yang Anda cari. Filter itu menyala sebelum mengembalikan hasil
WP_REST_Request::from_url()
yang tampaknya merupakan metode pabrik yang hanya digunakan secara internal untuk menangani embed.Opsi yang lebih baik adalah mengembalikan
WP_Error
instance padarest_pre_dispatch
filter .Beberapa peringatan:
Seperti yang disebutkan oleh @ moilo, referer tidak dapat diandalkan dan tidak seharusnya digunakan untuk pemeriksaan keamanan.
Selain itu, tidak dijamin untuk diatur.
Dengan hal-hal yang menghalangi, berikut adalah contoh bagaimana Anda dapat menggunakan
rest_pre_dispatch
filter untuk menyebabkan permintaan gagal jika berasal dari pengarah yang buruk:sumber
Apa pun yang Anda terima dari klien dianggap sebagai input pengguna dan tidak boleh dipercaya. Karena tajuk dapat dengan mudah dimanipulasi dan disalahgunakan, saran saya adalah jangan menggunakan metode ini jika Anda mengandalkannya untuk data sensitif.
Jika permintaan datang dari halaman, Anda dapat memiliki pendekatan lain. Kalau tidak, siapa pun dapat mengirim permintaan ke API entah dari mana dan mengubah pengarah.
Katakanlah Anda memiliki banyak halaman yang difilter sebagai "Diizinkan" . Anda dapat membuat nounce hanya untuk halaman-halaman ini, dan kemudian memvalidasinya dalam permintaan Anda.
Jika ada nounce dan valid, maka permintaan diizinkan. Kalau tidak, blokir.
sumber
@ssnepenthe 's aswer adalah benar dalam mengatakan bahwa hook Anda gunakan bukan orang yang tepat sesuatu dalam permintaan yang masuk.
Informasi permintaan tersedia segera ke PHP, jadi Anda bisa menggunakan pengait paling awal yang tersedia untuk memeriksanya. Dan jika Anda ingin melakukan ini dalam konteks API permintaan, Anda harus menggunakan hook paling awal dari permintaan REST API.
'rest_pre_dispatch'
disarankan oleh @ssnepenthe baik-baik saja, mungkin opsi lainrest_authentication_errors
yang memungkinkan Anda untuk mengembalikan kesalahan jika ada sesuatu yang salah.Tetapi Jack Johansson benar dalam mengatakan bahwa header HTTP (seperti header referer yang digunakan dalam aswer @ ssnepenthe) tidak dapat dipercaya, karena mereka sangat mudah diubah oleh klien. Jadi itu akan seperti menempatkan seorang penjaga keamanan di depan pintu yang hanya bertanya "apakah aman untuk membiarkan Anda masuk?" untuk siapa saja yang ingin masuk: itu tidak akan berhasil.
Tetapi soluisi yang diajukan jawaban Jack Johansson (nonce) juga bukan solusi nyata: seluruh titik nonces adalah berubah seiring waktu, dan titik akhir API publik tidak dapat memiliki hal-hal yang berubah berdasarkan waktu. Selain itu, WP nonces hanya dapat dipercaya ketika ada pengguna yang masuk, yang mungkin tidak berlaku untuk API publik dan jika pengguna masuk, mungkin tidak ada alasan untuk memeriksa domain yang masuk: Anda mempercayai pengguna, bukan mesin pengguna.
Jadi, apa yang harus dilakukan?
Ya, meskipun header HTTP tidak dapat dipercaya, tidak semua informasi yang tersedia
$_SERVER
berasal dari header.Biasanya, semua
$_SERVER
nilai yang kunci-kuncinya dimulai yang dimulai denganHTTP_
berasal dari header dan harus diperlakukan sebagai input pengguna yang tidak aman .Tetapi, misalnya,
$_SERVER['REMOTE_ADDR']
berisi alamat IP yang digunakan untuk koneksi TCP ke server Anda, yang berarti itu dapat dipercaya 1 .Yang juga berarti, bahwa:
$_SERVER['REMOTE_HOST']
nilai (misalnya di Apache Anda perluHostnameLookups On
di dalam Andahttpd.conf
) nilai itugethostbyaddr
untuk melakukan pencarian DNS terbalik untuk menyelesaikan nama domain dari IP yang disimpan di$_SERVER['REMOTE_ADDR']
Anda dapat memperoleh nama host yang cukup andal yang dapat Anda gunakan untuk mengecek daftar putih (untuk kode, Anda dapat mengadaptasi kode dari aswer @ ssnepenthe di mana Anda akan menggantinya
$referer = $request->get_header('referer')
dengan$referer = gethostbyaddr($_SERVER['REMOTE_ADDR'])
).Tapi ada masalah .
Jika server web Anda berada di belakang proksi terbalik (solusi yang cukup umum, sebenarnya) koneksi TCP ke server sebenarnya dibuat oleh proksi tersebut, maka itu
$_SERVER['REMOTE_ADDR']
akan menjadi IP dari proksi tersebut, dan bukan IP dari klien yang awalnya mengirim permintaan.IP permintaan asli dalam kasus seperti itu biasanya tersedia sebagai
$_SERVER['HTTP_X_FORWARDED_FOR']
, tetapi menjadi salah satu dari$_SERVER
nilai - nilai yang dimulai denganHTTP_
itu tidak benar-benar dapat dipercaya.Jadi, jika server web Anda berada di belakang proxy terbalik 2 bahkan
$_SERVER['REMOTE_ADDR']
tidak akan berguna untuk penjaga tersebut dan daftar putih berbasis domain hanya bisa diimplementasikan di tingkat proxy.Singkatnya, solusi yang dapat diandalkan untuk pengamanan titik akhir API harus diimplementasikan dengan menggunakan beberapa mekanisme otentikasi nyata (misalnya oAuth) atau harus dilakukan dengan bertindak langsung pada konfigurasi server dan tidak pada tingkat aplikasi.
Catatan
1 Ya, secara teori itu bisa rusak jika seseorang meretas ISP Anda atau jika penyerang bertindak dari dalam LAN Anda, dalam kedua kasus sangat sedikit yang bisa Anda lakukan untuk aman.
2 Jika Anda tidak tahu apakah Anda berada di belakang proxy terbalik, Anda dapat mengirim permintaan dari PC lokal Anda dan memeriksa apakah
$_SERVER['REMOTE_ADDR']
di server cocok dengan IP PC lokal dan juga jika$_SERVER['HTTP_X_FORWARDED_FOR']
ada dan cocok dengan IP PC lokal.sumber