Skip to content

Kõik WordPressist, veebiarendusest — ja mitte ainult

🔒 Failide krüptimine ja dekrüptimine PHP-s: OpenSSL ja Sodium mcrypti asemel

🔒 Failide krüptimine ja dekrüptimine PHP-s: OpenSSL ja Sodium mcrypti asemel

Fail krüpteerida enne serverisse salvestamist ja ole kindel, et keegi, isegi mitte hostingu administraator, ei saa seda ilma võtmeta lugeda. Kõlab nagu elementaarne vajadus, kuid kuna mcrypt PHP-st lahkub, lakkas tuttav lähenemine töötamast.

Mcrypt laiendus märgiti aegunuks PHP 7.1-s ja eemaldati täielikult PHP 7.2-s juba 2017. aastal. Täna, PHP 8 peal, lõpeb mcrypt_encrypt() väljakutse saatusliku veaga. Samal ajal istuvad serverites endiselt konfidentsiaalsed failid: andmebaasi varukoopiad, isikuandmetega CSV-d, PDF-lepingud, tellimuste ekspordid.

Hea uudis: PHP pakub karbist võttes kahte toimivat mehhanismi, OpenSSL ja Sodium. Mõlemad ei vaja kaasaegsel hostinguplatvormil täiendavat laienduse paigaldust, mõlemad on mcryptist kiiremad ja turvalisemad. Allpool on praktiline juhend failide krüpteerimiseks ja dekrüpteerimiseks PHP 8 peal koos koodiga, mida saad kopeerida ja käivitada.

💡 Kiirülevaade:

  • Miks mcrypt on surnud ja milliseid PHP versioone see puudutab
  • Samm-sammuline faili krüpteerimine OpenSSL-iga, kasutades AES-256-CBC-d
  • Dekrüpteerimine koos andmete rikkumise kaitsega HMAC-i abil
  • Sodium alternatiiv PHP 7.2-le ja uuemale
  • Millal valida OpenSSL ja millal Sodium

Miks mcrypt ei ole enam valik

Mcrypt teeki ei ole uuendatud alates 2007. aastast. Selle koodist leiti kriitilisi turvaauke ja hooldajaid ei olnud enam järel. PHP meeskond tegi otsuse: PHP 7.1-s märgiti laiendus aegunuks ja PHP 7.2-s, mis ilmus 2017. aasta novembris, eemaldati see tuumast täielikult.

Kui migreerid vana projekti, kus on mcrypt, kontrolli phpinfo(). PHP 7.2+ puhul ei ole seal rida "mcrypt support: enabled". mcrypt_encrypt(), mcrypt_decrypt() või voofiltrite mcrypt.tripledes / mdecrypt.tripledes väljakutse tagastab vea "Call to undefined function".

Tehniliselt on mcrypt saadaval PECL-i kaudu käsuga pecl install mcrypt. Kuid tootmiskeskkonna serverisse ühe pärandskripti jaoks toetamata ja teadaolevate turvaaukudega laienduse paigaldamine on halb mõte. Kirjuta krüpteerimine ümber OpenSSL-iga: see on sisse ehitatud PHP-sse alates versioonist 5.3 ega kao kuhugi.

Faili krüpteerimine OpenSSL-iga, samm-sammult

OpenSSL-i esindavad PHP-s funktsioonid openssl_encrypt() ja openssl_decrypt(). Need töötavad toorandmetega ja toetavad kümneid algoritme, alates AES-128-CBC-st kuni AES-256-GCM-ini. Failide jaoks kasutame AES-256-CBC-d: see on krüptograafiliselt tugev ega vaja erinevalt GCM-ist koos täiendavate tag'i parameetritega PHP 7.1.

1. Samm: genereeri krüpteerimisvõti

Võti on kogu skeemi peamine saladus. See peab olema krüptograafiliselt juhuslik, mitte käsitsi välja mõeldud. Ei mingeid näidetest pärit "secret-password"-e, ainult openssl_random_pseudo_bytes().

Allolev skript genereerib 256-bitise võtme ja väljastab selle vormingus, mis sobib sisestamiseks wp-config.php-sse. Käivita üks kord käsurealt ja salvesta tulemus:

1<?php
2// Generating a random 256-bit key (32 bytes)
3$encryption_key = base64_encode(openssl_random_pseudo_bytes(32));
4echo "define('FILE_ENCRYPTION_KEY', '" . $encryption_key . "');\n";

