Введение

Интерфейс между веб-серверами и внешними программами

В вычислительной технике Common Gateway Interface (CGI) — это спецификация интерфейса, позволяющая веб-серверам выполнять внешнюю программу для обработки HTTP- или HTTPS-запросов пользователей. Такие программы часто написаны на языке сценариев и обычно называются CGI-скриптами, но могут включать и скомпилированные программы. Типичный пример использования — отправка веб-формы на веб-странице, использующей CGI. Данные формы отправляются на веб-сервер в HTTP-запросе с URL, указывающим на CGI-скрипт. Веб-сервер затем запускает CGI-скрипт в новом процессе, передавая ему данные формы. CGI-скрипт передает свой вывод, как правило, в формате HTML, веб-серверу, который, в свою очередь, отправляет его обратно в браузер в качестве ответа на запрос. Разработанный в начале 1990-х годов, CGI был первым широко распространенным методом, обеспечивающим интерактивность веб-страниц. В связи с необходимостью запуска CGI-скриптов в отдельном процессе при каждом запросе от клиента, были разработаны различные альтернативные решения.

История

В 1993 году команда Национального центра суперкомпьютерных приложений (NCSA) опубликовала спецификацию для вызова исполняемых файлов командной строки в списке рассылки www talk. Другие разработчики веб-серверов приняли её, и с тех пор она стала стандартом для веб-серверов. В ноябре 1997 года была создана рабочая группа под председательством Кена Коара для более формального определения CGI, разработанного NCSA. Результатом этой работы стал RFC 3875, в котором была специфицирована версия CGI 1.1. В RFC конкретно упоминаются следующие участники: Например, если веб-сервер имеет полное доменное имя www.example.com, а его коллекция документов хранится в /usr/local/apache/htdocs/ в локальной файловой системе (его корневой каталог), то веб-сервер будет отвечать на запрос http://www.example.com/index.html, отправляя в браузер копию файла /usr/local/apache/htdocs/index.html (если он существует). Для страниц, генерируемых динамически, серверное программное обеспечение может перенаправлять запросы отдельным программам и передавать результаты запрашивающему клиенту (обычно веб-браузеру, который отображает страницу конечному пользователю). Таким программам обычно требуется дополнительная информация, передаваемая вместе с запросом, такая как строки запроса или cookie. В свою очередь, при возврате скрипт должен предоставить всю информацию, необходимую HTTP для ответа на запрос: HTTP-статус запроса, содержимое документа (если доступно), тип документа (например, HTML, PDF или обычный текст) и т. д. Изначально не существовало стандартизированных методов обмена данными между браузером, HTTP-сервером, с которым он взаимодействовал, и скриптами на сервере, которые должны были обрабатывать данные и в конечном итоге возвращать результат браузеру. В результате между различными вариантами HTTP-серверов возникали взаимные несовместимости, которые снижали переносимость скриптов. Осознание этой проблемы привело к разработке спецификации обмена данными, что и привело к созданию CGI. Программы, генерирующие веб-страницы и вызываемые серверным программным обеспечением, соответствующим спецификации CGI, называются CGI-скриптами, даже если они фактически написаны на нескриптовом языке, таком как C. Спецификация CGI была быстро принята и продолжает поддерживаться всеми известными пакетами HTTP-серверов, такими как Apache, Microsoft IIS и (с расширением) серверами на основе Node.js. Одним из первых применений CGI-скриптов была обработка форм. В ранних версиях HTML HTML-формы обычно имели атрибут "action" и кнопку, обозначенную как кнопка "submit". При нажатии кнопки "submit" URI, указанный в атрибуте "action", отправлялся на сервер вместе с данными из формы в виде строки запроса. Если в атрибуте "action" указан CGI-скрипт, то этот скрипт выполнялся, а скрипт, в свою очередь, генерировал HTML-страницу.

Развертывание

