25. ledna 2023

Když se v nějaké vámi používané PHP knihovně objeví bezpečnostní chyba, tak máte několik možností jak se o ní dozvědět dříve, než bude pozdě. V jednom z předchozích článků jsem popisoval PHP Security Advisories Database a její použití pomocí Roave Security Advisories i několik dalších způsobů. Všechny zmíněné ale vyžadují mít nebo používat nějaký extra balíček nebo nástroj.

Kromě balíčku roave/security-advisories, který díky svému dlouhému seznamu zranitelných knihoven a jejich verzí nedovolí takový balíček nainstalovat a upozorní na něj, používám i GitHub Action s názvem The PHP Security Checker, což je vlastně jen githubí omáčkou obalený security check ze Symfony CLI. O všech těchto věcech jsem již psal ve svém dřívějším článku včetně ukázek.

Pokud ale nechcete nic dalšího a rádi byste využili něco, co nejspíš už používáte, tak mám pro vás dobrou zprávu. Od verze 2.4 (vyšla v létě 2022) se Composer té databáze dotazuje rovnou sám, po každém composer require. Kontrolu lze také vyvolat ručně pomocí composer audit. K dotazování používá vlastní API, viz třeba seznam zranitelných verzí balíčku guzzlehttp/guz­zle.

Kontrola se provádí i po spuštění composer update (v obou případech lze přeskočit pomocí --no-audit), ale po composer install standardně ne – důvodem možná je obvykle automatizované spouštění, kdy výsledek stejně nikdo nevidí a možná taky to, že častá instalace, např. při spouštění testů, by posílala zbytečně moc požadavků na ono zmíněné API. Nicméně pokud i přesto chcete, tak kontrolu po instalaci můžete vynutit pomocí parametru --audit.

Po composer require

Pojďme se podívat na to, jak to vypadá. Dejme tomu, že bych teď chtěl nějakou tu zranitelnou verzi nainstalovat, konkrétně jsem si vybral Guzzle verze 7.4.4 – Composer to sice udělá, ale bude remcat a upozorní mě, všimněte si posledních dvou řádků:

