PHP on Azure works well. The risk is an app that still uses Microsoft's retired PHP SDK: code that can return successful responses while quietly lowering transport security.
HTTPS_PROXY is set. Its later Storage client also trusts uppercase HTTP_PROXY in web requests, which bypasses Guzzle's fix for httpoxy attacks. Both issues live in app code, not in a server warning.Check the package, not the hosting platform
Running PHP in Azure App Service or containers is a valid setup. This note covers Composer files that include microsoft/windowsazure, microsoft/azure-storage, or retired microsoft/azure-storage-* clients.
composer why microsoft/windowsazure
composer why microsoft/azure-storage-blob
composer show --locked | grep -E 'microsoft/(windowsazure|azure-storage)'
Microsoft retired the original Azure SDK for PHP in 2021 and archived it in 2023. They retired the separate Storage clients in 2024. These packages stay on Packagist so old builds do not break, but they get no security updates.
Risk 1: a proxy disables TLS checks
The old SDK's HTTP client contains this code before sending requests:
if (getenv('HTTPS_PROXY')) {
$options[RequestOptions::VERIFY] = false;
}
This is the real runtime path in the archived HttpClient. When HTTPS_PROXY is set, the client stops checking if the TLS certificate belongs to Azure. A proxy or network actor can show any certificate, read the request, and pass it along.
The dangerous part is quiet:
- The app starts normally.
- The proxy returns real Azure data.
- Health checks stay green.
- No certificate error shows up.
- Keys, tokens, and data cross the proxy in plain text.
Risk 2: Storage client reintroduces httpoxy
The later Storage SDK leaves TLS checks on, but reads proxy settings unsafely:
$proxy = getenv('HTTP_PROXY');
if (!empty($proxy)) {
$options['proxy'] = $proxy;
}
In web servers using CGI or FastCGI, an attacker can send a Proxy: http://bad-host header. PHP turns that into the HTTP_PROXY variable. The SDK reads it and sends storage calls to the attacker's server.
Guzzle only reads HTTP_PROXY on the command line for this reason. The Azure SDK bypassed Guzzle's safety rule by passing the variable directly.
Why this matters more than version numbers
These proxy paths are active code flaws. They run silently, keep returning green checks, and have no upstream fixes because the repositories are archived. Updating Guzzle alone does not fix them, because the bad logic lives in the Azure wrapper code.
A maintained migration path
The independent azure-oss/storage-blob project provides current packages for Blob Storage, Queue Storage, and Entra ID on PHP 8.2+ with modern Guzzle:
{
"php": "^8.2",
"guzzlehttp/guzzle": "^7.8 || ^8.0",
"azure-oss/storage-common": "^2.0"
}
How to migrate safely
- Search code for
WindowsAzure\andMicrosoftAzure\Storage\. - Check server environment for
HTTP_PROXY,HTTPS_PROXY, andverify=false. - Add an interface around storage calls so your app does not depend on SDK classes directly.
- Switch one service at a time to
azure-oss/storage-blob. - Test uploads, downloads, SAS tokens, and error handling.
- Confirm retired Microsoft packages are gone from
composer.lock.
Primary sources: Archived Azure SDK for PHP | httpoxy Vulnerability Class | PHP OSS for Azure