Тег <keygen> (от английского key generator, «создатель ключей») встраивали в форму, чтобы браузер сам создал пару ключей. Закрытый ключ сохранялся в браузере, а открытый уходил на сервер вместе с остальными полями формы: по нему сервер выпускал сертификат. Тег пустой: закрывающего </keygen> у него нет.
Из браузеров тег убрали, а в стандарте HTML он значится устаревшим. Сегодня keygen для браузера неизвестный тег: ключ он не создаёт и в данные формы не попадает. Новые страницы с ним писать не нужно.
<form action="/certificate" method="post">
<keygen name="key" keytype="rsa">
<button type="submit">Отправить</button>
</form>
В этой статье
Тег keygen в HTML: что это и для чего создавали
Раньше выпуск сертификата требовал отдельных программ: человек создавал ключи, отправлял заявку в центр сертификации и устанавливал ответ. Тег keygen позволял сделать это прямо в форме: браузер показывал выбор длины ключа, создавал пару и отправлял открытую часть на сервер.
Раньше у тега было шесть атрибутов. Современные браузеры их не читают.
| Атрибут | Что делал | Заметка |
|---|---|---|
name | название поля с открытым ключом при отправке формы | значение уходило на сервер вместе с остальными полями |
keytype | вид ключей, чаще всего rsa | если не указан, использовался rsa |
challenge | строка, которую сервер просил добавить к ключу для проверки | попадала в запрос на сертификат |
disabled | отключал поле | отключённое поле не отправлялось |
form | связывал поле с формой, которая находится в другом месте страницы | значением был id формы |
autofocus | фокус на поле при открытии страницы | единственный из шести, который остался: он глобальный |
Как браузер разбирает keygen
В стандарте для keygen есть особое правило разбора: его добавляют в документ и сразу закрывают, как img или br. Поэтому тег пустой, а текст после него остаётся рядом, а не внутри. Закрывающий </keygen> ни на что не влияет.
Класс у тега HTMLUnknownElement, свойств name, challenge и keytype у него нет, а display по умолчанию inline. Пример показывает, что происходит внутри формы.
const k = document.querySelector("keygen");
console.log(k.constructor.name, "keytype" in k);
Пример: как браузер разбирает keygen
Кнопки меняют запись. Под ней показаны класс тега, поля формы и ключи FormData, измеренные в рамке.
Работает ли keygen сейчас
Нет. Ключи не создаются, выбор длины ключа не показывается, а при отправке формы поле с name в данные не попадает: в form.elements и в FormData остаются только настоящие поля. Тег ничего не рисует, поэтому страница выглядит так, будто его нет.
Когда keygen убрали из браузеров
Браузеры убирали тег по очереди. Для Safari данных об удалении нет.
Пример: таблица версий
| Браузер | Убран в версии | Заметка |
|---|---|---|
| Chrome | 57 | до этого тег работал |
| Edge | 79 | работал в старом Edge, в версии 79 браузер перешёл на Chromium |
| Firefox | 69 | работал с версии 1 |
| Safari | нет данных | тег был с версии 1.2 |
Чем заменить keygen: Web Cryptography API
Стандарт HTML советует два пути. Для настройки рабочих устройств используют средства самой системы. Для выпуска сертификата создают пару ключей через Web Cryptography API, затем выгружают сертификат и ключ, чтобы человек установил их сам.
Пару ключей создаёт метод crypto.subtle.generateKey(). Если второй аргумент равен false, закрытый ключ выгрузить нельзя: он остаётся в браузере, как и у keygen. Открытый ключ выгружает exportKey() в формате spki: так принято хранить открытые ключи. Его отправляют на сервер обычным полем формы или через fetch. Если закрытый ключ нужно перенести на другое устройство, вместо false ставят true, но тогда его может выгрузить любой скрипт страницы.
const keys = await crypto.subtle.generateKey(
{ name: "ECDSA", namedCurve: "P-256" },
false,
["sign", "verify"]
);
const spki = await crypto.subtle.exportKey("spki", keys.publicKey);
Web Cryptography API работает только в защищённом контексте: на страницах с https и на localhost.
Пример: пара ключей через Web Crypto
Кнопки создают пару ключей. Размер открытого ключа и права на выгрузку измерены в рамке.
Частые ошибки с тегом keygen
Ошибки возникают оттого, что keygen пытаются использовать как рабочий тег или неточно переносят его работу на Web Cryptography API.
| Ошибка | Что получится | Как исправить |
|---|---|---|
<keygen name="key"> в форме в расчёте на создание ключа | Ничего не происходит, поле в данные формы не попадает | Создавать ключи через crypto.subtle.generateKey() |
true вторым аргументом generateKey() «на всякий случай» | Закрытый ключ может выгрузить любой скрипт страницы | Ставить false, если ключ должен остаться в браузере |
| Запуск страницы без https | crypto.subtle недоступен, ключи не создаются | Открывать страницу по https или на localhost |
Результат exportKey() кладут в поле формы как есть | В поле попадает строка [object ArrayBuffer], а не ключ | Перевести ключ в base64, как в примере выше |