Funktsioon openssl_random_pseudo_bytes(32) tagastab 32 baiti krüptograafiliselt kvaliteetset juhuslikkust. base64_encode teisendab binaarandmed stringiks, mida on mugav konfiguratsioonifailides hoida. Võti peab asuma väljaspool dokumendijuurt, failis wp-config.php või .env, kuid mitte teema koodis.

2. Samm: faili krüpteerimise funktsioon

Skript loeb faili kettalt, krüpteerib AES-256-CBC algoritmiga, lisab algusesse juhusliku IV ja terviklikkuse kontrolliks HMAC allkirja, salvestab tulemuse. Lisa kood alamteema functions.php faili või kohandatud pluginasse.

Hoiatus: enne tootmiskeskkonna serveris käivitamist tee täielik varukoopia. Testi krüpteerimist-dekrüpteerimist faili koopial testkataloogis. Kui võti kaob, on andmete dekrüpteerimine võimatu, AES-256 ei ole toore jõuga murtav.

1<?php
2function encrypt_file(string $sourcePath, string $destPath, string $key): bool
3{
4 if (!file_exists($sourcePath)) {
5 throw new RuntimeException('Source file not found: ' . $sourcePath);
6 }
7
8 $plaintext = file_get_contents($sourcePath);
9 if ($plaintext === false) {
10 throw new RuntimeException('Failed to read file');
11 }
12
13 $cipher = 'aes-256-cbc';
14 $ivLength = openssl_cipher_iv_length($cipher);
15 $iv = openssl_random_pseudo_bytes($ivLength);
16
17 $ciphertext = openssl_encrypt(
18 $plaintext,
19 $cipher,
20 base64_decode($key),
21 OPENSSL_RAW_DATA,
22 $iv
23 );
24
25 if ($ciphertext === false) {
26 throw new RuntimeException('Encryption error');
27 }
28
29 // HMAC signature for integrity verification during decryption
30 $hmac = hash_hmac('sha256', $iv . $ciphertext, base64_decode($key), true);
31
32 // File format: IV (16 bytes) + HMAC (32 bytes) + ciphertext
33 $result = file_put_contents($destPath, $iv . $hmac . $ciphertext);
34
35 return $result !== false;
36}

Mis siin rida-realt toimub:

  • openssl_cipher_iv_length('aes-256-cbc') tagastab 16, selle algoritmi initsialiseerimisvektori pikkuse.
  • openssl_random_pseudo_bytes($ivLength) loob juhusliku IV. See muudab sama võtmega krüpteeritud identsed andmed igal käitusel erinevaks šifritekstiks.
  • OPENSSL_RAW_DATA ütleb funktsioonile, et see tagastaks binaarandmed, mitte base64. Salvestame toore šifriteksti kompaktsuse huvides.
  • hash_hmac('sha256', ...) arvutab kontrollsumma IV ja šifriteksti kimbust. Dekrüpteerimisel arvutame HMAC-i uuesti ja võrdleme: kui andmeid on muudetud või need on rikutud, siis võrdlus ei klapi.
  • Fail salvestatakse formaadis: [IV 16 bytes][HMAC 32 bytes][ciphertext]. Eraldajaid pole, positsioonid on fikseeritud pikkustega.

3. Samm: dekrüpteerimise funktsioon

Pöördprotsess: loe IV, loe HMAC, loe šifritekst, arvuta HMAC uuesti ja võrdle hash_equals() abil, dekrüpteeri. Kood lisatakse samasse faili:

1<?php
2function decrypt_file(string $sourcePath, string $key): string|false
3{
4 if (!file_exists($sourcePath)) {
5 throw new RuntimeException('Encrypted file not found: ' . $sourcePath);
6 }
7
8 $data = file_get_contents($sourcePath);
9 if ($data === false) {
10 throw new RuntimeException('Failed to read file');
11 }
12
13 $cipher = 'aes-256-cbc';
14 $ivLength = openssl_cipher_iv_length($cipher);
15 $hmacLength = 32; // sha256 = 32 bytes
16
17 $iv = substr($data, 0, $ivLength);
18 $hmac = substr($data, $ivLength, $hmacLength);
19 $ciphertext = substr($data, $ivLength + $hmacLength);
20
21 // Integrity check: recompute HMAC and compare
22 $calculatedHmac = hash_hmac(
23 'sha256',
24 $iv . $ciphertext,
25 base64_decode($key),
26 true
27 );
28
29 if (!hash_equals($hmac, $calculatedHmac)) {
30 throw new RuntimeException('File corrupted or key invalid');
31 }
32
33 $plaintext = openssl_decrypt(
34 $ciphertext,
35 $cipher,
36 base64_decode($key),
37 OPENSSL_RAW_DATA,
38 $iv
39 );
40
41 return $plaintext;
42}

