Praegune olukord: PHP2Shell. Kaks kriitilist PHP turvaauku (CVSS 9,2) lubavad kahjulikku koodi ilma sisselogimata. Paigad alates 21.10.2026.Mida nüüd teha →

Command Injection'i vältimine PHP-s

Kuidas arendajad väldivad PHP-s Command Injection'i: süsteemikäskude asendamine PHP funktsioonidega, proc_open kasutamine ilma shellita, argumentide kontroll ja ohtlike kohtade leidmine olemasolevas koodis.

Seis Lugemisaeg 4 minTurvaline arendus

Lühidalt: Command Injection'i hoiate PHP-s kõige kindlamalt ära, kui ei kutsu shelli üldse: paljud ülesanded täidavad PHP funktsioonid või teegid otse. Kus on vaja välist programmi, annate käsu PHP 7.4-st alates massiivina funktsioonile proc_open(), siis käivitab PHP programmi ilma shellita. Väärtusi kontrollite lubatud väärtuste nimekirja vastu, lõpetate valikud märgiga -- ja laete protsessi töötama minimaalsete õigustega.

Miks on süsteemikutsel nii palju võimu

Pilditöötlus, PDF-i loomine, arhiveerimine, viirusekontroll, DNS-kirje päring: selliste ülesannete jaoks kutsuvad PHP-rakendused meelsasti väliseid programme. Tehniliselt on see mugav, piisab ühest exec() või shell_exec() reast. Turvatehniliselt on see koodi üks ohtlikumaid kohti.

Kui käsk pannakse tekstina kokku ja selle täidab shell, otsustab shell, mis on käsk ja mis andmed. Kui väljastpoolt tuleb väärtus kontrollimata sisse, võib see käsu tähendust muuta. Halvimal juhul on tagajärg sama mis PHP2Shelli puhul: suvaliste käskude täitmine serveris PHP protsessi õigustega.

Vahe: PHP2Shelli kõrvaldate PHP uuendusega. Command Injection oma koodis jääb alles pärast iga uuendust. Lisaks asuvad sellised kohad sageli abiskriptides, mis olid mõeldud ainult administraatoritele, näiteks hoolduseks, diagnostikaks või impordiks, ning jäävad hiljem kaitseta kättesaadavaks.

Kus Command Injection PHP-s tekib

Ohus on iga koht, kus PHP käivitab shelli või programmi. Selleks mõeldud funktsioonid on:

Funktsioon Kas kasutab shelli? Märkus
exec(), system(), passthru(), shell_exec() jah käsk tekstina, shell tõlgendab seda
Backtick-operaator jah vastab funktsioonile shell_exec()
popen() jah käsk tekstina
proc_open() stringiga jah käsk tekstina
proc_open() massiiviga ei PHP 7.4-st, argumendid antakse otse üle
mail() viienda parameetriga kaudselt lisaparameetrid meiliprogrammile

Tüüpiline ebaturvaline muster näeb välja nii. Failinimi tuleb päringust ja satub otse käsureale:

<?php
// EBATURVALINE: päringust pärit väärtus saab shelli käsu osaks
$datei = $_POST['datei'];
exec('convert uploads/' . $datei . ' -resize 800x800 vorschau/' . $datei);

Esimene valik: üldse mitte shelli

Kõige tõhusam kaitse on süsteemikutse asendamine. OWASP nimetab seda selgesõnaliselt esimeseks kaitseliiniks. Paljude ülesannete jaoks on PHP-s olemas omad funktsioonid või laiendused:

  • Kaustad ja failid: mkdir(), copy(), rename(), unlink()
  • Arhiivid: ZipArchive või PharData
  • Pildid: GD või Imagick PHP laiendusena
  • Võrgupäringud: dns_get_record(), gethostbyname(), cURL
  • Kontrollsummad: hash_file()

Sellega kaob küsimus, milliseid märke shell tõlgendab, täielikult. Lisaks saab süsteemikäskude funktsioone siis konfiguratsioonis keelata, nagu kirjeldab juhend disable_functions õigesti kasutada.

Kui väline programm on vajalik: proc_open massiiviga

PHP 7.4-st aktsepteerib proc_open() käsku massiivina. PHP käsiraamatu kohaselt käivitatakse protsess siis otse, ilma shelli ringkäiguta, ja PHP võtab enda peale argumentide vajaliku maskeerimise. Märkidel nagu semikoolon või toru pole siis enam erimärgitust.

<?php
declare(strict_types=1);

$name = basename((string) ($_POST['datei'] ?? ''));
if (!preg_match('/^[a-z0-9_-]{1,64}\.(jpg|png)$/', $name)) {
    throw new InvalidArgumentException('Ungültiger Dateiname.');
}

$befehl = ['/usr/bin/convert', '/srv/app/uploads/' . $name, '-resize', '800x800',
           '/srv/app/vorschau/' . $name];