$ composer require guzzlehttp/guzzle:7.4.4
./composer.json has been created
Running composer update guzzlehttp/guzzle
Loading composer repositories with package information
Updating dependencies
Lock file operations: 8 installs, 0 updates, 0 removals
  - Locking guzzlehttp/guzzle (7.4.4)
  - Locking guzzlehttp/promises (1.5.2)
  - Locking guzzlehttp/psr7 (2.4.3)
  - Locking psr/http-client (1.0.1)
  - Locking psr/http-factory (1.0.1)
  - Locking psr/http-message (1.0.1)
  - Locking ralouphie/getallheaders (3.0.3)
  - Locking symfony/deprecation-contracts (v3.2.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 8 installs, 0 updates, 0 removals
  - Installing symfony/deprecation-contracts (v3.2.0): Extracting archive
  - Installing psr/http-message (1.0.1): Extracting archive
  - Installing psr/http-client (1.0.1): Extracting archive
  - Installing ralouphie/getallheaders (3.0.3): Extracting archive
  - Installing psr/http-factory (1.0.1): Extracting archive
  - Installing guzzlehttp/psr7 (2.4.3): Extracting archive
  - Installing guzzlehttp/promises (1.5.2): Extracting archive
  - Installing guzzlehttp/guzzle (7.4.4): Extracting archive
2 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
4 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Found 2 security vulnerability advisories affecting 1 package.
Run composer audit for a full list of advisories.

S barvičkami v terminálu je to sice o dost výraznější:

Poslední 2 řádky z výstupu composer require

Formát lze sice změnit, viz níže, ale i tak by se to dalo jednoduše přehlídnout. Zvlášť třeba pokud byste spustili composer require s parametrem --quiet, „nic nevypisuj“.

composer audit

Proto je asi důležitější ten úplně poslední řádek, který říká, že bychom měli spustit composer audit:

$ composer audit
Found 2 security vulnerability advisories affecting 1 package:
+-------------------+----------------------------------------------------------------------------------+
| Package           | guzzlehttp/guzzle                                                                |
| CVE               | CVE-2022-31091                                                                   |
| Title             | Change in port should be considered a change in origin                           |
| URL               | https://github.com/guzzle/guzzle/security/advisories/GHSA-q559-8m2m-g699         |
| Affected versions | >=7,<7.4.5|>=4,<6.5.8                                                            |
| Reported at       | 2022-06-20T22:24:00+00:00                                                        |
+-------------------+----------------------------------------------------------------------------------+
+-------------------+----------------------------------------------------------------------------------+
| Package           | guzzlehttp/guzzle                                                                |
| CVE               | CVE-2022-31090                                                                   |
| Title             | CURLOPT_HTTPAUTH option not cleared on change of origin                          |
| URL               | https://github.com/guzzle/guzzle/security/advisories/GHSA-25mq-v84q-4j7r         |
| Affected versions | >=7,<7.4.5|>=4,<6.5.8                                                            |
| Reported at       | 2022-06-20T22:24:00+00:00                                                        |
+-------------------+----------------------------------------------------------------------------------+

To už je o něco lepší, že? Rovnou vidíme, který balíček má nějakou zranitelnost a jakou. Dokonce i návratová hodnota je nenulová, došlo k nějaké chybě, takže se to dá použít i v různých skriptech:

$ echo $?
1

Když se pokusím nainstalovat nejnovější verzi bez známých bezpečnostních problémů, tak to bude vypadat takto:

$ composer require guzzlehttp/guzzle
[...]
No security vulnerability advisories found
Using version ^7.5 for guzzlehttp/guzzle
[...]

Výstup z composer audit pak bude vypadat následovně, včetně nulové návratové hodnoty, což znamená vše oukej:

$ composer audit
No security vulnerability advisories found
$ echo $?
0

Pro správnou funkčnost composer audit musí být balíčky standardně nainstalovány. Pokud ale použijete parametr --locked (composer audit --locked), tak balíčky nainstalovány být nemusí a kontrola se provede jen na základě obsahu composer.lock.

Pokud byste z nějakého důvodu nechtěli kontrolovat balíčky v sekci require-dev, tak můžete použít --no-dev. Osobně bych ale kontroloval vše.

Jako GitHub Action

Díky nenulové návratové hodnotě při nalezení známého bezpečnostního problému v nějakém používaném balíčku lze composer audit spouštět jednoduše například i v GitHub Actions. A přesně tak to používám i já:

composer-audit:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v3
    - run: composer audit

Tuhle kontrolu spouštím každé dvě hodiny, abych se o případném problému a nutnosti aktualizovat dozvěděl včas. Na nějaké důležitější aplikaci, než je můj web, bych to klidně spouštěl častěji, třeba každou hodinu.

Výsledek spouštění kontroly balíčků každé 2 hodiny na GitHub Actions

Spouštění kontroly pomocí GitHub Actions

Formát výstupu

Composer nabízí několik různých formátů vypisovaných informací o známých zranitelnostech:

  • table: tabulka viz výše, standardně se použije pro composer audit
  • plain: obyčejný textový výpis, bez tabulky
  • json: hádejte
  • summary: jen krátká informace o tom, jestli se něco nalezlo, nebo ne; standardně pro composer require, composer updatecomposer install

Formát můžete změnit parametrem:

  • --audit-format=FORMAT pro composer require, composer updatecomposer install
  • --format=FORMAT pro composer audit

Dodám snad už jen to, že Composer můžete aktualizovat pomocí composer self-update.

Aktualizace článku

27. ledna 2023 Parametr --locked zajistí, že composer audit se bude dělat na základě obsahu composer.lock

Michal Špaček

Michal Špaček

Vyvíjím webové aplikace, zajímá mě jejich bezpečnost. Nebojím se o tom mluvit veřejně, hledám hranice tak, že je posouvám. Chci naučit webové vývojáře stavět bezpečnější a výkonnější weby a aplikace.

Veřejná školení

Zvu vás na následující školení, která pořádám a vedu:

Bezpečnost PHP aplikací
(13.–16. března 2023 )

HTTPS pro vývojáře a správce
(20.–21. března 2023 )