Расширение Subject Alternative Name (SAN) является одним из ключевых элементов современных X.509 сертификатов, позволяющим связывать один сертификат с несколькими идентификаторами одновременно. В отличие от устаревшего подхода, где имя хоста фиксировалось исключительно в поле Common Name (CN), SAN предоставляет гибкий механизм указания множества доменов, IP-адресов и других типов идентификаторов в рамках одного сертификата.
В экосистеме JavaScript библиотека Jsrsasign предоставляет инструменты для формирования и встраивания расширений сертификатов, включая SAN, через высокоуровневые ASN.1-конструкторы.
Расширение Subject Alternative Name определяется стандартом X.509 и имеет OID:
Его основная задача — описывать альтернативные имена субъекта сертификата. Это особенно важно для HTTPS-сертификатов, где один сертификат может обслуживать:
В современных TLS-реализациях именно SAN считается обязательным источником проверки имени хоста, тогда как Common Name игнорируется.
В структуре SAN используются GeneralName типы, каждый из которых кодируется отдельно в ASN.1:
Используются для доменов:
Поддерживаются как IPv4, так и IPv6:
Используется реже, но поддерживается стандартом:
Часто применяется в сложных инфраструктурах:
В ASN.1 расширение SAN выглядит как последовательность GeneralName:
SubjectAltName ::= GeneralNames
GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
Каждый GeneralName — это выбор (CHOICE), например:
Библиотека Jsrsasign предоставляет пространство имен:
KJUR.asn1.x509Для построения расширений используется класс Extension, а также вспомогательные структуры:
В Jsrsasign SAN обычно задается через объект расширения с именем
subjectAltName.
const extSAN = new KJUR.asn1.x509.Extension({
extname: "subjectAltName",
array: [
{ dns: "example.com" },
{ dns: "www.example.com" }
]
});
const extSAN = new KJUR.asn1.x509.Extension({
extname: "subjectAltName",
array: [
{ ip: "192.168.1.10" },
{ ip: "10.0.0.1" }
]
});
const extSAN = new KJUR.asn1.x509.Extension({
extname: "subjectAltName",
array: [
{ dns: "example.com" },
{ dns: "api.example.com" },
{ ip: "192.168.1.10" },
{ uri: "https://example.com/service" }
]
});
При генерации сертификата SAN добавляется в список расширений объекта Certificate.
const cert = new KJUR.asn1.x509.Certificate({
version: 3,
serial: { int: 1 },
issuer: { str: "/CN=Test CA" },
subject: { str: "/CN=example.com" },
notbefore: "230101000000Z",
notafter: "240101000000Z",
sbjpubkey: pubKeyObj,
ext: [
extSAN
]
});
Jsrsasign преобразует:
Это позволяет работать с объектами JavaScript без ручного ASN.1 кодирования.
Важно учитывать, что IP-адреса в SAN кодируются не как строки, а как бинарное представление OCTET STRING.
Jsrsasign выполняет это преобразование автоматически, но только при корректной строковой форме IPv4/IPv6.
Большинство браузеров и TLS-библиотек полностью игнорируют CN, если SAN присутствует. Поэтому:
Современные клиенты не принимают CN как источник имени хоста, если SAN отсутствует.
Нельзя использовать:
Допустимы только конкретные IP-адреса.
Если сертификат предназначен для домена, DNS-имена должны быть явно указаны в SAN.
Jsrsasign позволяет более низкоуровневую форму:
const gn1 = { dNSName: "example.com" };
const gn2 = { iPAddress: "10.0.0.1" };
const extSAN = new KJUR.asn1.x509.Extension({
extname: "subjectAltName",
array: [gn1, gn2]
});
Такой подход полезен при динамической генерации сертификатов.
После генерации сертификата SAN можно извлечь:
const cert = new X509();
cert.readCertPEM(pem);
const sans = cert.getExtSubjectAltName();
console.log(sans);
Результат обычно представляет список всех альтернативных имен, включенных в сертификат.
SAN используется в сценариях:
При сериализации сертификата Jsrsasign формирует ASN.1 структуру:
Это полностью соответствует RFC 5280, что обеспечивает совместимость с внешними TLS системами.
Если SAN не задан:
ERR_CERT_COMMON_NAME_INVALIDJsrsasign часто применяется в сценариях:
В таких случаях SAN формируется на основе входных параметров:
function buildSAN(domains, ips) {
const arr = [];
domains.forEach(d => arr.push({ dns: d }));
ips.forEach(i => arr.push({ ip: i }));
return new KJUR.asn1.x509.Extension({
extname: "subjectAltName",
array: arr
});
}
Хотя SAN не связан напрямую с ключами, он определяет область применения сертификата. В комбинации с:
формируется полная модель доверия TLS-сертификата.
Jsrsasign-реализация SAN:
При этом любые нестандартные поля в SAN игнорируются клиентами без ошибки, но могут снижать доверие к сертификату в строгих средах.