$prozess = proc_open($befehl, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
if (!is_resource($prozess)) {
    throw new RuntimeException('Programm konnte nicht gestartet werden.');
}
$fehlerausgabe = stream_get_contents($pipes[2]);
$status = proc_close($prozess);

Kolm asja teevad näite töökindlaks: programm on täieliku teega koodis fikseeritud, failinimi kontrollitakse kitsa mustri vastu ja iga muutuv argument algab absoluutse teega, seega ei saa seda valikuna lugeda. Kus väärtus seisab üksi, lõpetage valikud märgiga --, kui programm seda dokumentatsiooni järgi toetab, või lükake tagasi väärtused, mis algavad sidekriipsuga.

Ülesannete puhul, mis vajavad regulaarselt väliseid programme, näiteks suuremahuline pildi- või PDF-töötlus, tasub lahti siduda: veebirakendus paneb ainult töö järjekorda, eraldi taustateenus oma kasutaja ja õigustega täidab selle. Internetist tulevatele päringutele vastav PHP protsess ei vaja siis enam süsteemikäskude funktsioone ja need saab tema jaoks keelata. Välistel programmidel peaksid lisaks olema aja- ja mälupiirangud, et üksik töö serverit ei blokeeriks.

Erijuht on mail(). Viies parameeter annab lisavalikud süsteemi meiliprogrammile. Vormidest pärit väärtused, näiteks saatja aadress, ei tohi sinna kunagi kontrollimata sattuda. Töökindlam on meiliteek, mis saadab SMTP kaudu ega vaja süsteemikutset.

escapeshellarg: õigesti kasutada ja piire teada

Kus olemasolev kood töötab veel käsurealiinidega, on escapeshellarg() iga üksiku väärtuse jaoks miinimummeede. Funktsioon paneb väärtuse jutumärkidesse, nii et shell käsitleb seda täpselt ühe argumendina. escapeshellcmd() ei sobi kasutaja sisendile, sest see lubab lisaparameetreid, nagu OWASP näitega näitab.

escapeshellarg() olulised piirid:

  1. Argumendi-injection jääb võimalikuks: Maskeeritud väärtust, mis algab sidekriipsuga, loeb sihtprogramm siiski valikuna.
  2. Windows käitub teisiti: Seal asendab funktsioon käsiraamatu kohaselt teatud märgid, nagu % ja ", tühikutega; väärtused jõuavad kohale muudetuna.
  3. Märgistik: Olenevalt serveri locale-sättest võivad mitte-ASCII märgid kaduda.

Leidude otsimine olemasolevast koodist

Süsteemikutsete otsing käib kiiresti ja annab ülevaatliku nimekirja:

grep -rnE "\b(exec|system|passthru|shell_exec|popen|proc_open)\s*\(" src/ --include="*.php"
grep -rn '`' src/ --include="*.php" | grep -v '^\s*//'

Iga leid vajab vastust kolmele küsimusele: Kas kutse saab asendada PHP funktsioonidega? Kas väljastpoolt voolab väärtusi sisse? Milliste õigustega protsess töötab? Viimane küsimus on otsustav kahju jaoks hädaolukorras. Oma kasutajaga ja koodile kirjutusõigusteta PHP protsess teeb vähem kahju, vt Vähima õiguse põhimõte: veebiserveri kasutaja õigused.

Oluline

Kui PHP-FPM-i või veebiserveri protsess käivitab shelli, on see tugev hoiatusmärk sissemurdmisest. Kuidas seda ära tunda, kirjeldab Hoiatusmärk: veebiserver käivitab shelli.

Kuidas PHP SOS konkreetselt aitab?

  • Me otsime kõik süsteemikutsed teie rakendusest, pistikprogrammidest ja abiskriptidest.
  • Me asendame kutsed võimaluse korral PHP funktsioonidega ja viime ülejäänud üle kutsetele ilma shellita.
  • Me keelame PHP konfiguratsioonis mittevajalikud funktsioonid ja kontrollime PHP kasutaja õigusi.
  • Me testime muudatused ja dokumenteerime, milliseid programme rakendus tohib veel kutsuda.

Oma tarkvara kontrolli pakume turvaauditi ja läbitungimistestina.

Korduma kippuvad küsimused

Kas escapeshellarg piisab Command Injection'i vastu?

See takistab väärtuse käivitamist järgmise käsuna. See ei takista, et kutsutud programm loeb väärtust valikuna, kui see algab sidekriipsuga. Seetõttu kontrollige väärtusi lisaks ja lõpetage valikud, kus programm seda toetab, märgiga --.

Mis vahe on escapeshellarg'il ja escapeshellcmd'il?

escapeshellarg käsitleb üksikut väärtust täpselt ühe argumendina. escapeshellcmd maskeerib ainult metamärgid kogu käsureal ja lubab lisaparameetreid. Kasutaja sisendi jaoks on escapeshellarg õige valik, kutse ilma shellita on veel parem.

Kas peaksin exec'i ja system'i disable_functions abil keelama?

Kui teie rakendus neid ei vaja, siis jah. See piirab kahju pärast sissemurdmist. See ei asenda aga turvalist koodi, sest käske vajavad rakendused vajavad neid funktsioone edasi.

Kuidas ma tunnen ära, kas Command Injection'it on ära kasutatud?

Tugev hoiatusmärk on PHP või veebiserveri protsessid, mis käivitavad shelli, nagu sh või bash. Lisaks tundmatud protsessid, uued failid üleslaadimiskaustades ja ebatavalised väljaminevad ühendused.

Allikad

Kohene kontakt

Iga tund loeb. Kirjutage meile kohe.

Kirjeldage lühidalt süsteemi, PHP versiooni ja tähelepanekut. Võtame teiega ühendust, selgitame olukorra välja ja töötame kaugtööna, kuni intsident on lõpetatud ja dokumenteeritud.

Kohene abi