Http-прокси на PHP
Обычно в постах о программировании я пишу об успешных подходах и находках. В этот раз расскажу об идее, которая на практике не заработала.
В прошлый раз я рассказывал, что если у вас есть свой виртуальный сервер, вы можете не возиться с VPN, а отправить трафик из браузера через
Я задумался, можно ли провернуть такой же трюк без своего виртуального сервера. Стал смотреть в сторону виртуальных (shared) хостингов, в частности бесплатных или предоставляющих бесплатный тестовый период. На hostings.info нашел бесплатный хостинг с доступом по SSH. Трюк с
Я стал думать дальше и решил попробовать другой вариант. На сервере хостера запущен PHP. Я могу подключиться к нему через обычный
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\ServerRequest;
// Создание экземпляра клиента Guzzle
$client = new Client();
// Обработка входящего запроса
$request = ServerRequest::fromGlobals();
// Получение URL-адреса запрашиваемого сайта
$url = $request->getUri();
$url
// Я собирался ходить на https-сайты, поэтому подменил протокол и порт
->withScheme('https')
->withPort(443)
// Подменяем хост (видимо, тут и происходит обработка протокола http-прокси)
->withHost($request->getHeaderLine('host'))
->withQuery($request->getUri()->getQuery())
;
// Создание прокси-запроса
$proxyRequest = new Request(
$request->getMethod(),
$url,
$request->getHeaders(),
$request->getBody(),
$request->getProtocolVersion()
);
// Отправка прокси-запроса и получение ответа
$response = $client->send($proxyRequest, [
'stream' => true,
'verify' => false,
'allow_redirects' => false, // Коды редиректов отправляем назад в браузер
]);
// Передача заголовков ответа клиенту
foreach ($response->getHeaders() as $name => $values) {
foreach ($values as $value) {
header(sprintf('%s: %s', $name, $value), false);
}
}
// Передача тела ответа клиенту
echo $response->getBody();
Чтобы этот скрипт завести, нужно сохранить его в файл со произвольным редким названием, например, q7e6r53t.php
, и установить через composer библиотеку guzzle. Кроме того, в nginx в настройку хоста надо добавить следующее:
server {
listen 8082;
server_name localhost;
root /mnt/c/git/proxy;
location / {
try_files $uri $uri/ /q7e6r53t.php$is_args$args;
}
location ~ \q7e6r53t.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
}
В таком варианте прокси заработал локально, даже с авторизацией и куками. Самый большой недостаток этого подхода в том, что нельзя проксировать
127.0.0.1 - - [18/Jun/2023:12:56:47 +0300] "CONNECT www.google.com:443 HTTP/1.1" 400 166 "-" "-"
И даже если вдруг представить, что такое возможно, это был бы man in the middle. Поэтому в браузере приходится набирать адрес сайта с http, а скрипт подменяет протокол на https. Если в PHP нет нужных сертификатов, подключиться к сайту будет невозможно. Для отключения проверки сертификатов я добавил флаг 'verify' => false
. Конечно, это несекьюрно, но тут и так трафик передается хостеру в открытом виде, так что держать ворота запертыми в открытом поле смысла нет :)
На практике у хостера этот скрипт не заработал. В браузере отображалась страница ошибки Apache о неправильно сконфигурированном хосте. Очевидно, Apache настроен так, чтобы не позволять так просто делать
В ходе лабораторной работы мы написали простейший скрипт
Комментарии
Оставьте свой комментарий