Võtmepunkt: hash_equals(), mitte ===. Tavaline stringide võrdlus on ajastusrünnete suhtes haavatav, ründaja saab HMAC-i bait-baidi haaval tuletada, mõõtes serveri vastuseaega. hash_equals() võrdleb stringe konstantse ajaga, olenemata sellest, millise tähemärgi juures need lahknesid.

Kasutusnäide reaalsete radadega

1<?php
2$key = FILE_ENCRYPTION_KEY; // from wp-config.php
3
4// Encrypting the database backup
5encrypt_file(
6 __DIR__ . '/backup.sql',
7 __DIR__ . '/backup.sql.enc',
8 $key
9);
10
11// Decrypting and serving for download
12$decrypted = decrypt_file(__DIR__ . '/backup.sql.enc', $key);
13header('Content-Type: application/octet-stream');
14header('Content-Disposition: attachment; filename="backup.sql"');
15echo $decrypted;

Funktsioonid on universaalsed: need töötavad mis tahes failitüübiga, pildid, PDF, CSV, SQL tõmmised. Suurust piirab ainult saadaolev RAM, kuna fail loetakse tervenisti mällu. Gigabaidiste failide jaoks oleks vaja voogedastusega töötlemist tükkide kaupa puhverdamisega, kuid valdava enamuse praktiliste ülesannete jaoks on see kood piisav.

Alternatiiv: Sodium (libsodium)

Sodium laiendus on PHP-sse sisse ehitatud alates versioonist 7.2 ja sai tuuma osaks PHP 8.1-s. See pakub OpenSSL-iga võrreldes lihtsamat API-t: ei ole vaja käsitsi hallata IV-d ja HMAC-i, autenditud krüpteerimine töötab karbist võttes.

