SSL workaround
В данном документе рассматриваются моменты установки и аспекты работы с
OpenSSL,
Apache +
mod_ssl, установка и обслуживание CA.
Выдача и получение сертификатов. Авторизация пользователей web сервера при помощи сертификатов.
Данный документ представляет собой компиляцию с некоторыми комментариями
следующих документов:
SSL
Secure Sockets Layer protocol (SSL) - протокол уровеня передачи данных, который может
служит промежточным между протоколом сетевого уровня ( прим. TCP/IP ) и протоколом
уровня приложения (те HTTP). SSL предлагает зашищенный канал передачи данных
между клиентом и сервером с использованием футентификации, цифровых подписей и
шифрования. Протокол разработан с поддержкой большого числа специальных алгоритмов
, используемых для криптования, создания дайджестов и подписей. Он позволяет
делать выбор алгоритмов с учетом требуемой надежности, соответствия принятому
законодательству и пр. факторам, а так же расширение новыми алгоритмами.
Выбор происходит во время начала протокольной сессии между клиентом и сервером.
Существует несколько версий SSL протокола:
Версия | Источник | Описание | Поддержка броузерами
|
---|
SSL 2.0 | Netscape | Оригинальный протокол | Netscape 3.0,Internet Explorer 3.0
|
SSL 3.0 | Expired Internet Draft
| Revisions to prevent specific security attacks, add ciphers,and support certificate chains
| Netscape 3.0, Internet Explorer 3.0
|
TLS 2.0 | IETF Draft | Revision of SSL 3.0 | Нет
|
Один из основных использование SSL - защита Web HTTP коммуникаций между клиентом
и Web сервером. Этот вариант не пересекается с ипользованием небезопасного
HTTP. Защищенный вариант использует URLы, которые начинаются с https а не с http,
и использует другой порт (по умолчанию 443).
OpenSSL - свободная некоммерческая реализация
SSL 2.0 и 3.0. Она включает реализацию открытых ключей ( public key ), которая может быть
использована за пределами US. OpenSSL предлагает достаточно несложный путь для освоения SSL
и является темой данного документа.
Термины.
- Cryptographic Algorithms
Криптографические алгоритмы
- Технические способы использующиеся для преобразования сообщения в шифрованную(криптованную) форму таким образом, что сообщение не может быть прочитано никем, за исключением тех, кому оно предназначено. Различают два типа алгоритмов криптования - симметричние (convetional) и ассиметричные (public key).
Симметричные алгоритмы требуют, чтобы и отправитель и получатель имели в своем распоряжении общий для них ключ, с помощью которого собственно и производится криптование.
Ассиметричные алгоритмы ипользуют на стороне получателя пару ключей - приватный и публичный. Криптование сообщения производится с помощью публичного ключа получателя, который используя свой приватный ключ может декриптовать сообщение. Публичный ключ модет передоваться в открытом виде.
- Message Digest
- Хэш функция над сообщением, позволяющая контролировать его целостность.
- Digital Signatures
Цифровая подписи.
- Цифровая подпись использует для идентификация отправителя сообщения. Как правило содержит message digest, номер последовательности и прочую информацию, критованную с использованием приватного ключа отправителя сообщения. Данная информация может быть декритована с использованием публичного ключа отправителя, что позволяет контролировать происхождение и целостность сообщения.
- Certificate
Сертификаты.
- Certificate Authority
- Третья доверительная сторона, которая подписывает и удостоверяет действительность сертификата, используя свой приватный ключ.
Certificate Authority
Для использование ssl расширения Apache совершенно не нужно располагать Certificate Authority,
достаточно получить, а точнее приобрести, необходимые ключи и сертификаты подписанные сторонним
(CA). Некоторые компании, как Thawte и
VeriSign имеют собственные CA
и предоставляют следующий сервис:
- проверка сертификатов
- выдача и управлние сертификатами.
Однако возможно создать собственную CA, для генерации и использования сертификатов внутри
организации для идентификации серверов и пользователей. При установке CA, необходимо помнить,
что CA не только выдает сертификаты, но и определяет сроки их действительности, обновляет их,
управляет списком просроченных выданных сертификатов (Certificate Revocation Lists, or CRLs).
Помните, что вам необходимо "познакомить" Ваш browser с сертификатом собственно CA, для того,
чтобы browser мог работать с серверами, чьи сертификаты подписаны вышеупомянутым CA.
Создание сертификата для CA
Первым шагом для создания Certificate Authority является создания сертификата
для данного CA, подписанного самим же CA. Для этого используется комманда"req
" с ключом "-x509
". Ключ "-new
" задает требование генерации новой пары (приватный,публичный) ключей. В случае, если данные ключи уже есть, приватный ключ можно указать используя опцию "-key filename
", опустив соответственно "-new
" и "-keyout
".
Сертификат записывается в cacert.pem
и приватный ключ (в случае его генерации)
cakey.pem
, которые располагаются (согласно указанным в opensslay.cnf переменным
certificate и private_key соответсвенно). commonName для самоподписанного сертификата не
должно соответсвовать имени домена для сервера ( поскольку Nescape использует имя домена для
сертификации серверов). "req
" потребует введение пароля для приватного ключа
( private_key ) или же вы можете указать файл с паролем используя "-passin
". for Ex:(смотрите пути в openssl.cnf).
/usr/local/bin/openssl req -new -x509 -keyout ${SSLDIR}/private/cakey.pem \
-out ${SSLDIR}/cacert.pem -config /usr/local/openssl/openssl.cnf
Using configuration from /usr/local/openssl/openssl.cnf
Generating a 512 bit private key
writing new private key to '../private/cakey.pem'
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorperated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]: RU
State or Province Name (full name) [MA]: Some State
Locality Name (eg, city) [Cambridge]: some Locality
Organization Name (eg, company) [The Open Group]: None Group
Organizational Unit Name (eg, section) [Research Institute]: CT
Common Name (eg, YOUR name) [example.opengroup.org]: NONE CA
|
CA сертификат и ключ должны оставаться в $SSLDIR/private
и $SSLDIR, как указано
в ssleay.conf
в CA default section. Они будут
использоваться для проверки сертификатов клиента подписанных созданным CA.
Cоздание ключа и сертификата для сервера
Сначала с использованием процедуры аналогичной вышеприведенной создаем для сервера
запрос на сертификат:
openssl req -new -keyout newkey.pem -out newreq.pem -days 360
Using configuration from /usr/local/etc/openssl.cnf
Generating a 1024 bit RSA private key
.......................+++++
.+++++
writing new private key to 'newkey.pem'
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [RU]:
State or Province Name (full name) [Some State]:
Locality Name (eg, city) [Some Locality]:
Organization Name (eg, company) [Simple Org.]:
Organizational Unit Name (eg, section) [Computing Dep.]:
Common Name (eg, YOUR name) []:hostname.aaaa.ru
Email Address []:some@some.aaaa.ru
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
|
Используя "ca" команду подписываем полученный сертификат.Ключ -policy указывает секцию SSLeay
конфигурации, которая определят, какие поля с distinguished name необходими, а так же их порядок.
В качестве входных подаются файл, содержащий запрос newreq.pem и ключ сервера newkey.pem.
По запросу вводится пароль, открывающий private ключ CA.
Внимание!! Перед этим вы должны удостовериться в том, что в CA репозитарии,
согласно ssleay.conf должны быть созданы $database файл, $new_certs_dir и $serial.
Формат $serial - две цифры, если после создания CA никакие сертификаты больше не выдавалсь, то
должен содержать в себе "01".
openssl ca -policy policy_anything -out newcert.pem -config /usr/local/etc/openssl.cnf -infiles newreq.pem
Using configuration from /usr/local/etc/ssleay.cnf
Enter PEM pass phrase:
Check that the request matches the signature
Signature ok
The Subjects Distinguished Name is as follows
countryName :PRINTABLE:'RU'
stateOrProvinceName :PRINTABLE:'Some State'
localityName :PRINTABLE:'Some Locality'
organizationName :PRINTABLE:'Simple Org.'
organizationalUnitName:PRINTABLE:'Computing Dep.'
commonName :PRINTABLE:'aaaaa.abbn.cc'
emailAddress :IA5STRING:'xz@abbn.cc'
Certificate is to be certified until Mar 16 22:46:52 2000 GMT (365 days)
Sign the certificate? [y/n]:y |
После чего в текущем каталоге находиться сертификат сервера newcert.pem,
он же находится в $new_certs_dir под именем index_number.pem , значение
$serial увеличивается на 1, в $database заноситься запись про выданный
сертификат.Для дальнейшего исрользования сохраним ключ сервера и его
сертификат в private/serverkey.pem certs/servercert.pem соответственно.
( Какова роль расположения??). Многие документы рекомендуют создавать
hash на сертификаты в том же каталоге, где сертификаты ищутся,
предполагаеться для быстроты достуа при проверке выданных сертификатов.
ln -s servercert.pem `x509 -noout -hash < servercert.pem`.0 |
И так, в нашем распоряжении есть ключ сервера
(/usr/local/CA/private/serverkey.pem), его сертификат, подписаннный
неким CA ( в данной ситуации нашим CA)(/usr/local/certs/servercert.pem),
и, собственно, сам CA - его ключ (/usr/local/CA/private/cakey.pem), его
сертификат подписанный им самим(/usr/local/CA/cacert.pem).
Загрузка сертификата CA в browser
Для того, чтобы browser мог распознавать сертификаты, подписанные
вашим CA, необходимо загрузить "самоподписанный" сертификат CA.
При загрузке помните,что после данной процедуры, ваш browser
будет безоговорочно ??? принимать все сертификаты подписанные данным CA.
Сертифика CA загружается с использованием
HTTP Content-Type application/x-x509-ca-cert.
Это можно выполнить, если не привязываться к серверу, используя cgi скрипт.
Netscape продукты могут принимать сертификаты, как в
PEM, так и в DER формате. В силу непольной реализации работы с DER,
SSLeay/OpenSSL в работе использует PEM формат. Но вы можете получить
сертификат в DER формате используя команду
crl2pkcs7 -inform PEM -outform DER -certfile $CA_cert.pem -out $CA_cert.der -nocrl
|
Microsoft IE использует входной формат отличный от pem?????????
Miscrosoft IE5 понимает pem формат.
HTML форма для загрузки CA сертификата.
<HTML><HEAD><TITLE>Load CA Certificate</TITLE></HEAD><BODY>
<H1>Load Certificate Authority Certificate</H1>
<FORM ACTION="http://example.some.somwere/cgi-bin/loadCAcert.pl" METHOD=post>
<TABLE>
<TR>
<TD>Netscape Browser (PEM Format):</TD>
<TD><INPUT TYPE="RADIO" NAME="FORMAT" VALUE="PEM" CHECKED></TD></TR>
<TR><TD>Microsoft Browser (DER Format):</TD>
<TD><INPUT TYPE="RADIO" NAME="FORMAT" VALUE="DER"></TD></TR>
</TABLE>
<INPUT TYPE="SUBMIT" VALUE="Load Certificate">
</FORM>
</BODY></HTML>
|
loadCAcert.pl скрипт.
Perl CGI скрипт загрузки CA сертификата
#!/usr/local/bin/perl -T
require 5.003;
use strict;
use CGI;
my $cert_dir = "/usr/local/CA/";
my $cert_file = "cacert.pem";
my $query = new CGI;
my $kind = $query->param('FORMAT');
if($kind eq 'DER') { $cert_file = "cacert.der"; }
my $cert_path = "$cert_dir/$cert_file";
open(CERT, "<$cert_path");
my $data = join '',<CERT>;
close(CERT);
print "Content-Type: application/x-x509-ca-cert\n";
print "Content-Length: ", length($data), "\n\n$data";
|
Также возможно записать сертификат в файл с соответствующим суффиксом и
объявить серверу в конфигурации соответствие данного суффикса с MIME типом
application/x-x509-ca-cert. Для apache сеервера это будет
добавление строки AddType application/x-x509-ca-cert .pem
в srm.conf
если суффикс .pem
.
Apache + SSL
Теперь собственно обратимся к настройке SSL с Apache.
Укажем серверу его ключ:
SSLCertificateKeyFile /usr/local/CA/private/serverkey.pem
И его сертификат:
SSLCertificateFile /usr/local/CA/certs/servercert.pem
Далее укажем сертификат для CA и рсположения сертификатов которые могут быть
использованы для аутентификации.
SSLCACertificatePath /usr/local/CA/certs/
SSLCACertificateFile /usr/local/CA/cacert.pem
Для того, что бы apache мог воспользоваться своим private key в случае, когда
он зашифрован, вам необходимо передать перед стартом серверу секретную фразу,
которой был зашифрован ключ. Эта процедура управляется дерективой
SSLPassPhraseDialog
. Она может принимать значения
builtin
и exec:/path/to/program
. В первом варианте
при старте сервер запрашивает пароль для расшифровки своего ключа, во втором
использует внешнюю программу, для получения пароля, пароль выдается ей на
stdout
.
Создание сертификатов для клиентов
Сертификаты клиентов используются для аутентификации клиента на сервере.
Процедура создания сертификата клиента несколько сложнее, чем создание
сертификата сервера, поскольку клиент должен сгенерировать пару ключей,
оставив секретный ключ у себя и переслать открытый ключ вместе с запросом
на сертификацию CA. После того, как будет получен подписанный CA сертификат,
клиент должен его сохранить для дальнейшего использования.
Различные клиенты, такие как Nescape Navigator/Communicator и
Microsoft Internet Explorer используют различный механизм для создания
клиентских сертификатов.
Процедура создания сертификата представляет собой HTML формы, которые
включают в себя вызов CGI скрипта, который вызывает процедуры SSLeay/OpenSSL
для получения сертификата.
Последовательность действий такова:
- Пользователь запрашивает HTML страницу с формой.
- Пользователь вводит идентификационную иноформацию.
- Отправление формы вызывает следующие действия
- Browser создает пару ключей (public и private)
- Секретный ключ сохраяняется в browser
- Открытый ключ с идентификационной информацие посылаеться на сервер.
- CGI сервер создает сертификат и пересылает его клиенту.
Вместо автоматической выдачи сертификата CA рекомендуеться производить дополнительные проверки на предложенные данные.
HTML форма содержит поля ( с умолчательными значениями ) для различных
"distinguished name" атрибутов, которые используются в сертификате клиента,
иформация, позволяющая browser сгенерить пару ключей, скрытые поля, которые зависят то типа browser, посзволяющие передать эту информацию для CGI скрипта.
Netscape Navigator/Communicator
В Netscape Navigator форма содержит дополнительный тэг <KEYGEN>
Этот тэг создает пару ключей и определяет, что открытый ключ должен быть фозвращен как значение формы, когда форма будет исполнена. <KEYGEN>
тэг вызывает диалог browser, позволяющий выбрать степень защищенности в зависимости от версии Netscape Navigator/Communicator. Информация формы используется
CGI скриптом для создания запроса на сертификацию и этот запрос используется
для создания сертификата клиента.
Netscape возвращает "Signed Public Key And Challenge" (SPKAC) открытый ключ,
если обнаруживает <KEYGEN> элемент формы. Нижеприведенная форма
возвращает его в скрытом SPKAC поле. CGI скрипт затем считывавет данные из
этого поля и передает SPKAC значение в SSLeay/OpenSSL используя
-spkac ключ при вызове ca. (Смотри ns-ca.doc
в doc каталоге в поставле SSLeay/OpenSSL).
Форма для запроса Netscape клиентом сертификата
<HTML><HEAD><TITLE>Create Client Certificate</TITLE></HEAD><BODY>
<CENTER><H1>Create Client Certificate</H1></CENTER>
<FORM NAME="GenerateForm" ACTION="http://example.osf.org/cgi-bin/ns_key.pl">
<TABLE>
<TR><TD>Common Name:</TD><TD>
<INPUT TYPE="TEXT" NAME="commonName" VALUE="Client Certificate" SIZE=64>
</TD></TR>
<TR><TD>email:</TD><TD>
<INPUT TYPE="TEXT" NAME="emailAddress" VALUE="f.hirsch@opengroup.org" SIZE=40>
</TD></TR>
<TR><TD>Organization:</TD><TD>
<INPUT TYPE="TEXT" NAME="organizationName" VALUE="The Open Group">
</TD></TR>
<TR><TD>Organizational Unit:</TD><TD>
<INPUT TYPE="TEXT" NAME="organizationalUnitName" VALUE="Research Institute">
</TD></TR>
<TR><TD>Locality (City):</TD><TD>
<INPUT TYPE="TEXT" NAME="localityName" VALUE="Cambridge">
</TD></TR>
<TR><TD>State:</TD><TD>
<INPUT TYPE="TEXT" NAME="stateOrProvinceName" VALUE="MA">
</TD></TR>
<TR><TD>Country:</TD><TD>
<INPUT TYPE="TEXT" NAME="countryName" VALUE="US" SIZE="2">
</TD></TR>
</TABLE>
<!--
' keygen is Netscape specific and will be ignored in
' internet explorer
-->
<KEYGEN NAME="SPKAC" CHALLENGE="challengePassword">
<INPUT TYPE="SUBMIT" NAME="SUBMIT">
</FORM>
<P><HR></BODY></HTML>
|
Perl скрипт для обработки запроса сертификата для Netscape клиента
#!/usr/local/bin/perl
require 5.003;
use strict;
use CGI;
use File::CounterFile; # module to maintain certificate request counter
my $doc_dir = $ENV{'DOCUMENT_ROOT'}; # apache specific location for storage
unless($doc_dir) {
print "<HTML><HEAD><TITLE>Failure</TITLE></HEAD>";
print "<BODY>DOCUMENT_ROOT not defined</BODY></HTML>";
exit(0);
}
my $base_dir = $doc_dir;
$base_dir =~ s/\/htdocs//;
my $SSLDIR = '/usr/local/ssl'; # define where SSLeay files are located
my $CA = "$SSLDIR/bin/ca";
my $CONFIG = "/usr/local/etc/ssleay.cnf";
my $CAPASS = "caKEY";
my $query = new CGI; # get a handle on the form data
my $key = $query->param('SPKAC'); # this will fail if not Netscape browser
unless($key) { fail("No Key provided $key. Netscape required"); }
my $counter = new File::CounterFile("$base_dir/.counter", 1);
unless($counter) { fail("Could not create counter: $!"); }
my $count = $counter->inc();
my $certs_dir = "$base_dir/certs";
my $req_file = "$certs_dir/cert$count.req"; # certificate request filename
my $result_file = "$certs_dir/cert$count.result"; # certificate filename
# Explicitly list form fields we must have for certificate creation to work.
my @req_names = ('commonName', 'emailAddress', 'organizationName',
'organizationalUnitName', 'localityName', 'stateOrProvinceName',
'countryName', 'SPKAC');
# build the request file
open(REQ, ">$req_file") or fail("Could not create request $req_file: $!");
my $name;
foreach $name (@req_names) {
my $value = $query->param("$name");
$value =~ tr/\n//d;
print REQ "$name = $value\n";
}
close(REQ);
# make sure we actually created a request file
unless(-f $req_file) { fail("request missing: $req_file"); }
unless(-e $CA) { fail("command missing"); } # ensure that ca command will run
# command for processing certificate request, without password
my $cmd = "$CA -config $CONFIG -spkac $req_file -out $result_file -days 360";
my $rc = system("$cmd -key $CAPASS 2>errs");
if($rc != 0) { fail("$cmd<P>rc = $rc", "errs"); }
open(CERT, "<$result_file") or fail("Could not open $result_file<P>$!");
# send the client certificate to the browser
print "Content-Type: application/x-x509-user-cert\n";
my $result = join '', <CERT>;
close CERT;
my $len = length($result);
print "Content-Length: $len\n\n";
print $result;
exit(0);
sub fail {
my($msg, $errs) = @_;
print $query->header;
print $query->start_html(-title => "Certificate Request Failure");
print "<H2>Certificate request failed</H2>$msg<P>";
if($errs) {
if(open(ERR, "<errs")) {
while(<ERR>) {
print "$_<BR>";
}
close ERR;
}
}
print $query->dump();
print $query->end_html();
exit(0);
}
|
CGI скрипт создает файл, содержащий значения для "distinguished name",
переданных формой и специальный SPKAC значение для
"Signed Public Key And Challenge (SPKAC)" созданное Navigator/Communicator.
SSLeay/OpenSSL caкоманда вызывается, используя данный файл в качестве аргумента.(Смотри ns-ca.doc в документации к SSLeay/OpenSSL)
$SSLDIR/bin/ca -spkac $req_file -out $result_file -days 360 -key $CAPASS \
2>errs
|
$req_file является именем уникального файла в каталоге сертификатов
certs, который содержит запрос на сертификацию, полученный из CGI
данных. $result_file является уникальным именеем файла в каталоге
сертификатов certs, и будет содержать собственно сертификат.
$CAPASS Perl переменная сожержит CA ключ.
Если ca команда завершилась успешно, то сертификат возвращается
через CGI как application/x-x509-user-cert HTTP.
Content-Type. Navigator распознает этот тип и производит оставшие запросы данных от пользователя для установки сертификата в browser.
Однако для реально действующего CA не рекомендуется производить
генерацию сертификата "на лету". Поскольку, как правило, переданные данные подлежат проверке,
кроме того, при получении подписанного сертификата необходимо явно указывать
пароль в том случае, если private key хранится в криптованном виде.
Cписок команд и опций openssl.
req |
основное применение - генерирование и обработка запросов на получение сертификата (certifcate requests) в формате PKCS#10, а так же получение самоподписанных сертификатов для корневого CA.
-key filename |
указывает имя файла, в котором уже находится сгенерированный приватный ключ |
-x509 |
|
|
| |
| |
Краткая терминология
- ASN.1:
- Abstract Syntax Notation One, as defined in X.208.
- BER:
- Basic Encoding Rules, as defined in X.209.
- Certificate:
- A type that binds an entity's distinguished
name to a public key with a digital signature. This type is
defined in X.509. This type also contains the distinguished
name of the certificate issuer (the signer), an issuer-
specific serial number, the issuer's signature algorithm
identifier, and a validity period.
- CertificateSerialNumber:
- A type that uniquely identifies a
certificate (and thereby an entity and a public key) among
those signed by a particular certificate issuer. This type
is defined in X.509.
- CertificateRevocationList:
- A type that contains information
about certificates whose validity an issuer has prematurely
revoked. The information consists of an issuer name, the
time of issue, the next scheduled time of issue, and a list
of certificate serial numbers and their associated
revocation times. The CRL is signed by the issuer. The type
intended by this standard is the one defined RFC 1422.
- DER:
- Distinguished Encoding Rules for ASN.1, as defined in
X.509, Section 8.7.
- DES:
- Data Encryption Standard, as defined in FIPS PUB 46-1.
- desCBC:
- The object identifier for DES in cipher-block
chaining (CBC) mode, as defined in [NIST91].
- ExtendedCertificate:
- A type that consists of an X.509 public-
key certificate and a set of attributes, collectively signed
by the issuer of the X.509 public-key certificate. This type
is defined in PKCS #6.
- MD2:
- RSA Data Security, Inc.'s MD2 message-digest algorithm,
as defined in RFC 1319.
- md2:
- The object identifier for MD2, as defined in RFC 1319.
- MD5:
- RSA Data Security, Inc.'s MD5 message-digest algorithm,
as defined in RFC 1321
.
- md5:
- The object identifier for MD5, as defined in RFC 1321.
- Name:
- A type that uniquely identifies or "distinguishes"
objects in an X.500 directory. This type is defined in
X.501. In an X.509 certificate, the type identifies the
certificate issuer and the entity whose public key is
certified.
- PEM:
- Internet Privacy-Enhanced Mail, as defined in RFCs
1421-1424.
- RSA:
- The RSA public-key cryptosystem, as defined in [RSA78].
- rsaEncryption:
- The object identifier for RSA encryption, as
defined in PKCS #1.
To Do
- Конфигурационный файл с различными x509 расширениями
- Протестировать созданный CA с MSIE.
- Lynx+OpenSSL ???
- Протестировать доступ с использованием сертификатов
- Как принудительно делать exire на сертификаты
- Что такое serial и зачем он нужен
- x509 extensions & netscape extensions
- Как работать с policy.