Trumpai: įkėlimo užklausų filtravimas pakraštyje reiškia multipart/form-data tipo POST užklausų atmetimą tarpiniame serveryje (proxy), žiniatinklio serveryje ar WAF, jei jos nėra skirtos žinomam įkėlimo keliui. Specializuoti autoriai tai siūlo kaip laikiną, neoficialią priemonę nuo PHP2Shell. Ji gali sulaužyti formas ir įkėlimus ir niekada nepakeičia atnaujinimo. Elkitės trimis žingsniais: registruokite, nustatykite išimtis, tik tada blokuokite, su fiksuota pabaigos data.
Pasiūlymas iš specializuotos diskusijos
Kol serveris nepataisytas, operatoriai ieško visko, kas mažina riziką. Specializuotoje PHP2Shell diskusijoje pasirodė toks pasiūlymas: POST užklausas formatu multipart/form-data, taigi formatu failų įkėlimams ir kai kurioms formoms, leisti tik ten, kur programa jų iš tikrųjų tikisi. Visos kitos atmetamos tarpiniame serveryje arba žiniatinklio programų ugniasienėje (Web Application Firewall).
Svarbu tinkamai įvertinti. Pasiūlymas ateina ne iš php.net, o iš specializuotų autorių, ir aiškiai skirtas kaip laikina priemonė. php.net nurodo savo pereinamąsias priemones, surinktas skyriuje Skubios priemonės, kai dar negalite pataisyti. Filtras gali jas papildyti, bet ne pakeisti.
Čia aprašome, kaip jį įvesti kontroliuojamai. Detales, kodėl jis galėtų padėti nuo kurių atakų, sąmoningai praleidžiame.
Ką filtras duoda ir kur kenkia
Mintis už jo yra atakos paviršiaus sumažinimas. Daugumai svetainės puslapių failų įkėlimų nereikia. Jei tokias užklausas priima tik keli žinomi keliai, didelė dalis galimų atakos bandymų PHP apskritai nepasiekia.
Kita pusė taip pat aiški. Kiekviena funkcija, kuri siunčia multipart užklausas ir nėra išimčių sąraše, nustoja veikti. Tai liečia ne tik akivaizdžias įkėlimo formas.
| Funkcija | Dažnai naudoja multipart/form-data | Rizika blokuojant |
|---|---|---|
| Kontaktų ir paraiškų formos su priedu | taip | užklausos prarandamos |
| Medijos valdymas CMS administravime | taip | redakcija negali įkelti paveikslėlių |
| Produktų ar klientų importas | taip | sąsajos lūžta tyliai |
| Formos be priedo | kartais | priklauso nuo formų konstruktoriaus |
| Sąsajos ir išorinių paslaugų atgaliniai pranešimai | retai, bet įmanoma | gedimas pastebimas vėlai |
Be to, yra esminė problema: Cloudflare, kuris pats įdiegė apsaugos taisykles nuo PHP2Shell, perspėja, kad vien taisyklių pagal užklausos duomenis nepakanka. Kaip abu lygmenis galvoti kartu, aprašo WAF ar atnaujinimas: kodėl reikia abiejų.
1 žingsnis: pirmiausia registruoti, paskui blokuoti
Prieš ką nors blokuodami išsiaiškinkite, kurie keliai apskritai gauna multipart užklausas. Standartiniai žurnalai turinio tipo nerodo. Todėl Nginx laikinai sukurkite savo žurnalą:
# http bloke
map $uri $upload_pfad {
default 0;
~^/kontakt/upload\.php$ 1;
~^/admin/medien/ 1;
}
map "$request_method:$upload_pfad:$content_type" $multipart_fremd {
default 0;
"~*^POST:0:multipart/form-data" 1;
}
log_format multipart '$time_iso8601 $remote_addr "$request" "$content_type" $status';
# server bloke
# Dėmesio: access_log server bloke pakeičia paveldėtą žurnalą,
# todėl įprastą žurnalą čia nurodykite iš naujo.
access_log /var/log/nginx/access.log combined;
access_log /var/log/nginx/multipart-test.log multipart if=$multipart_fremd;
$upload_pfad įrašai yra pavyzdžiai. Pradėkite su tuščiu išimčių sąrašu, tada bandomasis žurnalas parodys visus multipart POST. Su Apache tą patį galima pasiekti su aplinkos kintamuoju:
# VirtualHost
SetEnvIfNoCase Content-Type "^multipart/form-data" ist_multipart
CustomLog ${APACHE_LOG_DIR}/multipart-test.log combined env=ist_multipart
Leiskite žurnalui veikti kelias dienas, pageidautina laikotarpiu, kai aktyvi ir redakcija, kandidatai bei sąsajos.
2 žingsnis: nustatyti išimtis ir kontroliuojamai blokuoti
Iš bandomojo žurnalo išveskite kelius, kuriems teisėtai reikia įkėlimų. Sąrašą suderinkite su atsakingais asmenimis: kas prižiūri turinį, kokios formos yra, kurios paslaugos siunčia duomenis?
- Sudaryti išimčių sąrašą iš žurnalo ir pasiteiravimų ir įrašyti jį į
$upload_pfadarbaRewriteCondeilutes. - Filtrą pirmiausia aktyvuoti testinėje aplinkoje arba ramiu laiko tarpu.
- Patiems išbandyti visas formas, įkėlimus ir užsakymo kelius.
- Stebėti klaidų žurnalą dėl atmestų užklausų (būsena 403) ir prireikus papildyti sąrašą.
- Nustatyti pabaigos datą: po PHP atnaujinimo ir visų darbinių procesų (worker) paleidimo iš naujo filtras vėl pašalinamas.
Nginx tam serverio bloke pridedamas užraktas:
# server bloke, po žurnalo fazės įvertinimo
if ($multipart_fremd) {
return 403;
}
Apache užduotį atlieka mod_rewrite. Pasak Apache dokumentacijos, kelios sąlygos jungiamos su IR:
RewriteEngine On
RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP:Content-Type} ^multipart/form-data [NC]
RewriteCond %{REQUEST_URI} !^/kontakt/upload\.php$
RewriteCond %{REQUEST_URI} !^/admin/medien/
RewriteRule ^ - [F]
Jei naudojate CDN ar debesies WAF, ta pati logika dažnai gali būti atvaizduota kaip atskira taisyklė. Ir čia galioja: pirmiausia registravimo režimu, paskui blokuoti.
Filtras nėra PHP atnaujinimo pakaitalas ir nėra priežastis jį atidėti. PHP2Shell ištaisytas tik su PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 arba patvirtintu atgaliniu pataisų perkėlimu (backport), po kurio iš naujo paleidžiami visi PHP procesai.
Teisingas priemonės įvertinimas
Įkėlimo filtras priklauso eilei kitų šiuo metu plintančių pasiūlymų. Kai kurie prasmingi, kiti žalingi. Apžvalgą, kuriuos patarimus specializuoti autoriai atmeta, pavyzdžiui, visų užklausų su sesijos slapuku blokavimą, pateikia Pavojingi klaidingi patarimai dėl PHP2Shell.
Kaip PHP viduje apdoroja įkėlimus ir kodėl formatas multipart/form-data čia vaidina ypatingą vaidmenį, paaiškina Kaip PHP apdoroja failų įkėlimus. Dauguma įmonių svarbiausias žingsnis vis dėlto yra ne filtras, o aiškus atnaujinimo terminas.
Išvada: įrankis dienoms, ne mėnesiams
Įkėlimo filtras pakraštyje yra tipiškas avarinės priemonės pavyzdys: jis gali sumažinti atakos paviršių pereinamuoju laikotarpiu, bet turi šalutinių poveikių ir neturi oficialios php.net paramos. Tinkamai naudojamas, su registravimo faze, suderintu išimčių sąrašu, bandymais ir fiksuota pabaigos data, jis pateisinamas. Be šių žingsnių rizikuojate prarastomis paraiškomis, užblokuotomis redakcijomis ir tylomis sąsajų klaidomis.
Todėl sprendimą priimkite sąmoningai ir užfiksuokite, kas ir kada jį priėmė. Ir nepamirškite eilės tvarkos: pirmiausia PHP atnaujinimas su visų darbinių procesų paleidimu iš naujo, php.net pereinamosios priemonės užpildo laiką iki to, o filtras daugių daugiausia yra papildomas sluoksnis.
Kaip PHP SOS padeda konkrečiai?
- Įvertinti padėtį: išsiaiškiname, ar įkėlimo filtras jūsų situacijoje apskritai prasmingas, ar atnaujinimas galimas greičiau.
- Registruoti ir analizuoti: įrengiame registravimo fazę ir išimčių sąrašą išvedame iš tikrų kreipinių.
- Kontroliuojamai blokuoti: aktyvuojame filtrą, išbandome formas ir užsakymo kelius ir stebime atmestas užklausas.
- Švariai atšaukti: WAF ir virtualaus pataisymo rėmuose po atnaujinimo filtrą vėl pašaliname.
Dažni klausimai
Ar multipart užklausų filtravimas yra oficiali php.net rekomendacija?
Ne. php.net nurodo kitas pereinamąsias priemones, pavyzdžiui, post_max_size ribas ir session.upload_progress išjungimą. Filtravimas pakraštyje yra specializuotų straipsnių pasiūlymas ir aiškiai skirtas tik kaip laikina priemonė.
Kurios funkcijos dėl filtro gali nustoti veikti?
Viskas, kas siunčia failus ar formas multipart formatu ir nėra jūsų išimčių sąraše: kontaktų formos su priedu, paraiškų formos, CMS medijos valdymas, importo funkcijos, kai kurios sąsajos ir mokėjimų atgaliniai pranešimai. Todėl prieš blokuojant yra registravimo fazė.
Ar filtras pakeičia PHP atnaujinimą?
Ne. Jis daugių daugiausia sumažina atakos paviršių pereinamuoju laikotarpiu. Pats Cloudflare pažymi, kad vien taisyklių pagal užklausos duomenis nepakanka. PHP2Shell ištaisytas tik su pataisyta PHP versija ir visų darbinių procesų (worker) paleidimu iš naujo.
Ar vietoj to turėčiau blokuoti užklausas su PHPSESSID?
Ne. Šį plintantį patarimą specializuoti autoriai aiškiai atmeta. Jis paralyžiuoja prisijungimus ir krepšelius nesuteikdamas patikimos apsaugos.