1<?php
2function sodium_encrypt_file(string $sourcePath, string $destPath, string $key): bool
3{
4 $plaintext = file_get_contents($sourcePath);
5 $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
6 $ciphertext = sodium_crypto_secretbox($plaintext, $nonce, base64_decode($key));
7 return file_put_contents($destPath, $nonce . $ciphertext) !== false;
8}
9
10function sodium_decrypt_file(string $sourcePath, string $key): string|false
11{
12 $data = file_get_contents($sourcePath);
13 $nonce = substr($data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
14 $ciphertext = substr($data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
15 $result = sodium_crypto_secretbox_open($ciphertext, $nonce, base64_decode($key));
16 return $result !== false ? $result : false;
17}

Märkus: Sodium kontrollib terviklikkust ise. Kui andmeid on muudetud või võti on vale, tagastab sodium_crypto_secretbox_open() lihtsalt false, eraldi HMAC kontrolle pole vaja. Kood on poole lühem.

Üks puudus: Sodium nõuab PHP 7.2 või uuemat. Kui projekt töötab PHP 7.0-7.1 peal, on ainus võimalus OpenSSL. Kuid praktikas on 2026. aastal juba keeruline leida hostingut, kus oleks PHP alla 7.4: WordPress.org 2026. aasta juuni andmete kohaselt on PHP 7.0-7.1 osakaal alla 0,3% kõigist installatsioonidest.

OpenSSL või Sodium: kaks valikukriteeriumi

Valik kahe lähenemise vahel taandub kahele tegurile:

  • PHP versioon. PHP 7.2+, võta Sodium, see on vaikimisi turvalisem ega lase sul HMAC teostust tuksi keerata. PHP 7.0-7.1, ainult OpenSSL. Alla PHP 7.0, on aeg serverit uuendada, mitte leiutada lahendusi PECL-mcryptiga.
  • Andmete ülekantavus keskkondade vahel. OpenSSL on saadaval kõikjal, sealhulgas PHP 5.3+. Kui krüpteeritud failid peavad olema loetavad arendusserveris, tootmiskeskkonnas ja kliendi juures, on OpenSSL ühilduvuse seisukohast usaldusväärsem. Sodium šifritekst dekrüpteerub ainult seal, kus Sodium on olemas.

Praktikas kasutame OpenSSL-i projektides, kus ühilduvus erinevate keskkondade vahel on oluline. Sodiumit seal, kus kogu stack on uuendatud PHP 8-le ja turvalisus on esikohal.

Videos analüüsib Dave Hollingworth üksikasjalikult mõlemat lähenemist koos koodi demonstratsiooni ja iga taga olevate krüptograafiliste primitiivide selgitusega. Materjal täiendab artiklit: näidatakse äärmuslikke juhtumeid, defuse/php-encryption teegi paigaldamist Composeriga ning OpenSSL-i ja Sodiumi jõudluse võrdlust reaalsete andmete peal.

⁉️🤔 Korduma kippuvad küsimused

Kas ma saan faili krüpteerimiseks kasutada md5() või sha1()?

Ei. md5() ja sha1() on räsifunktsioonid, need on definitsiooni poolest pöördumatud. Krüpteeritud fail peab dekrüpteeruma tagasi, aga räsi ei saa dekrüpteerida. Räsisid kasutatakse terviklikkuse kontrolliks (nagu HMAC ülaltoodud koodis) ja paroolide salvestamiseks password_hash() abil, kuid mitte sisu krüpteerimiseks.

Mida teha, kui krüpteerimisvõti kaob?

Andmete dekrüpteerimine ilma võtmeta on võimatu. Hoia võtit failis wp-config.php väljaspool dokumendijuurt ja varunda see faili- ja andmebaasivarukoopiatest eraldi. Ära pane võtit Git repositooriumisse, lisa wp-config.php faili .gitignore või kasuta keskkonnamuutujaid.

Miks on IV vajalik, kui võti on juba salajane?

Ilma juhusliku IV-ta annavad sama võtmega krüpteeritud identsed andmed identse šifriteksti. Korduvaid plokke nägev ründaja saab teavet faili struktuuri kohta. IV muudab iga krüpteerimise unikaalseks: sama fail, krüpteerituna kaks korda ühe võtmega, annab kaks erinevat šifriteksti.

Kas ma saan krüpteerida suuri faile, mitu gigabaiti?

Ülaltoodud funktsioonid loevad faili tervenisti mällu, gigabaidiste andmete puhul viib see mälu ammendumiseni. Voogkrüpteerimiseks kasuta openssl_encrypt() tsüklis koos tükkide kaupa puhverdamisega (näiteks 1 MB kaupa) või defuse/php-encryption teeki, mis toetab voogrežiimi karbist võttes.

Kas see kood töötab PHP 8.3 peal?

Jah. Nii OpenSSL kui ka Sodium on PHP 8-s täielikult toetatud. Kood on testitud praeguste PHP versioonidega ega kasuta aegunud funktsioone. PHP 8.3 puhul on ühilduvus säilitatud, OpenSSL laienduses ei ole tagasiühilduvust lõhkuvaid muudatusi.

Faili krüpteerimine 2026. aastal: praktiline otsus

Mcrypt lahkus PHP-st ja see on paremuse poole. Kaks sisseehitatud asendustööriista on nii turvalisemad kui ka kiiremad ega nõua PECL-iga trummeldamist. OpenSSL töötab kõikjal, Sodium on vaikimisi lihtsam ja usaldusväärsem.

Lühidalt: uus projekt PHP 8 peal, alusta Sodiumiga, kood tuleb puhtam. Vana koodi migreerimine mcryptilt, kirjuta ümber OpenSSL-ile, see on saadaval isegi PHP 7.0 peal. Ja krüptograafia peamine reegel: hoia võtmeid krüpteeritud andmetest eraldi. Võtme kaotus võrdub andmete kaotusega ja toores jõud siin ei aita.

Alusta testskriptiga faili koopial: veendu, et tsükkel "krüpteeritud → dekrüpteeritud → bait-baidilt klapib" töötab vigadeta. Ja millist meetodit sina oma projektides kasutad, OpenSSL, Sodium või midagi muud? Kirjuta kommentaaridesse.