Веб-сервер, поддерживающий CGI, может быть настроен на интерпретацию URL-адреса как ссылки на CGI-скрипт. Распространенной практикой является создание каталога `cgi-bin/` в корне дерева каталогов и обработка всех исполняемых файлов в этом каталоге (и только их, в целях безопасности) как CGI-скриптов. Когда веб-браузер запрашивает URL, указывающий на файл в каталоге CGI (например, http://example.com/cgi-bin/printenv.pl/with/additional/path?and=a&query=string), HTTP-сервер вместо простой отправки этого файла (/usr/local/apache/htdocs/cgi-bin/printenv.pl) веб-браузеру запускает указанный скрипт и передает вывод скрипта веб-браузеру. То есть, все, что скрипт выводит в стандартный поток вывода, передается веб-клиенту, а не отображается в окне терминала, в котором запущен веб-сервер. Другой популярный подход – использование расширений имен файлов; например, если CGI-скриптам последовательно присваивается расширение `cgi`, веб-сервер может быть настроен на интерпретацию всех файлов с таким расширением как CGI-скриптов. Хотя это удобно и необходимо для многих готовых скриптов, это открывает сервер для атак, если удаленный пользователь может загрузить исполняемый код с соответствующим расширением. Спецификация CGI определяет, как дополнительная информация, передаваемая с запросом, передается скрипту. Веб-сервер создает подмножество переменных окружения, переданных ему, и добавляет детали, относящиеся к HTTP-окружению. Например, если к URL сразу после имени скрипта добавляется слэш и дополнительные имена каталогов (в данном примере, /with/additional/path), этот путь сохраняется в переменной окружения `PATH_INFO` перед вызовом скрипта. Если параметры передаются скрипту через HTTP GET-запрос (вопросительный знак, добавленный к URL, за которым следуют пары `param=value`; в примере, ?and=a&query=string), эти параметры сохраняются в переменной окружения `QUERY_STRING` перед вызовом скрипта. Тело HTTP-запроса, например, параметры формы, отправленные через HTTP POST-запрос, передаются в стандартный ввод скрипта. Скрипт может затем прочитать эти переменные окружения или данные из стандартного ввода и адаптироваться к запросу веб-браузера.

Применение

CGI часто используется для обработки входных данных от пользователя и формирования соответствующего вывода. Примером программы CGI может служить программа, реализующая вики-систему. Если пользовательский агент запрашивает имя статьи, веб-сервер запускает программу CGI. Программа CGI извлекает исходный код страницы этой статьи (если он существует), преобразует его в HTML и выводит результат. Веб-сервер получает вывод от программы CGI и передает его пользовательскому агенту. Затем, если пользовательский агент нажимает кнопку "Редактировать страницу", программа CGI заполняет текстовое поле HTML или другой элемент управления редактированием содержимым страницы. Наконец, если пользовательский агент нажимает кнопку "Опубликовать страницу", программа CGI преобразует обновленный HTML в исходный код страницы этой статьи и сохраняет его.

Безопасность

Программы CGI по умолчанию выполняются в контексте безопасности веб-сервера. При первом появлении CGI вместе с эталонными дистрибутивами веб-серверов NCSA, Apache и CERN предоставлялся ряд примеров скриптов, демонстрирующих, как можно было написать скрипты оболочки или программы на C для использования нового CGI. Одним из таких примеров был CGI-скрипт PHF, реализующий простую телефонную книгу. Как и многие другие скрипты того времени, этот скрипт использовал функцию `escape shell cmd`. Эта функция должна была очищать аргумент, полученный от пользовательского ввода, и затем передавать его в оболочку Unix для выполнения в контексте безопасности веб-сервера. Скрипт некорректно очищал ввод, позволяя передавать в оболочку символы новой строки, что фактически позволяло выполнять несколько команд. Результаты выполнения этих команд затем отображались на веб-сервере. Если контекст безопасности веб-сервера это позволял, злоумышленники могли выполнять вредоносные команды. Это был первый широко распространенный пример нового типа веб-атаки, известного как инъекция кода, когда необработанные данные от веб-пользователей могли приводить к выполнению кода на веб-сервере. Поскольку пример кода был установлен по умолчанию, атаки были широко распространены и привели к ряду рекомендаций по безопасности в начале 1996 года.