RFC 3948 UDP Encapsulation of IPsec ESP Packets

Network Working Group                                        A. Huttunen
Request for Comments: 3948                          F-Secure Corporation
Category: Standards Track                                     B. Swander
                                                               Microsoft
                                                                V. Volpe
                                                           Cisco Systems
                                                              L. DiBurro
                                                         Nortel Networks
                                                             M. Stenberg
                                                            January 2005

Инкапсуляция пакетов IPsec ESP в UDP

UDP Encapsulation of IPsec ESP Packets

 PDF

Статус документа

Этот документ содержит спецификацию проекта стандартного протокола Internet и служит приглашением к дискуссии в целях развития протокола. Текущее состояние стандартизации и статус протокола можно узнать из документа Internet Official Protocol Standards (STD 1). Документ может распространяться свободно.

Авторские права

Copyright (C) The Internet Society (2005).

Тезисы

Данная спецификация определяет метод инкапсуляцию и декапсуляцию пакетов ESP1 в пакеты UDP для передачи через трансляторы NAT2. Определенная здесь инкапсуляция ESP может использоваться как с протоколом IPv4, так и с IPv6. По согласования инкапсуляция применяется при обмене ключами IKE3.

Оглавление

Исключено в версии HTML.

1. Введение

Эта спецификация протокола определяет методы инкапсуляции и декапсуляции пакетов ESP в пакеты UDP для прохождения через трансляторы сетевых адресов (NAT) (см. [RFC3715], параграф 2.2, п. i). Номера портов UDP используются те же самые, что применяются для трафика IKE, как определено в [RFC3947].

Использование общих номеров портов для IKE и инкапсулированного в UDP трафика ESP обусловлено тем, что это обеспечивает более эффективное масштабирование (одно отображение в NAT и не требуется передача отдельных сообщений IKE keepalive), упрощает настройку (только один порт на межсетевом экране) и реализацию.

Выбор транспортного или туннельного режима следует выполнять с учетом потребностей клиента (см. [RFC3715], раздел 3, «Удаленные пользователи»). Клиенты L2TP/IPsec должны поддерживать режимы, определенные в [RFC3193]. Клиенты IPsec в туннельном режиме должны поддерживать туннельный режим.

Реализациям IKE, поддерживающим этот протокол, недопустимо использовать поле ESP SPI со значением 0 для пакетов ESP. Это позволяет различать пакеты IKE и ESP.

Как определено в этом документе, инкапсуляция пакетов ESP в UDP описывается в терминах заголовков IPv4. Нет никаких технических ограничений на использование заголовков IPv6 в качестве внешних и/или внутренних.

Поскольку защита внешних адресов IP в IPsec AH принципиально не совместима с NAT, спецификация протокола просто не включает IPsec AH. Данный протокол предполагает использование IKE (IKEv1 [RFC2401] или IKEv2 [IKEv2]) для согласования IPsec SA. Установка ключей вручную не поддерживается.

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с [RFC2119].

2. Формат пакетов

2.1. Формат заголовка при инкапсуляции ESP в UDP

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        Source Port            |      Destination Port         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Length              |           Checksum            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Заголовок ESP [RFC2406]                    |
   ~                                                               ~
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Заголовок UDP соответствует стандарту [RFC0768] с учетом перечисленных ниже ограничений:

  • поля Source Port и Destination Port должны совпадать с аналогичными полями трафика IKE;

  • в поле IPv4 UDP Checksum следует указывать значение 0;

  • получателям недопустимо зависеть от нулевого значения в поле контрольной суммы UDP.

В поле SPI заголовка ESP недопустимо устанавливать значение 0.

2.2. Формат заголовка IKE для порта 4500

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        Source Port            |      Destination Port         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Length              |           Checksum            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Non-ESP Marker                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Заголовок ESP [RFC2406]                    |
   ~                                                               ~
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Заголовок UDP соответствует стандарту [RFC0768] и применяется, как описано в [RFC3947]. Этот документ не задает новых требований к обработке контрольных сумм для пакетов IKE.

Поле Non-ESP Marker представляет собой 4 байта с нулевыми значениями, служащими для выравнивания с полем SPI в пакетах ESP.

2.3. Формат пакетов NAT-Keepalive

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        Source Port            |      Destination Port         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Length              |           Checksum            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |    0xFF       |
   +-+-+-+-+-+-+-+-+

Заголовок UDP соответствует стандарту [RFC0768] с учетом перечисленных ниже ограничений:

  • поля Source Port и Destination Port должны совпадать с аналогичными полями трафика UDP-ESP, как указано в параграфе 2.1;

  • в поле IPv4 UDP Checksum следует указывать значение 0;

  • получателям недопустимо зависеть от нулевого значения в поле контрольной суммы UDP.

Отправитель должен использовать 1-октетный элемент данных со значением 0xFF. Получателям следует игнорировать принятые пакеты NAT-keepalive.

3. Процедуры инкапсуляции и декапсуляции

3.1. Дополнительные процедуры

3.1.1. Процедура декапсуляции NAT в туннельном режиме

При использовании для передачи пакетов туннельного режима (см. [RFC3715], раздел 3, criteria «Mode support» и «Удаленные пользователи»), the inner IP header can contain addresses that are not suitable for the current network. This procedure defines how these addresses are to be converted to suitable addresses for the current network.

В зависимости от локальной политики должно выполняться одно из перечисленных ниже условий.

  1. Если в политике определено приемлемое пространство IP-адресов отправителей для инкапсулированных пакетов от партнеров, проверяется соответствие IP-адреса во внутреннем заголовке этому пространству.

  2. Если удаленному партнеру присвоен адрес, проверяется соответствие адреса отправителя во внутреннем заголовке присвоенному адресу IP.

  3. Для пакета выполняется трансляция NAT, делающая его подходящим для пересылки в локальную сеть.

3.1.2. Процедура декапсуляции NAT в транспортном режиме

При использовании для передачи пакетов транспортного режима контрольные суммы в заголовках TCP и UDP будут не корректны, поскольку отдельные части заголоков IP будут меняться в процессе передачи. Приведенная здесь процедура определяет корректировку контрольных сумм (см. [RFC3715], параграф 2.1, п. b).

В зависимости от локальной политики должно выполняться одно из перечисленных ниже условий.

  1. Если после заголовка ESP следует заголовок TCP/UDP и реальные адреса отправителя и получателя были определены в соответствии с [RFC3947], выполняется перерасчет контрольной суммы TCP/UDP:

    • из контрольной суммы в пакете вычитается IP-адрес отправителя, указанный в заголовке пакета;

    • к результату прибавляется реальный IP-адрес отправителя полученный от IKE (из NAT-OA);

    • вычитается IP-адрес получателя, указанный в заголовке пакета;

    • прибавляется реальный IP-адрес получателя полученный от IKE (из NAT-OA).

Примечание. Если полученный и реальный адреса (например, для получателя) совпадают, соответствующую пару операций выполнять не требуется.

  1. Если после заголовка ESP следует заголовок TCP/UDP, выполняется перерасчет контрольной суммы TCP/UDP.

  2. Если после заголовка ESP следует заголовок UDP, устанавливается нулевое значение для поля контрольной суммы UDP. Если после заголовка ESP следует заголовок TCP и имеется опция для отключения расчета контрольной суммы TCP, можно воспользоваться этой опцией. Это следует применять только для транспортного режима при обеспеченной защите целостности пакетов, в туннельном режиме контрольная сумма TCP должна проверяться (это не является нарушением духа параграфа 4.2.2.7 в [RFC1122], поскольку контрольная сумма создается отправителем и проверяется получателем; значение поля контрольной суммы защищено протоколом IPsec).

В дополнение к этому реализация может фиксировать все вложенные протоколы, работа которых нарушеается транслятором NAT (см. [RFC3715], параграф 2.1, п. g).

3.2. Инкапсуляция ESP в транспортном режиме

До применения ESP/UDP

            -------------------------------
      IPv4  |исх. заголов. IP|     |      |
            | (любые опции)  | TCP |Данные|
            -------------------------------

После применения ESP/UDP

            ----------------------------------------------------------
      IPv4  |исх. заголов. IP|Загол|Загол|     |      |   ESP   | ESP|
            | (любые опции)  | UDP | ESP | TCP |Данные| Trailer |Auth|
            ----------------------------------------------------------
                                      |<----- зашифровано ----->|
                                |<--- аутентифицировано ---->|
  1. Применяется обычная процедура инкапсуляции ESP.

  2. В нужное место помещается корректно отформатированный заголовок UDP.

  3. Поля Total Length, Protocol и Header Checksum (для IPv4) в заголовке IP редактируются в соответствии с результирующим пакетом IP.

3.3. Декапсуляция ESP в транспортном режиме

  1. Заголовок UDP удаляется из пакета.

  2. Поля Total Length, Protocol и Header Checksum (для IPv4) в заголовке IP редактируются в соответствии с результирующим пакетом IP.

  3. Применяется обычная процедура декапсуляции ESP.

  4. Выполняется процедура декапсуляции NAT для транспортного режима.

3.4. Инкапсуляция ESP в туннельном режиме

До применения ESP/UDP

            -------------------------------
      IPv4  |исх. заголов. IP|     |      |
            | (любые опции)  | TCP |Данные|
            -------------------------------

После применения ESP/UDP

        ---------------------------------------------------------------------
   IPv4 |нов. загол| UDP | ESP |исх. заголов. IP|     |      |   ESP   | ESP|
        | (опции)  | Hdr | Hdr | (любые опции)  | TCP |Данные| Trailer |Auth|
        ---------------------------------------------------------------------
                               |<------------ зашифровано ------------>|
                         |<------------ аутентифицировано ------------>|
  1. Применяется обычная процедура инкапсуляции ESP.

  2. В нужное место помещается корректно отформатированный заголовок UDP.

  3. Поля Total Length, Protocol и Header Checksum (для IPv4) в заголовке IP редактируются в соответствии с результирующим пакетом IP.

3.5. Декапсуляция ESP в туннельном режиме

  1. Заголовок UDP удаляется из пакета.

  2. Поля Total Length, Protocol и Header Checksum (для IPv4) в заголовке IP редактируются в соответствии с результирующим пакетом IP.

  3. Применяется обычная процедура декапсуляции ESP.

  4. Выполняется процедура декапсуляции NAT для туннельного режима.

4. Процедура NAT Keepalive

Единственной целью отправки пакетов NAT-keepalive является обеспечение сохранности отображений NAT в течение всего срока действия соединения между партнерами (см. [RFC3715], параграф 2.2, п. j). Прием сообщения NAT-keepalive недопустимо использовать в качестве подтверждения жизнеспособности соединения.

Узел может передать пакет NAT-keepalive, если между партнерами имеется одна или множество связей SA (phase I или phase II) или такие связи были не более N ранее. Значение N задается в локальной конфигурации, по умолчанию используется 5 минут.

Узлу следует передать пакет NAT-keepalive, если нужно детектировать этот узел в соответствии с [RFC3947], а партнеру не передавалось других пакетов в течение M секунд. Значение M адается в локальной конфигурации, по умолчанию используется 20 секунд.

5. Вопросы безопасности

5.1. Конфликт туннельного режима

Разработчикам следует принимать во внимание возможность возникновения ситуаций, когда удаленные пользователи будут согласовывать на SGW4 (защитный шлюз) пересекающиеся параметры, которые могут воздействовать на работу в туннельном режиме (см. [RFC3715], параграф 2.1, п. e).

             +----+            \ /
             |    |-------------|----\
             +----+            / \    \
             ноутбук         NAT 1     \
             Ari                        \
            10.1.2.3                     \
             +----+            \ /        \       +----+          +----+
             |    |-------------|----------+------|    |----------|    |
             +----+            / \                +----+          +----+
             ноутбук          NAT 2                  SGW          Сервер
             Bob                                                  Suzy
            10.1.2.3

Поскольку SGW будет видеть две SA, ведущие в 10.1.2.3, ему непонятно, в которую направлять пакеты от сервера Suzy. Разработчики должны обеспечить способ снятия такой неопределенности.

Рекомендуется на устройстве SGW присваивать уникальные в локальном масштабе адреса IP компьютерам Ari и Bob (используя протокол типа DHCP over IPsec) или использовать NAT для смены адресов отправителя в пакетах от Ari и Bob на уникальные в местном масштабе адреса IP до отправки их пакетов в направлении сервера Suzy. Это описано в параграфе «Масштабирование» раздела 3 в [RFC3715].

См. также Приложение A.

5.2. Конфликт транспортного режима

Похожая проблема возникает в транспортном режиме, когда 2 клиента (Ari и Bob), расположенные за одним транслятором NAT, организуют защищенные соединения с одним сервером (см. [RFC3715], параграф 2.1, п. e).

Клиент Cliff хочет подключиться к тому же серверу без использования защиты.

             +----+
             |    |
             +----+ \
             ноутбук \
             Ari      \
            10.1.2.3   \
             +----+     \ /                +----+
             |    |------+-----------------|    |
             +----+     / \                +----+
             ноутбук   /NAT                Сервер
             Bob      /
            10.1.2.4 /
                    /
            +----+ /
            |    |/
            +----+
            ноутбук
            Cliff
           10.1.2.5

Транспортные связи SA с сервером будут иметь вид

для Ari: Server —> NAT, <дескриптор трафика 1>, инкапсуляция UDP <4500, Y>

для Bob: Server —> NAT, <дескриптор трафика 2>, инкапсуляция UDP <4500, Z>

Трафик Cliff передается в открытом виде без организации SA.

Дескрипторы трафика содержат информацию о протоколах и номерах портов. Для инкапсуляции в UDP используется порт 4500 и описанный в параграфе 2.1 формат. Y и Z — динамические номера портов, выделяемые транслятором NAT на этапе согласования IKE. Таким образом, трафик IKE от ноутбука Ari будет иметь вид UDP <4500,4500> и придет на сервер в виде UDP <Y,4500>, где Y указывает динамически выделенный транслятором порт.

Если дескрипторы трафика 1 и 2 перекрываются, обычного просмотра базы может быть не достаточно для определения связи SA, которая служит для передачи трафика. Реализации должны обрабатывать эту ситуации, запрещая конфликты соединений или с помощью иных мер.

Предположим, что Cliff хочет подключиться к тому же серверу без применения защиты трафика. Организовать такое соединение непросто, поскольку на сервере уже имеется правило (от сервера на внешний адрес устройства NAT) для защиты по дескриптору трафика. Если дескрипторы трафика совсем не перекрываются, такое соединение становится возможным.

Ниже приведен пример правил для сервера

для Ari: Server —> NAT, только UDP, защита

для Bob: Server —> NAT, только TCP, защита

для Cliff: Server —> NAT, только ICMP, без защиты

Отметим, что эти правила позволяет Ari и Bob отправлять серверу пакеты ICMP без защиты.

Сервер видит всех расположенных за транслятором NAT клиентов с одним адресом IP, поэтому установка разных правил для одного и того же дескриптора трафика не возможно в принципе.

Ниже приведен пример сомнительной политики на сервере для описываемого случая.

Server —> NAT, TCP, защита (Ari и Bob)

Server —> NAT, TCP, без защиты (Cliff)

Сервер не сможет реализовать такую политику, поскольку Bob может предать свой трафик в открытом виде и сервер не сможет отличить его от трафика Cliff. Таким образом, становится невозможным обеспечить гарантию защиты некоторым клиентам, расположенным за NAT, одновременно предоставляя другим клиентам за тем же транслятором работать без защиты. Если политика сервера позволяет, он может просто обеспечить некий (best effort — по возможности) уровень защиты, обеспечивая ее расположенным за NAT клиентам, которые инициировали защиту, и передавая в открытом виде отклики на незащищенные запросы.

Для обеспечения гарантированной защиты описанный выше проблемный вариант недопустимо разрешать на серверах. Если устраивает защита уровня best effort (по возможности), такой вариант можно использовать.

См. также Приложение A.

6. Согласование с IAB

Вопросы UNSAF [RFC3424] решаются документом с требованиями по совместимости IPsec-NAT [RFC3715].

7. Благодарности

Спасибо Tero Kivinen и William Dixon за активное участие в подготовке этого документа.

Спасибо Joern Sierwald, Tamir Zegman, Tatu Ylonen и Santeri Paavolainen за их вклад в ранние документы по работе через трансляторы NAT.

8. Литература

8.1. Нормативные документы

[RFC0768] Postel, J., «User Datagram Protocol», STD 6, RFC 768, August 1980.

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, March 1997.

[RFC2401] Kent, S. and R. Atkinson, «Security Architecture for the Internet Protocol», RFC 24015, November 1998.

[RFC2406] Kent, S. and R. Atkinson, «IP Encapsulating Security Payload (ESP)», RFC 24066, November 1998.

[RFC2409] Harkins, D. and D. Carrel, «The Internet Key Exchange (IKE)», RFC 24097, November 1998.

[RFC3947] Kivinen, T., «Negotiation of NAT-Traversal in the IKE», RFC 3947, January 2005.

8.2. Дополнительная литература

[RFC1122] Braden, R., «Requirements for Internet Hosts — Communication Layers», STD 3, RFC 1122, October 1989.

[RFC3193] Patel, B., Aboba, B., Dixon, W., Zorn, G., and S. Booth, «Securing L2TP using IPsec», RFC 3193, November 2001.

[RFC3424] Daigle, L. and IAB, «IAB Considerations for Unilateral Self-Address Fixing (UNSAF) Across Network Address Translation», RFC 3424, November 2002.

[RFC3715] Aboba, B. and W. Dixon, «IPsec-Network Address Translation (NAT) Compatibility Requirements», RFC 3715, March 2004.

[IKEv2] Kaufman, C., «Internet Key Exchange (IKEv2) Protocol», Work in Progress8, October 2004.

Приложение A. Разъяснения для случая множества клиентов за NAT

В этом приложении даны разъяснения, касающиеся возможных решений проблем в случаях, когда множество находящихся за одним транслятором NAT узлов одновременно подключаются к одному адресу IP.

В разделах 5.1 и 5.2 отмечено, что вы должны избегать таких проблем. Поскольку эти проблемы возникают и решаются не на уровне протокола, а на уровне локальной реализации, механизмы решения не относятся к самому протоколу. По этой причине они вынесены в данное приложение.

Выбор варианта будет очевидно зависеть от сценария использования (поддержки) IPsec NAT-T9. Приведенный здесь список не является исчерпывающим и могут существовать другие решения. Сначала будут описаны базовые решения, пригодные для всех протоколов вышележащего уровня.

При использовании ESP в транспортном режиме имеется несколько основных вариантов, перечисленных ниже.

Tr1) Реализация встроенного NAT (трансляция сетевых адресов) выше декапсуляции IPsec.

Tr2) Реализация встроенного NAPT (трансляция сетевых адресов и портов) выше декапсуляции IPsec.

Tr3) Инициатор может отказаться от запроса транспортного режима при обнаружении NAT и запросить взамен организацию туннельной SA. Это может произойти после отказа поддержки транспортного режима отвечающим или изначально по желанию инициатора. Решение этого вопроса не сложнее вопроса выбора туннельного или транспортного режима без NAT. Если по тем или иным соображениям ответчик предпочитает или требует использовать туннельный режим для работы через NAT, он должен отвергнуть предложение организации транспортной SA в ускоренном режиме.

При использовании ESP в туннельном режиме имеется несколько основных вариантов, перечисленных ниже.

Tn1) Совпадает с Tr1.

Tn2) Совпадает с Tr2.

Tn3) Этот вариант возможен, если инициатору может быть выделен адрес через его туннельную связь SA от сервера DHCP на отвечающей стороне. Инициатор может сразу запросить адрес через DHCP-IPsec, независимо от его предположений о наличии или отсутствии NAT. Он может заново инициировать согласование IKE в ускоренном режиме для DHCP через туннельную SA после того, как ответчик отвергнет ускоренное предложение о создании транспортной SA. Это происходит при передаче элемента данных NAT-OA или в результате обнаружения через NAT-D размещения инициатора за транслятором NAT и требования локальной политики (конфигурации, воспринимать соединения через NAT только при выделении адресов через DHCP-IPsec.

Разработчики могут также выбрать ограничение интероперабельности для своей реализации. Разработчикам следует указывать, какие протоколы и приложения смогут работать в таком ограниченном варианте. Отметим, что для вариантов Tr4 и Tn4 не предполагается возможность работы с трафиком TCP (см. ниже).

Ниже перечислены варианты ограниченной интероперабельности для транспортного режима ESP.

Tr4) Реализовать в протоколе вышележащего уровня осведомленность о необходимости отказа от использования во входящих и исходящих IPsec SA адреса IP и номера порта отправителя в качестве идентификатора сессии (например, идентификаторы сессий L2TP отображаются на пары IPsec SA без использования порта UDP или IP-адреса отправителя).

Tr5) Реализовать интеграция приложения с инициированием IKE так, чтобы можно было организовать привязку к другому порту отправителя, если ускоренное предложение IKE SA будет отвергнуто ответчиком; после этого может быть заново предложен новый селектор QM10.

Ниже перечислены варианты ограниченной интероперабельности для транспортного режима ESP.

Tn4) Совпадает с Tr4.

Адреса авторов

Ari Huttunen

F-Secure Corporation

Tammasaarenkatu 7

HELSINKI FIN-00181

FI

EMail: Ari.Huttunen@F-Secure.com

Brian Swander

Microsoft

One Microsoft Way

Redmond, WA 98052

US

EMail: briansw@microsoft.com

Victor Volpe

Cisco Systems

124 Grove Street

Suite 205

Franklin, MA 02038

US

EMail: vvolpe@cisco.com

Larry DiBurro

Nortel Networks

80 Central Street

Boxborough, MA 01719

US

EMail: ldiburro@nortelnetworks.com

Markus Stenberg

FI

EMail: markus.stenberg@iki.fi

Перевод на русский язык

Николай Малых

nmalykh@gmail.com

Полное заявление авторских прав

Copyright (C) The Internet Society (2005).

This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an «AS IS» basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Интеллектуальная собственность

The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF’s procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79.

Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.

Подтверждение

Финансирование функций RFC Editor обеспеченоInternet Society.

1Encapsulating Security Payload — инкапсулированное защищенное содержимое.

2Network Address Translator — транслятор сетевых адресов.

3Internet Key Exchange — обмен ключами в Internet.

4Security gateway.

5Этот документ признан устаревшим и заменен RFC 4301. Прим. перев.

6Этот документ признан устаревшим и заменен RFC 4303, RFC 4305. Прим. перев.

7Этот документ признан устаревшим и заменен RFC 4306, а затем RFC 5996 и RFC 7296. Прим. перев.

8Работа завершена и опубликована в RFC 4306, который затем заменен RFC 5996 и RFC 7296. Прим. перев.

9NAT Traversal — работа через NAT. Прим. перев.

10Ускоренного режима. Прим. перев.




RFC 3986 Uniform Resource Identifier (URI): Generic Syntax

Network Working Group                                     T. Berners-Lee
Request for Comments: 3986                                       W3C/MIT
STD: 66                                                      R. Fielding
Updates: 1738                                               Day Software
Obsoletes: 2732, 2396, 1808                                  L. Masinter
Category: Standards Track                                  Adobe Systems
                                                            January 2005

Базовый синтаксис идентификаторов URI

Uniform Resource Identifier (URI): Generic Syntax

PDF

Статус документа

В этом документе содержится проект стандарта для протокола Internet, предложенного сообществу Internet. Документ служит приглашением к дискуссии в целях развития и совершенствования протокола. Текущее состояние стандартизации протокола вы можете узнать из документа Internet Official Protocol Standards (STD 1). Документ может распространяться без ограничений.

Авторские права

Copyright (C) The Internet Society (2005).

Тезисы

Унифицированный идентификатор ресурса (URI1) представляет собой компактную последовательность символов, указывающую абстрактный или физический ресурс. Данная спецификация определяет базовый синтаксис URI и процесс преобразования ссылок URI, которые могут иметь относительную форму, а также содержит рекомендации и обсуждение вопросов безопасности при использовании URI в сети Internet. Синтаксис URI определяет грамматику, которая является надмножеством всех корректных URI, позволяющую реализациям разбирать основные компоненты ссылки URI без наличия информации о конкретных требованиях схемы для каждого из возможных идентификаторов. Спецификация не определяет порождающую грамматику для URI — такая задача выполняется индивидуальными спецификациями для каждой схемы URI.

Оглавление

Исключено в версии HTML

1. Введение

Идентификаторы URI обеспечивают простой и расширяемый способ указания ресурсов. Эта спецификация синтаксиса и семантики URI основана на концепциях, введенных глобальной информационной инициативой WWW2, где использование таких идентификаторов началось с 1990-х и было описано в документе Universal Resource Identifiers in WWW [RFC1630]. Синтаксис разработан в соответствии с документами Functional Recommendations for Internet Resource Locators [RFC1736] и Functional Requirements for Uniform Resource Names [RFC1737].

Этот документ отменяет [RFC2396], который объединил в себе документы Uniform Resource Locators [RFC1738] и Relative Uniform Resource Locators [RFC1808] для определения единого базового синтаксиса URI. Документ отменяет также [RFC2732], где был введен синтаксис для адресов IPv6. Он исключает часть RFC 1738, определяющую специфический синтаксис для отдельных схем URI — эти части были обновлены в отдельных документах. Процесс регистрации новых схем URI определен отдельно в [BCP35]. Рекомендации для разработчиков новых схем URI можно найти в [RFC2718]. Все существенные отличия от RFC 2396 отмечены в Приложении D.

В этом документе термины «символ» (character) и «кодированный набор символов» (coded character set) используются в соответствии с определением [BCP19], а термин «кодировка символов» (character encoding) в соответствии с определением [BCP19] для «набора символов» (charset).

1.1. Обзор URI

Идентификаторы URI имеют перечисленные ниже особенности.

Унификация (Uniform)

Унификация обеспечивает несколько преимуществ. Можно применять разные типы идентификаторов ресурсов в одном контексте даже при использовании различных механизмов доступа к этим ресурсам. Обеспечивается единая смысловая интерпретация общих семантических соглашений для разнотипных идентификаторов ресурсов. Можно добавлять новые типы идентификаторов без нарушения использования имеющихся типов. Можно использовать одни идентификаторы в разных контекстах, что позволяет новым приложениям или протоколам воспользоваться существующими и широко распространенными наборами идентификаторов.

Ресурс (Resource)

Данная спецификация не ограничивает сферу того, что может быть отнесено к ресурсам. Термин «ресурс» используется в самом общем смысле, обозначая нечто, идентифицируемое с помощью URI. Примерами могут быть электронные документы, изображения, источники информации определенного назначения (например, текущая погода в Лос-Анжелесе), службы (например, шлюз HTTP-SMS) и наборы других ресурсов. Ресурс не обязательно доступен через Internet — например, люди, корпорации, книги в библиотеке могут выступать в качестве ресурсов. Подобно этому, ресурсами могут быть и абстрактные категории типа операторов и операндов в математических выражениях, типы отношений (например, родитель или работник), численные значения (например, 0, 1, ).

Идентификатор (Identifier)

Идентификатор олицетворяет информацию, требуемую для того, чтобы отличить идентифицируемое от всего остального в области идентификации. Использование термина «идентификация» относится к цели отличить ресурс от всех других ресурсов, независимо от способа достижения этой цели (например, по имени, адресу или контексту). Не следует считать, что идентификатор определяет или олицетворяет то, на что он указывает, хотя в некоторых случаях это может наблюдаться. Не следует предполагать, что система, использующая URI, получит доступ к тому или иному ресурсу — во многих случаях URI используются лишь для обозначения ресурсов, никак не способствуя доступу к ним. Не следует также считать, что идентифицируемый ресурс является «точечным» по своей природе (например, ресурс может оказаться именованным множеством или отображением, которое время от времени меняется).

URI является идентификатором, состоящим из последовательности символов, соответствующей синтаксическим правилам <URI> в разделе 3. Он обеспечивает однотипную идентификацию ресурсов через определяемый раздельно набор схем именования (параграф 3.1). Способы выполнения, назначения и разрешения определяются в спецификациях конкретных схем.

Данная спецификация не задает каких-либо ограничений на природу ресурсов, причины, по которым приложения могут обращаться к ресурсам, или типы систем, которые могут применять URI для идентификации ресурсов. Спецификация не требует, чтобы URI, идентифицирующие определенные ресурсы, были неизменными во времени, хотя это и служит одной из общих целей схем URI. Тем не менее, данная спецификация не препятствует приложениям вводить свои ограничения на типы используемых ресурсов или выбирать подмножества URI с желаемыми для приложения характеристиками.

URI имеют глобальную область действия и интерпретируются независимо от контекста, хотя результат интерпретации может быть связан с контекстом конкретного конечного пользователя. Например, http://localhost/ имеет одинаковую интерпретацию для любого пользователя этой ссылки, хотя сетевой интерфейс, соответствующий имени localhost может различаться для каждого пользователя — интерпретация не зависит от доступа. Однако выполняемые на основе такой ссылки действия происходят в контексте конечного пользователя, что предполагает использование для уникальных в глобальном масштабе ресурсов использование URI, который отличает этот ресурс от всех прочих. Идентификаторы URI, относящиеся к локальному контексту конечного пользователя следует применять только в том случае, когда сам контекст определяет аспекты ресурса (например, справочная система ссылается на определенный файл в компьютере конечного пользователя типа file:///etc/hosts).

1.1.1. Базовый синтаксис

Каждый идентификатор URI начинается с имени схемы, как описано в параграфе 3.1, которое указывает спецификацию для выделения идентификаторов в рамках этой схемы. Таким образом, синтаксис URI обеспечивает федеративную, расширяемую систему именования, где спецификация каждой схемы может дополнительно ограничивать синтаксис и семантику используемых в этой схеме идентификаторов.

Данная спецификация определяет синтаксические элементы URI используемые во всех или многих схемах URI. Таким образом, определяется синтаксис и семантика, требуемые для реализации независимых от схем механизмов разбора ссылок URI, благодаря чему зависящую от схемы обработку URI можно отложить до того момента, когда потребуется зависящая от схемы семантика URI. Аналогично, протоколы и форматы, использующие ссылки URI, могут использовать эту спецификацию, как определение синтаксиса, разрешенного для всех URI, включая и схемы, которые еще не определены. Это отвязывает развитие схем идентификации от развития протоколов, форматов данных и реализаций, использующих URI.

Анализатор базового синтаксиса URI может разобрать любую ссылку URI на основные компоненты. После определения схемы для компонент может быть применен специфический для этой схемы разбор. Иными словами, базовый синтаксис URI является надмножеством синтаксиса всех схем URI.

1.1.2. Примеры

Ниже приведены примеры нескольких URI, иллюстрирующие разные схемы URI и варианты компонент базового синтаксиса.

      ftp://ftp.is.co.za/rfc/rfc1808.txt
      http://www.ietf.org/rfc/rfc2396.txt
      ldap://[2001:db8::7]/c=GB?objectClass?one
      mailto:John.Doe@example.com
      news:comp.infosystems.www.servers.unix
      tel:+1-816-555-1212
      telnet://192.0.2.16:80/
      urn:oasis:names:specification:docbook:dtd:xml:4.1.2

1.1.3. URI, URL и URN

URI можно разделить на локацию, имя или оба вместе. Термин URL3 обозначает подмножество URI, которое в дополнение к идентификации ресурса указывает его «расположение» путем обозначения основного механизма доступа (например, его «расположения» в сети). Термин URN4 исторически применялся для обозначения обоих типов URI в схеме urn [RFC2141] — уникальных в глобальном масштабе и неизменных даже в случаях прекращения существования ресурса или утраты доступа к нему имен, а также любых других URI со свойствами имени.

Отдельные схемы не нужно классифицировать, как «локатор» или «имя». Экземпляры URI из любой данной схемы могут иметь характеристики имени, локации или обоих сразу (зачастую, в зависимости от действий агентства по именованию, а не особенностей схемы). В будущих спецификациях и связанных с ними документах следует применять общий термин URI, а не более ограниченные термины URL и URN [RFC3305].

1.2. Внутреннее устройство

1.2.1. Транскрипция

Одним из основных соображений при разработке синтаксиса URI была глобальная транскрипция. URI представляет собой последовательность символов из весьма ограниченного набора — буквы латиницы, цифры и несколько специальных символов. URI можно представить разными способами- например, записать на бумаге, вывести на экран или передать в виде последовательности октетов. Интерпретация URI зависит только от использованных символов, а не от способа представления этих символов в сетевом протоколе.

Цели транскрипции можно показать на простом примере. Представим себе двух коллег — Сема и Кима, сидящих в пабе на международной конференции и обменивающихся между собой идеями. Сэм спрашивает у Кима, где можно получить дополнительную информацию и Ким пишет для него URI исследовательского сайта на салфетке. По возвращении домой Сэм вводит URI с салфетки в свой компьютер и находит информацию, о которой говорил Ким.

Этот пример демонстрирует некоторые соображения, которые следует принимать во внимание:

  • URI является последовательностью символов, которые не обязательно представляются последовательностью октетов;

  • URI можно получить не только через сеть, поэтому ему следует состоять из символов, которые могут быть введены в компьютер с учетом ограничений, присущих клавиатурам (и другим устройствам ввода) в части языка и кодировок символов;

  • URI зачастую приходится запоминать, поэтому для человека важно присутствие в составе URI понятных и знакомых компонент.

Эти соображения не всегда согласуются между собой. Например, достаточно часто наиболее значимая компонента имени в URI будет требовать использования символов, которые не могут быть введены в некоторых системах. Возможность переноса идентификаторов ресурсов из одной среду в другую является более важным свойством, нежели осмысленность отдельных компонент URI.

В локальном или региональном контексте по мере развития технологий пользователи будут получать преимущества от возможности применения более широкого набора символов, включая отсутствующие в данной спецификации. Для представления символов, не входящих в кодировку US-ASCII, в URI возможно %-представление (percent-encoding), описанное в параграфе 2.1, если такое представление разрешает используемая схема и протокольный элемент, в который включается URI. Такие определения должны учитывать кодировку используемых символов для их отображения на октеты до использования %-представления для URI.

1.2.2. Отделение идентификации от взаимодействия

Основным недоразумением, связанным с URI, является представление, что эти идентификаторы используются только для ссылок на доступные ресурсы. URI, сам по себе, лишь обеспечивает идентификацию ресурса, а доступ к такому ресурсу не гарантируется и не предполагается в URI. Вместо этого любая операция, связанная со ссылкой URI, определяется протокольным элементом, атрибутом формата данных или текстом на естественном языке, в котором присутствует этот идентификатор.

На основе URI система может попытаться выполнить по отношению к ресурсу различные операции, которые можно описать словами «доступ», «обновление», «замена», поиск атрибутов». Такие операции определяются протоколами, которые могут использовать URI, а вовсе не данной спецификацией. Однако мы используем некоторые термины общего назначения для базовых операций с URI. Преобразование URI (resolution) представляет собой процесс определения механизма доступа и подходящих параметров, требуемых для разыменования URI. Такое преобразование может потребовать нескольких итераций. Для использования механизма доступа с целью выполнения действия по отношению к указанному URI ресурсу нужно «разыменовать» URI.

Когда URI используются в информационно-поисковых системах для идентификации источника данных, наиболее распространенной формой разыменования URI является «извлечение» — возможность использовать URI для того, чтобы получить представления связанного с идентификатором ресурса. «Представление» является последовательностью октетов в комбинации с метаданными, описывающими эти октеты, которые совместно составляют запись о состоянии ресурса на момент генерации представления. Извлечение достигается с помощью процесса, который может включать использование URI в качестве кэш-ключа для проверки локально кэшированного представления (если оно имеется) и разыменования URI для применения операции извлечения (поиска). В зависимости от используемого для поиска протокола может быть предоставлена дополнительная информация о ресурсе (метаданные) и его связях с другими ресурсами.

Ссылки URI в информационно-поисковых системах рассчитаны на отложенную привязку (late-binding) — результат доступа в общем случае определяется в момент доступа и может существенно меняться в зависимости от времени и других аспектов взаимодействия. Эти ссылки создаются для использования в будущем — то, что идентифицируется, не является неким конкретным результатом, полученным раньше, а представляет некие характеристики, которые предполагаются верными для будущих результатов. В таких случаях ресурс, указанный URI, реально представляет собой единообразие характеристик, наблюдаемых с течением времени, возможно сопровождаемых некоторыми комментариями и заявлениями, сделанными держателем (провайдером) ресурса.

Хотя имена многих схем URI включают протокол, это не предполагает, что использование этих URI обеспечит доступ к ресурсу по этому протоколу. URI зачастую используются просто для идентификации. Даже при использовании URI для поиска представления ресурса доступ может выполняться через шлюзы, прокси, системы кэширования, службы преобразования имен, которые не зависят от протокола, связанного с именем схемы. Преобразование некоторых URI может потребовать использования не одного протокола (например, DNS и HTTP обычно требуются для доступа к http URI, если представление отсутствует в локальном кэше).

1.2.3. Иерархические идентификаторы

Синтаксис URI организован иерархически с компонентами, перечисленными в порядке убывания значимости слева направо. Для некоторых схем URI видимая иерархия ограничивается самой схемой — все, что указано после разграничителя компонент схемы (:) считается непрозрачным для обработки URI. Другие схемы URI деляют иерархия явной и видимой для алгоритмов разбора общего назначения.

Базовый синтаксис использует символы / (дробная черта), ? (знак вопроса) и # (знак номера) для разграничения компонент, которые значимы для иерархической интерпретации идентификатора средствами разбора общего назначения. В дополнение к улучшению читаемости таких идентификаторов за счет согласованного использования знакомого синтаксиса это унифицированное представление иерархии в схемах именования позволяет создавать независимые от схемы ссылки относительно такой иерархии.

Зачастую организуется группа или «дерево» документов, служащих общей цели, где большинство ссылок URI указывает на ресурсы внутри этого дерева. Аналогично, документы, расположенные на конкретном сайте гораздо чаще будут ссылаться на ресурсы этого сайта, нежели на ресурсы других. Относительные ссылки URI позволяют обеспечить частичную независимость дерева документов от места его расположения и схемы доступа. Например, один и тот же набор гипертекстовых документов может быть доступен и переносим с помощью схем file, http и ftp, если в документах другие документы указаны относительными ссылками. Кроме того, такое дерево документом можно целиком перенести в другое место, не меняя относительных ссылок.

Относительные ссылки (параграф 4.2) указывают на ресурс путем описания разницы в иерархическом пространстве имен между контекстом ссылки и целевым URI. Алгоритм преобразования ссылок, описанный в разделе 5, определяет способ преобразования таких ссылок в целевые URI. Поскольку относительные ссылки могут применяться только в контексте иерархических URI, разработчикам новых схем URI следует использовать синтаксис, согласующийся с базовыми иерархическими компонентами, если нет важный причин для отказа от использования в схеме относительных ссылок.

Примечание. В предыдущих спецификациях использовались термины partial URI и relative URI для обозначения относительных ссылок URI. Поскольку некоторых такая терминология вводила в заблуждение и они считали относительные URI неким подмножеством URI, а не методом указания ссылок URI, в данной спецификации используется термин «относительные ссылки» (relative reference).

Все ссылки URI разбираются анализатором базового синтаксиса. Однако, поскольку иерархическая обработка не оказывает влияния на абсолютные URI, используемые в ссылках, не содержащих сегментов с точками (сегменты полного пути с символами «.» и «..», как описано в параграфе 3.3), спецификации схем URI могут определять «непрозрачные» идентификаторы для запрета использования символов дробной черты, вопросительного знака и URI вида «scheme:.» и «scheme:..».

1.3. Синтаксические обозначения

В этой спецификации применяются обозначения ABNF5 [RFC2234], включая основные элементы синтаксиса ABNF, используемые в данной спецификации, — ALPHA (буквы), CR (возврат каретки), DIGIT (десятичные цифры), DQUOTE (двойные кавычки), HEXDIG (шестнадцатеричные цифры), LF (перевод строки) и SP (пробел). Полный синтаксис URI собран в Приложении A.

2. Символы

Синтаксис URI предоставляет метод идентификации ресурсов с помощью последовательности символов. Символы URI, в свою очередь, часто кодируются в форме октетов для передачи или представления. Эта спецификация не задает какого-либо конкретного способа отображения между символами URI и октетами, служащими или передачи этих символов. Когда URI включается в элемент протокола, кодировка символов определяется этим протоколом и без такого определения в URI предполагается такая же кодировка символов, как в окружающем тексте.

Нотация ABNF определяет терминальные значения, как неотрицательные целые числа (код — codepoint) на базе кодировки US-ASCII [ASCII]. Поскольку URI является последовательностью символов, нужно обратить эту связь для понимания синтаксиса URI. Следовательно, целые числа, используемые ABNF должны быть отображены обратно на соответствующие символы US-ASCII для завершения синтаксических правил.

URI состоят из ограниченного набора символов, включающего цифры, буквы и несколько специальных знаков. Зарезервированное подмножество этих символов может использоваться для разграничения синтаксических компонент внутри URI тогда, как оставшиеся символы (включая незарезервированные и зарезервированные, но не используемые в качестве разграничителей) определяют каждую компоненту идентификатора.

2.1. %-представление

Механизм %-кодирования служит для представления в компонентах идентификаторов октетов данных, для которых нет символов в числе разрешенных или соответствующий октету символ является разделителем компонент или внутри компоненты. Октет с %кодированием представляется тремя символами — сначала следует знак №, а за ним две шестнадцатеричных цифры, определяющие значение октета. Например, «%20» будет представлять двоичный октет 00100000 (ABNF — %x20), которому в кодировке US-ASCII соответствует символ пробела (SP). Применение кодирования и декодирования с использованием % описано в параграфе 2.4.

      pct-encoded = "%" HEXDIG HEXDIG

Заглавные буквы A — F в качестве шестнадцатеричных цифр эквивалентны буквам a — f. Если два URI отличаются только регистром букв в шестнадцатеричных цифрах при использовании %-кодирования, эти идентификаторы являются эквивалентными. Для согласованности при создании и нормализации URI следует использовать заглавные буквы в %-представлении.

2.2. Зарезервированные символы

URI включают компоненты и субкомпоненты, разграниченные символами из «зарезервированного» набора. Эти символы называют «зарезервированными», поскольку они могут (но не обязаны) применяться в качестве разграничителей в базовом синтаксисе, синтаксисе отдельных схем или синтаксисе приложений при разыменовании URI. Если какой-либо из зарезервированных символов требуется включить в состав компоненты URI (не в качестве разграничителя), для него должно использоваться %-кодирование до вставки символа в URI.

      reserved    = gen-delims / sub-delims
      gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
      sub-delims  = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

Целью резервирования является выделение набора символов разграничения, отличимых от остальных символов URI. Идентификаторы URI, различающиеся заменой зарезервированных символов %-представлениями, не являются эквивалентными. %-кодирование зарезервированных символов и декодирование октетов с %представлениям зависит от интерпретации URI в большинстве приложений. Символы зарезервированного набора защищены от нормализации и, следовательно, могут без опаски применяться в определяемых схемой или производителем алгоритмах разграничения для отделения друг от друга компонент URI.

Отдельное подмножество зарезервированных символов (gen-delims) применяется в качестве базовых разграничителей компонент URI, как описано в разделе 3. Синтаксические правила ABNF для компонент не будет использовать символы reserved и gen-delims напрямую, вместо этого каждое синтаксическое правило указывает разрешенные для компоненты символы (т. е., символы, не служащие разграничителями) и, если в числе таких символов оказываются зарезервированные, они могут использоваться для разграничения субкомпонент внутри компоненты. Данная спецификация определяет лишь наиболее общие субкомпоненты, а спецификации схем URI или синтаксис конкретной реализации алгоритма разыменования URI могут определять дополнительные символы разграничения из числа разрешенных для компоненты.

Создающим URI приложениям следует использовать %-представления октетов, соответствующих символа из числа зарезервированных, если эти символы специально не разрешены схемой URI для представления данных в компонентах. Если в компоненте URI обнаружен зарезервированный символ, для которого не известно правило разделения, этот символ должен интерпретироваться, как октет данных, соответствующий символу US-ASCII.

2.3. Незарезервированные символы

Символы, разрешенные для применения в URI, но не зарезервированные в качестве разграничителей, называют незарезервированными (unreserved). К таким символам относятся строчные и прописные буквы, десятичные цифры, дефис, точка, символ подчеркивания и тильда.

      unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"

Идентификаторы URI, различающиеся заменой незарезервированных символов %-представлениями, не являются эквивалентными — они указывают один и тот же ресурс. Однако при реализации сравнения URI нормализация не всегда выполняется до сравнения (см. раздел 6). Для согласованности %-кодирование октетов ALPHA (%41-%5A и %61-%7A), DIGIT (%30-%39), дефиса (%2D), точки (%2E), подчеркивания (%5F) или тильды (%7E) не следует применять при создании URI, а при обнаружении такого представления в URI следует сначала выполнить соответствующее декодирование с помощью нормализатора URI.

2.4. Кодирование и декодирование

В обычных обстоятельствах существует единственный момент, когда для октетов внутри URI используется %-кодирование в процессе создания URI из компонент — момент, когда реализация определяет, какие из зарезервированных символов будут разграничивать компоненты, а какие можно безопасно использовать для данных. После создания URI всегда хранится в %-представлении.

При разыменовании URI компоненты и субкомпонеты, значимые для процесса разыменования конкретной схемы (если таковые есть), должны анализироваться и разделяться до того, как октеты с %-кодированием в этих компонентах будут безопасно декодированы, поскольку в противном случае данные могут быть ошибочно истолкованы, как разграничитель. Единственное исключение применяется для %-кодированных октетов, соответствующих незарезервированным символам, которые можно декодировать в любой момент. Например, октет, соответствующий тильде (~), старые реализации URI часто представляют в форме %7E и последовательность %7E может быть заменена символом ~ без изменения интерпретации.

Поскольку символ % служит индикатором специального представления символов, для него должно применяться %-кодирование %25, если символ нужен в составе URI. Реализациям недопустимо использовать %-кодирование или декодирование одной строки более одного раза, поскольку декодирование уже декодированной строки может приводить к ошибочной интерпретации октета с символом %, как начала нового %-представления и наоборот в случае %-кодирования уже кодированной строки.

2.5. Идентификационные данные

Символы URI обеспечивают идентификацию данных для каждой компоненты URI, выступая в качестве внешнего интерфейса для идентификации между системами. Хотя существование и природа интерфейса создания URI скрыты от клиентов, использующих URI (и, таким образом, находятся за пределами требований интероперабельности, задаваемых данной спецификацией), они зачастую являются источником недоразумений и ошибок при интерпретации символов URI. Разработчикам следует принимать во внимание наличие множества кодировок символов в процессе создания и передачи URI — локальная кодировка имен и данных, кодировка публичного интерфейса, кодировка символов URI, кодировка формата данных и протокольная кодировка.

Локальные имена типа имен системных файлов сохраняются в локальной кодировке символов. Создающие URI приложения (например, серверы-источники) обычно используют локальную кодировку в качестве основы для создания осмысленных имен. Производитель URI преобразует локальную кодировку в одну из подходящих для публичного интерфейса и потом преобразует созданное представление в ограниченный набор символов URI (зарезервированные и незарезервированные символы, %-представление). Эти символы, в свою очередь, кодируются в октеты, которые используются форматом представления данных (например, кодировка документа), а данные зачастую передаются с использованием кодирования в протоколах Internet.

Для большинства систем незарезервированные символы в компонентах URI интерпретируются, как октеты данных, соответствующие представлению данного символа в кодировке US-ASCII. Потребители URI считают, что буква X соответствует октету 01011000 и даже в тех случаях, когда подобное допущение некорректно, оно не наносит вредя. Системы с внутренними идентификаторами в другой кодировке (например, EBCDIC) обычно выполняют трансляцию символов в текстовых идентификаторах в кодировку UTF-8 [STD63] (или какое-либо другое надмножество US-ASCII) at на внутреннем интерфейсе, обеспечивая таким способом юолее осмысленные идентификаторы, нежели те, которые даст простое %-представление исходных октетов.

В качестве примера рассмотрим информационную службу, которая предоставляет данные, локально хранящиеся на файловой системе с кодировкой EBCDIC, клиентам через Internet с помощью сервера HTTP. Когда автор создает файл с именем Laguna Beach в файловой системе, в http URI для соответствующего ресурса разумно предположить осмысленную строку Laguna%20Beach. Однако, если сервер создает идентификаторы URI, используя чрезмерно упрощенное отображение октетов, в результате будет получен URI со строкой %D3%81%87%A4%95%81@%C2%85%81%83%88. Внутренний интерфейс преобразования кодировки исправит эту проблему путем трансляции локального имени в надмножество US-ASCII до создания URI. Естественно, для корректной интерпретации входных URI на таком интерфейсе требуется декодирование октетов с %-представлением (например, %20 преобразовать в SP) до того, как будет проведена обратная смена кодировки для получения локального имени.

В некоторых случаях внутренний интерфейс между компонентой URI и идентификационными данными, которые будут представлять ресурс, значительно менее прямой, чем трансляция кодировки. Например, честь URI может отражать запрос отличных от ASCII данных или числовых координат на карте. Подобно этому, схема URI может определять компоненты с дополнительными требованиями к кодированию, которые применяются до формирования компонент и создания URI.

Когда новая схема URI определяет компоненту, представляющую текстовые данные, которые состоят из символов UCS6 [UCS], данные следует сначала представить в форме октетов, соответствующих кодировке UTF-8 [STD63] и только тогда не соответствующие незарезервированным символам октеты следует преобразовывать в %-представление. Например, символ A будет представляться, как A, символ LATIN CAPITAL LETTER A WITH GRAVE7 — как %C3%80, а символ KATAKANA LETTER A8 — как %E3%82%A2.

3. Синтаксические компоненты

Базовый синтаксис URI включает иерархическую последовательность компонент, называемых схемой (scheme), основанием (authority), путем (path), запросом (query) и фрагментом (fragment).

      URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
      hier-part   = "//" authority path-abempty
                  / path-absolute
                  / path-rootless
                  / path-empty

Схема и путь являются обязательными компонентами, хотя путь может быть пустым (нет символов). При наличии компоненты authority путь должен начинаться с символа дробной черты (/) или быть пустым. При отсутствии authority путь не может начинаться с двух символов дробной черты (//). Эти ограничения приводят к 5 разным правилам ABNF для пути (gfhfuhfa 3.3), из которых только одно будет соответствовать любой заданной URI ссылке.

Ниже приведены примеры двух URI с отметкой их компонент.

         foo://example.com:8042/over/there?name=ferret#nose
         \_/   \______________/\_________/ \_________/ \__/
          |           |            |            |        |
       схема     основание        путь        запрос  фрагмент
          |   _____________________|__
         / \ /                        \
         urn:example:animal:ferret:nose

3.1. Схема

Каждый идентификатор URI начинается с имени схемы, которое указывает спецификацию для выделения идентификаторов в рамках этой схемы. Таким образом, синтаксис URI представляет собой федеративную, расширяемую систему именования, в которой спецификация каждой схемы может вносить свои ограничения в синтаксис и семантику применяемых в этой схеме идентификаторов.

Имя схемы состоит из последовательности символов, начинающейся с буквы, за которой может следовать любая комбинация букв, цифр, а также плюсов (+), точек (.) и дефисов (-). Хотя регистр символов в схемах не принимается во внимание, канонической формой является использование строчных букв (нижний регистр) и в документах со спецификациями схем должны использоваться строчные буквы. Реализациям следует воспринимать прописные буквы в качестве эквивалентов соответствующих строчных (например, HTTP и http) для повышения отказоустойчивости, но для совместимости следует выдавать только строчные буквы.

      scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

Спецификации конкретных схем не включены в этот документ. Процесс регистрации новых схем URI определен в [BCP35]. Реестр схем поддерживает отображение между именами и спецификациями схем. Рекомендации для разработчиков новых схем URI можно найти в [RFC2718]. Спецификация схемы URI должна определять свой собственный синтаксис так, чтобы все соответствующие ему строки соответствовали также грамматике <absolute-URI>, описанной в параграфе 4.3.

В случае представления URI с нарушением ограничений для одной или нескольких схем процессам преобразования соответствующих схем следует помечать ссылку, как ошибочную, вместо игнорирования неиспользуемых частей — это позволит снизить число эквивалентных URI и поможет обнаружить неприемлемое использование базового синтаксиса, которое может показывать, что URI был создан для того, чтобы ввести пользователя в заблуждение (параграф 7.6).

3.2. Основание

Многие схемы включают иерархический элемент для «органа именования», которому передаются полномочия по управлению пространством имен, определяемым оставшейся частью URI. Этот «орган» (основание), в свою очередь, может делегировать полномочия кому-либо еще. Базовый синтаксис обеспечивает общие способы различать основания на основе зарегистрированных имен или адресов серверов вкупе с дополнительной информацией о пользователе и порте.

Компоненте authority предшествуют символы //, а завершается она одиночным символом /, знаком вопроса (?), символом номера (#) или просто окончанием URI.

      authority = [ userinfo "@" ] host [ ":" port ]

При создании и нормализации URI следует опускать разграничитель «:», отделяющий хост от порта, если компонента порта пустая. Некоторые схемы не позволяют использовать субкомпоненты порта и/или информации о пользователе.

Если URI содержит компоненту authority, путь должен начинаться с символа / или быть пустым. Анализаторы без проверки (которые просто делят ссылку URI на основные компоненты) зачастую игнорируют структуру субкомпонент основания, трактуя, как цельную строку между все, что находится между символами // и первым завершающим разделителем до тех пор, пока URI не будет разыменован.

3.2.1. Информация о пользователе

Субкомпонента userinfo может состоять из имени пользователя и, опционально, обусловленной схемой информации для получения доступа к ресурсу. При наличии информации о пользователя за ней следует символ @, отделяющий ее от хоста.

      userinfo = *( unreserved / pct-encoded / sub-delims / ":" )

Использование формата user:password в поле userinfo устарело. Приложениям не следует отображать в форме открытого текста какие-либо данные после символа двоеточия (:) в субкомпоненте userinfo, если это не пустая строка (указывающая отсутствие пароля). Приложения могут игнорировать или отвергать такие данные, когда они получены, как часть ссылки, и следует отвергать эти данные, если они не зашифрованы. Передача аутентификационной информации в открытом виде приводит к риску безопасности практически в любом варианте применения.

Приложениям, которые отображают URI для обратной связи с пользователем (например, графические браузеры гипертекста), следует выводить userinfo так, чтобы эту информацию можно было отличить от остальной части URI. Такое отображение поможет пользователю в тех случаях, когда userinfo используется для ввода в заблуждение, будучи представленной подобно доверенному доменному имени (см. параграф 7.6).

3.2.2. Хост

Субкомпонента host в authority идентифицируется IP-литералом в квадратных скобках, адресом IPv4 с разделением полей точками или зарегистрированным именем. Регистр символов в субкомпоненте host не принимается во внимание. Наличие субкомпоненты host в URI не подразумевает, что схема требует доступа к указанному хосту Internet. Во многих случаях host-синтаксис применяется лишь с целью воспользоваться существующим процессом регистрации, реализованным в DNS, которые обеспечивает уникальные в глобальном масштабе имена без издержек на развертывание дополнительного реестра имен. Однако такое использование не достается даром — владелец указанного имени может смениться с течением времени по причинам, не предусмотренным создателем URI. В других случаях данные компоненты host идентифицируют зарегистрированное имя, которое никак не связано с хостом Internet. Термин host используется для правила ABNF потому, что он чаще всего используется для указания хоста, но такое применение не является единственным.

      host = IP-literal / IPv4address / reg-name

Синтаксическое правило для хоста неоднозначно, поскольку оно не полностью различает IPv4address и reg-name. Для устранения этой неоднозначности применяется алгоритм «первого соответствия» (first-match-wins) — если host соответствует правилу для IPv4address, эту субкомпоненту следует считать адресом IPv4, а не зарегистрированным именем (reg-name). Хотя регистр символов в host не принимается во внимание, создателям и нормализаторам следует использовать символы нижнего регистра (строчные буквы) для имен и шестнадцатеричных адресов в целях однородности, а заглавные буквы применять только для %-представления.

Хост, идентифицируемый буквальным адресом IP версии 6 [RFC3513] или выше, выделяется квадратными скобками по обе стороны IP-литерала ([литерал]). Это единственный случай применения квадратных скобок в синтаксисе URI. В предположении будущих (еще не определенных) форматов IP-литералов реализации могут использовать необязательный флаг версии для явной индикации такого формата вместо его эвристической идентификации.

      IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
      IPvFuture  = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )

Флаг версии не указывает номер версии IP, а показывает будущие версии формата литерала. По этой причине реализациям недопустимо устанавливать флаг версии для имеющихся литеральных адресов IPv4 и IPv6, описанных ниже. Если URI содержит IP-литерал, начинающийся с v (регистр не имеет значения),что показывает наличие флага версии, и разыменовывается приложением, которое не знает значения этого флага версии, этому приложению следует вернуть подходящий сигнал ошибки (address mechanism not supported — неподдерживаемая адресация).

Хост, идентифицируемый литеральным адресом IPv6, указывается в квадратных скобках без предшествующего флага версии. Представленный здесь формат ABNF представляет собой трансляцию текстового определения адреса IPv6 из [RFC3513]. Этот синтаксис не поддерживает идентификаторы областей действия адресов IPv6. 128-битовый адрес IPv6 делится на восемь 16-битовых частей. Каждая из частей представляется числовым 16-ричным значением (без учета регистра букв), содержащим от 1 до 4 символов (нули в начале опускаются). Восемь представленных таким способом частей указываются от старшей к младшей с разделением двоеточиями. Две младшие части могут быть представлены в текстовом формате IPv4. Одна или несколько последовательных 16-битовых частей со значением могут быть опушены (пусты) с сохранением лишь двоеточий в качестве разделеителей опущенных частей.

      IPv6address =                            6( h16 ":" ) ls32
                  /                       "::" 5( h16 ":" ) ls32
                  / [               h16 ] "::" 4( h16 ":" ) ls32
                  / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
                  / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
                  / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
                  / [ *4( h16 ":" ) h16 ] "::"              ls32
                  / [ *5( h16 ":" ) h16 ] "::"              h16
                  / [ *6( h16 ":" ) h16 ] "::"

      ls32        = ( h16 ":" h16 ) / IPv4address
                                    ; младшие 32 бита адреса

      h16         = 1*4HEXDIG
                  ; 16 битов адреса представлены в 16-ричном формате

Хост, идентифицируемый литеральным адресом IPv4, представляется в нотации с разделением точками (последовательность из 4 десятичных значений от 0 до 255, разделенных точками), как описано в [RFC1123] со ссылкой на [RFC0952]. Отметим, что на некоторых платформах могут использоваться иные варианты обозначения, как описано в параграфе 7.4, но представленная выше форма является единственно разрешенной данной грамматикой.

      IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet

      dec-octet   = DIGIT                 ; 0-9
                  / %x31-39 DIGIT         ; 10-99
                  / "1" 2DIGIT            ; 100-199
                  / "2" %x30-34 DIGIT     ; 200-249
                  / "25" %x30-35          ; 250-255

Хост, идентифицируемый зарегистрированным именем, указывается последовательностью символов, обычно предназначенной для поиска в локальном списке или реестре имен, хотя специфическая семантика схемы URI может требовать использования конкретного реестра (или таблицы с фиксированным именем). Наиболее распространен механизм поиска имен в DNS9. Зарегистрированные имена, предназначенные для поиска в DNS, используют синтаксис, определенный в параграфе 3.5 [RFC1034] и параграфе 2.1 [RFC1123]. Такие имена состоят из последовательности меток, разделенных точками, и каждая метка начинается и заканчивается буквой или цифров и может включать символы «-». За самой правой меткой полного доменного имени в DNS может следовать одна точка и ее следует включать, если требуется различать полные доменные имена от локальных (внутри некого локального домена).

   reg-name = *( unreserved / pct-encoded / "-" / ".")10

Если схема URI предполагает принятую по умолчанию субкомпоненту host, она используется в случае отсутствия субкомпоненты host или при указании пустого имени (нулевой размер). Например схема file для URI определена так, что отсутствие субкомпоненты authority, пустая субкомпонента host и значение localhost указывают на машину локального пользователя, а в схеме http отсутствие authority или пустое значение host не приемлемы.

Данная спецификация не задает конкретной технологии поиска зарегистрированного имени и, следовательно, не ограничивает синтаксис reg-name сверх необходимого для интероперабельности. Решение вопроса проверки соответствия синтаксиса зарегистрированного имени передается операционной системе каждого приложения, выполняющего преобразование URI, и эта операционная система решает, что она будет разрешать для идентификации хоста. Реализация преобразования URI может использовать DNS, таблицы хостов, «желтые страницы», NetInfo, WINS или любую другую систему поиска зарегистрированных имен. Однако для URI с глобальной значимостью требуются глобальные способы именования типа полных доменных имен DNS. Создателям URI следует использовать имена, соответствующие синтаксису DNS, даже в случаях, когда использование DNS не представляется очевидным. Следует также ограничивать размер имен 255 символами.

Синтаксис reg-name разрешает использовать октеты с %-кодированием для того, чтобы представлять зарегистрированные имена с отличными от ASCII символами независимым от технологии преобразования имен способом. Не входящие в ASCII символы должны сначала представляться в кодировке UTF-8 [STD63], а после этого для каждого октета последовательности UTF-8 должно использоваться %-кодирование для представления в качестве символа URI. Приложениям, создающим URI, недопустимо использовать %-кодирование в субкомпоненте host, если оно служит не для последовательности символов UTF-8. Когда зарегистрированное имя с отличными от ASCII символами представляет доменное имя на другом (не английском) языке, предназначенное для преобразования через DNS, имя должно трансформироваться в представление IDNA [RFC3490] до операции поиска. Создателям URI следует представлять такие имена в кодировке IDNA, а не с помощью %-кодирования, если они хотят обеспечить интероперабельность с унаследованными преобразователями URI.

3.2.3. Порт

Субкомпонента port в authority является необязательным номером порта в десятичном формате, следующим за субкомпонентой host и отделенным от нее двоеточием.

      port = *DIGIT

Схема может определять используемый по умолчанию порт. Например, схема http по умолчанию предполагает порт 80, соответствующий зарезервированному порт TCP. Тип порта, обозначенного номером (например, TCP, UDP, SCTP), определяется схемой URI. Создателям и нормализаторам URI следует опускать компоненту port и разграничитель «:», если номер порта не указан или совпадает с используемым в схеме по умолчанию.

3.3. Путь

Компонента path содержит данные (обычно, организованные иерархически), которые вместе с неиерархическими данными компоненты query (параграф 3.4) служат для идентификации ресурса в области действия схемы URI и полномочий именования (если они есть). Путь завершается первым символом «?», «#» или просто концом URI.

Если URI содержит компоненту authority, путь может быть пустым или начинаться с символа «/». Если URI не включает authority, путь не может начинаться с символов «//». Кроме того, ссылка URI (параграф 4.1) может указывать относительный путь и в этом случае первый сегмент пути не может включать символ «:». ABNF задает пять раздельных правил для устранения неоднозначности пути, из которых только одно будет соответствовать подстроке пути в данной ссылке URI. Для обозначения подстрок URI при разборе правил используется базовый термин «компонента пути» (path component).

      path          = path-abempty    ; начинается с / или пуст
                    / path-absolute   ; начинается с /, но не с //
                    / path-noscheme   ; начинается с сегмента без двоеточия
                    / path-rootless   ; начинается с сегмента
                    / path-empty      ; 0 символов

      path-abempty  = *( "/" segment )
      path-absolute = "/" [ segment-nz *( "/" segment ) ]
      path-noscheme = segment-nz-nc *( "/" segment )
      path-rootless = segment-nz *( "/" segment )
      path-empty    = ""11

      segment       = *pchar
      segment-nz    = 1*pchar
      segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
                    ; сегмент ненулевого размера без двоеточий (:)

      pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"

Путь состоит из последовательности сегментов (path segment), разделенных символами «/». Путь всегда определяется для URI, хотя он может быть пустым (нулевого размера). Использование символ дробной черты для индикации иерархии требуется лишь в тех случаях, кода URI будет применяться в качестве контекста для относительных ссылок. Например URI <mailto:fred@example.com> имеет компоненту пути fred@example.com, а <foo://info.example.com?fred> имеет пустой путь.

Сегменты пути «.» и «..», называемые также сегментами из точек (dot-segment), определяются для относительных ссылок в иерархии имен. Они предназначены для использования в начале пути относительных ссылок (параграф 4.2) для индикации положения в иерархическом дереве имен. Это похоже на роль этих символов в структуре каталогов некоторых операционных систем, где одна точка указывает текущий каталог, а две — родительский. Однако, в отличие от файловых систем сегменты с точками интерпретируются только внутри иерархии пути URI и удаляются в процессе преобразования (параграф 5.2).

За исключением сегментов с точками сегменты пути с точки зрения базового синтаксиса являются «непрозрачными». Создающие URI приложения зачастую применяют зарезервированные символы, дозволенные в сегментах, для разграничения специфических для схемы или обработчика субкомпонент. Например, зарезервированные символы «;» и «=» часто служат для разделения параметров и их значений в данном сегменте. Зарезервированный символ запятой «,» часто применяется с аналогичными целями. Например, создатель URI может использовать сегмент вида «name;v=1.1» для индикации ссылки на версию 1.1 для «name», а другой может использовать для этих же целей сегмент вида «name,1.1». Типы параметров могут определяться семантикой конкретной схемы, но в большинстве случаев синтаксис параметра зависит от конкретной реализации алгоритма разыменования URI.

3.4. Запрос

Компонента query содержит неиерархические данные, которые, наряду с данными компоненты path (параграф 3.3), служат для идентификации ресурса в зоне действия схемы URI и полномочий именования (если они есть). Компонента запроса указывается первым символом «?» и завершается символом «#» или концом URI.

      query       = *( pchar / "/" / "?" )

Символы «/» и «?» могут представлять данные в компоненте query. Следует помнить, что некоторые устаревшие реализации с ошибками могут некорректно обрабатывать такие данные при их использовании в качестве базовых URI для относительных ссылок (параграф 5.1), видимо по причине неспособности отделить путь от запроса при просмотре разделителей иерархии. Однако, поскольку компоненты query часто применяются для передачи идентифицирующих данных в форме gfh «ключ=значение» (key=value) и зачастую значение является ссылкой на другой URI, для большей применимости иногда лучше избегать %-представления этих символов.

3.5. Фрагмент

Компонента идентификатора фрагмента URI позволяет опосредованно указывать вторичный ресурс путем ссылки на основной и указания дополнительных идентификационных данных. Идентифицируемым вторичным ресурсом может быть некая часть или подмножество основного ресурса или некий другой ресурс, описанный данным представлением. Компонента идентификатора фрагмент указывается символом «#» и завершается в конце URI.

      fragment = *( pchar / "/" / "?" )

Смысл идентификатора фрагмента определяется множеством представлений, которое может быть результатом операций поиска на первичном ресурсе. Формат и преобразование фрагмента зависят, следовательно, от типа среду [RFC2046] потенциально найденного представления, хотя само этот поиск выполняется только в случае разыменования URI. Если такого представления не существует, семантика фрагмента считается неизвестной и, фактически, неограниченной. Семантика идентификатора фрагмента не зависит от схемы URI и, в силу этого, не может быть переопределена в спецификации схемы.

Отдельные типы сред могут задавать свои ограничения и структуры в рамках синтаксиса идентификатора фрагмента для задания различных типов подмножеств, представления или внешних ссылок, которые могут быть идентифицированы этим типом среду в качестве вторичных ресурсов. Если основной ресурс имеет множество представлений, как часто бывает с ресурсами, чье представление выбирается на основе атрибутов поискового запроса (иными словами, согласования содержимого), тогда все идентифицируемое фрагментом должно быть согласовано в рамках всех таких представлений. Каждому представлению следует определять фрагмент так, чтобы он соответствовал одному и тому же вторичному ресурсу, независимо от способа представления, или просто оставлять фрагмент не определенным (например, не найден).

Как и для всех URI, использование компоненты идентификатора фрагмента не подразумевает реальных поисковых действий. URI с идентификатором фрагмента может применяться для ссылки на вторичный ресурс без каких-либо предположений о доступности или фактах доступа к основному ресурсу.

Идентификаторы фрагментов играют важную роль в информационно-поисковых системах в качестве основного варианта косвенных ссылок на клиентской стороне, что позволяет автору конкретно указать аспекты существующего ресурса, предоставляемые его владельцем лишь опосредованно. Таким образом, идентификаторы фрагментов не используются в специфической для схем обработке URI и отделяются от остальной части URI до разыменования, а идентификационные данные в самом фрагменте разыменовываются только пользовательским агентом, независимо от схемы URI. Хотя такая раздельная обработка зачастую воспринимается как потеря информации, особенно в случаях перенаправления ссылок когда ресурс со временем перемещается, это также позволяет предотвратить возможность запрета авторам указывать селективные ссылки внутри ресурса со стороны держателей информации. Косвенные ссылки также обеспечивают дополнительную гибкость и расширяемость для систем, использующих URI, поскольку определить и развернуть новый тип среды проще, чем новую схему идентификации.

Символы «/» и «?» разрешены для представления данных в идентификаторах фрагментов. Однако следует помнить, что некоторые устаревшие реализации с ошибками могут некорректно обрабатывать такие данные при их использовании в качестве базовых URI для относительных ссылок (параграф 5.1).

4. Применение

Когда приложение указывает ссылку на URI, это не всегда является полной формой URI, определенной правилами синтаксиса. В целях экономии места и использования преимуществ иерархической локализации многие элементы протоколов Internet и форматов типа среды допускают сокращение URI, тогда как другие ограничивают синтаксис конкретной формой URI. В этой спецификации определены наиболее общие формы синтаксиса ссылок, поскольку они оказывают влияние на базовый синтаксис и сами зависят от него, требуя однотипного разбора для обеспечения согласованности интерпретаций.

4.1. Ссылка URI

Ссылки URI (URI-reference) служат для обозначения наиболее распространенного применения идентификаторов ресурсов.

      URI-reference = URI / relative-ref

URI-reference представляет собой URI или относительную ссылку. Если префикс ссылки URI не соответствует синтаксису с указанием схемы, отделенной двоеточием, это говорит о том, что URI-reference является относительной ссылкой.

Ссылка URI обычно сначала разбирается на 5 компонент URI в соответствии с порядком их указания и типом (относительная или абсолютная) ссылки. После этого каждая компонента разбирается на соответствующие части и выполняется их проверка. ABNF для ссылок URI вместе с правилом «первого соответствия» (first-match-wins) вполне достаточно для проверяющего базовый синтаксис анализатора. Читателям, знакомым с регулярными выражениями, следует обратиться к Приложению B, где приведен пример разбора URI-reference без проверки корректности, который будет принимать произвольную строку и выделять из нее компоненты URI.

4.2. Относительная ссылка

Относительные ссылки используют преимущества иерархического синтаксиса (параграф 1.2.3) для выражения ссылок URI относительно пространства имен другого иерархического URI.

      relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
      relative-part = "//" authority path-abempty
                        / path-absolute
                        / path-noscheme
                        / path-empty

Идентификатор URI, указываемый относительной ссылкой, который называют также целевым URI, получается с помощью алгоритма преобразования ссылок, описанного в разделе 5.

Относительные ссылки, начинающиеся с символов //, называют сетевыми путями и используются такие ссылки достаточно редко. Относительные ссылки, начинающиеся с одного символа /, называют абсолютными путями. Относительные ссылки без символа дробной черты в начале называют относительными путями (relative-path reference).

Сегменты пути с символом двоеточия (например, this:that) не могут использоваться в качестве первого сегмента относительного пути, поскольку будет возникать путаница с именами схем. Перед такими сегментами должен присутствовать сегмент с точкой (например, «./this:that») для указания ссылки по относительному пути.

4.3. Абсолютные URI

Некоторые протокольные элементы разрешают только абсолютную форму URI без идентификаторов фрагментов. Например, в базовых URI для использования с относительными ссылками синтаксическое правило absolute-URI не разрешает фрагменты.

      absolute-URI  = scheme ":" hier-part [ "?" query ]

Спецификации схем URI должны определять свой синтаксис так, чтобы все строки, соответствующие этому синтаксису, соответствовали и грамматике <absolute-URI>. Спецификации схем не будут определять синтаксис идентификаторов фрагментов независимо от их применимости к определяемым этой схемой ресурсам, поскольку идентификация фрагментов ортогональна определению схемы. Однако в спецификации схем рекомендуется включать широкий набор примеров, показывающих использование URI этой схемы с идентификаторами фрагментов, когда это применимо.

4.4. Ссылка на тот же документ

Когда ссылка URI указывает на URI, который за исключением его фрагментов (если они есть) идентичен базовому URI (параграф 5.1), это называется ссылкой на тот же документ. Наиболее частым примером таких ссылок являются относительные ссылки, которые пусты или включают лишь символ #, за которым следует идентификатор фрагмента.

При разыменовании ссылки на тот же документ с целью получения документа субъект этой ссылки размещается в том же самом элементе (презентации, документе, сообщении) и, следовательно, после разыменование ссылки не требуется новых поисковых действий.

Нормализация базовых и целевых URI до их сравнения (как описано в параграфах 6.2.2 и 6.2.3) разрешена, но редко выполняется на практике. Нормализация может повышать число ссылок на тот же документ, что позволяет получить преимущества для некоторых систем кэширования. По этой причине авторам ссылок не следует полагать, что слабо различающиеся, но эквивалентные ссылки URI будут (или не будут) интерпретироваться любым приложением как ссылки на тот же документ.

4.5. Ссылки по суффиксам

Синтаксис URI разработан для однозначного указания на ресурсы с возможностью расширения за счет схем URI. Однако использование URI для идентификации стало повсеместным и традиционные средства массовой информации (телевидение, радио, газеты, рекламные щиты и т. п.) все шире применяют в качестве ссылок суффиксы URI, содержащие только компоненты authority и path типа

      www.w3.org/Addressing/

или просто DNS-имя, которое им принадлежит. Такие ссылки предназначены для непосредственного восприятия человек без участия машин и предполагают, что контекстной эвристики достаточно для дополнения URI (например, большинство зарегистрированных имен, начинающихся с www, очевидно имеют в URI префикс http://). Хотя не существует стандартного набора эвристических методов устранения неоднозначности суффиксов URI, многие реализации клиентов позволяют пользователю вводить такие ссылки и эвристическими методами преобразуют их.

И хотя использование ссылок по суффиксам стало повсеместным, его следует по возможности избегать и никогда не следует применять в ситуациях, где предполагается долгосрочная ссылка. Упомянутая выше эвристика может меняться с течением времени (в частности, при распространении новых схем URI) и зачастую будет неприменимой в ином контексте. Кроме того, это может вызывать проблемы безопасности, аналогичные описанным в [RFC1535].

Поскольку суффиксы URI используют такой же синтаксис, как ссылки с относительными путями, их нельзя использовать в контексте, где предполагается наличие относительных ссылок. Поэтому ссылки по суффиксам ограничены ситуациями, где не определено базовых URI, типа диалоговых окон или анонсов off-line.

5. Преобразование ссылки

В этом разделе описан процесс преобразования ссылок URI в контексте, позволяющем использовать относительные ссылки так, что в результате получается строка, соответствующая синтаксическим правилам <URI> из раздела 3.

5.1. Организация базового URI

Термин «относительный» предполагает наличие «базового URI», от которого «начинается» относительная ссылка. Как и ссылки, включающие только фрагменты (параграф 4.4), относительные ссылки применимы только при известном базовом URI. Базовый URI нужно организовать до разбора ссылки URI, которая может быть относительной. Для базового URI требуется соответствие синтаксическому правилу <absolute-URI> (параграф 4.3). Если базовый URI создается из ссылки URI, эта ссылка должна быть преобразована в абсолютную форму с исключением всех фрагментов до использования в качестве базового URI.

Базовый URI для ссылки можно организовать одним из четырех способов, описанных ниже в порядке предпочтения. Порядок предпочтения можно рассматривать в терминах уровней, где самый внутренний вариант базового URI является наиболее предпочтительным (см. рисунок ниже).

         .----------------------------------------------------------.
         |  .----------------------------------------------------.  |
         |  |  .----------------------------------------------.  |  |
         |  |  |  .----------------------------------------.  |  |  |
         |  |  |  |  .----------------------------------.  |  |  |  |
         |  |  |  |  |       <относительная ссылка>     |  |  |  |  |
         |  |  |  |  `----------------------------------'  |  |  |  |
         |  |  |  | (5.1.1) Базовый URI в содержимом       |  |  |  |
         |  |  |  `----------------------------------------'  |  |  |
         |  |  | (5.1.2) Базовый URI инкапсулирующего         |  |  |
         |  |  | элемента (сообщение, презентация или ничего) |  |  |
         |  |  `----------------------------------------------'  |  |
         |  | (5.1.3) URI применяется для поиска элемента        |  |
         |  `----------------------------------------------------'  |
         |(5.1.4) Использ. по умолч. базовый URI (завис. от прилож. )|
         `----------------------------------------------------------'

5.1.1. Базовые URI внутри содержимого

В некоторых типах сред базовые URI для относительных ссылок могут встраиваться непосредственно в содержимое так, что они могут быть легко получены анализатором. Это может быть полезно для описательных документов типа оглавлений, которые могут передаваться другим с использованием протоколов, отличающихся от применяемых в обычном контексте поиска (например, по электронной почте или в новостях USENET).

Методы встраивания базовых URI для каждого типа среды выходят за рамки этой спецификации. В тех случаях, когда это возможно, здесь описывается подходящий синтаксис путем указания формата данных, связанного с типом среды.

5.1.2. Базовый URI из инкапсулирующего элемента

Если нет встроенного базового URI, он определяется контекстом поиска представления. Для вложенных документов (например, в сообщении или архиве), таким контекстом служит инкапсулирующий элемент. Таким образом, по умолчанию базовым URI для представления служит базовый URI инкапсулирующего элемента.

Механизм встраивания базовых URI в контейнеры MIME (например, сообщение или элемент со множеством частей) определен MHTML [RFC2557]. Протоколы, которые не используют синтаксис заголовков MIME, но позволяют включать в сообщения те или иные метаданные с тегами, могут задавать свой синтаксис для определения базового URI.

5.1.3. Базовый URI из поискового URI

Если нет вложенного базового URI и представление не инкапсулировано в некий другой объект, тогда, если URI был использован для получения представления, этот идентификатор URI следует считать базовым URI. Отметим, что если поиск представления привел к перенаправлению, в качестве базового следует использовать последний URI (по которому было получено реальное представление).

5.1.4. Используемый по умолчанию базовый URI

Если не применимо ни одно из описанных выше условий, базовый идентификатор URI определяется контекстом приложения. Поскольку такое определение очевидным образом зависит от приложения, невозможность использовать какой-либо из описанных выше методов может приводить к разной интерпретации одного и того же содержимого в разнотипных приложениях.

Отправитель представления с относительными ссылками отвечает за возможность организации базовых URI для таких ссылок. Как и ссылки, содержащие только идентификаторы фрагментов, относительные ссылки можно надежно применять лишь в ситуациях, где возможно определить базовый URI.

5.2. Преобразование относительных ссылок

В этом разделе описан алгоритм преобразования ссылки URI, которая может быть задана относительно данного базового URI, в компоненты цели. Эти компоненты потом можно собрать в целевой URI, как описано в параграфе 5.3. Этот алгоритм обеспечивает детерминированные результаты и может применяться для тестирования вывода других реализаций. Приложения могут использовать свои алгоритмы преобразования относительных ссылок, если они дают на выходе результат, совпадающих с выходом приведенного здесь алгоритма.

5.2.1. Предварительный разбор базового URI

Базовый организуется URI (Base) в соответствии с описанной в параграфе 5.1 процедурой и разбирается на пять основных компонент, описанных в разделе 3. Отметим, что обязательной для базового URI является лишь компонента scheme, а остальные компоненты могут быть пустыми или не определенными. Компонента считается не определенной, если соответствующий разграничитель отсутствует в ссылке URI. Компонента path определена всегда, но может быть пустой.

Описанная в параграфах 6.2.2 и 6.2.3 нормализация базового URI является необязательной. Ссылка URI должна быть преобразована в целевой URI до выполнения нормализации.

5.2.2. Преобразование ссылок

Для каждой ссылки URI (R) приведенный ниже псевдокод описывает преобразование R в целевой URI (T).

      -- Ссылка URI разбирается на пять компонент URI
      -- (R.scheme, R.authority, R.path, R.query, R.fragment) = parse(R);

      -- Нестрогий анализатор может игнорировать схему в ссылке,
      -- если она идентична схеме в базовом URI.
      --
      if ((not strict) and (R.scheme == Base.scheme)) then
         undefine(R.scheme);
      endif;

      if defined(R.scheme) then
         T.scheme    = R.scheme;
         T.authority = R.authority;
         T.path      = remove_dot_segments(R.path);
         T.query     = R.query;
      else
         if defined(R.authority) then
            T.authority = R.authority;
            T.path      = remove_dot_segments(R.path);
            T.query     = R.query;
         else
            if (R.path == "") then
               T.path = Base.path;
               if defined(R.query) then
                  T.query = R.query;
               else
                  T.query = Base.query;
               endif;
            else
               if (R.path starts-with "/") then
                  T.path = remove_dot_segments(R.path);
               else
                  T.path = merge(Base, R);12
                  T.path = remove_dot_segments(T.path);
               endif;
               T.query = R.query;
            endif;
            T.authority = Base.authority;
         endif;
         T.scheme = Base.scheme;
      endif;

      T.fragment = R.fragment;

5.2.3. Слияние путей

Приведенный выше псевдокод иллюстрирует процедуру «слияния» ссылки по относительному пути с путем из базового URI. Это достигается следующим образом:

  • если базовый URI имеет определенную компоненту authority и пустой путь или путь в базовом URI заканчивается символами «/..», возвращается строка, состоящая из базового пути, дополненного символом «/», которая затем объединяется с путем в ссылке,13

  • в остальных случаях возвращается строка, состоящая компоненты path в ссылке, добавленной в конец пути базового URI, из которого исключен последний сегмент (т. е., все символы после самого правого символа «/» или весь путь базового URI, если в нем нет символов «/»).

5.2.4. Удаление сегментов с точками

Псевдокод также включает процедуру «удаления сегментов с точками» для интерпретации и удаления сегментов «.» и «..» из пути в ссылке. Это делается после извлечения пути из ссылки (независимо от того, является ли путь относительным) для удаления всех неприемлемых или избыточных сегментов с точками до формирования целевого URI. Этот процесс можно реализовать множеством способов и ниже описан простой путь с двумя буферами для строк.

  1. Входной буфер инициализируется добавленными сейчас компонентами пути, а выходной — пустой строкой.

  2. Пока входной буфер не пуст, выполняется приведенный ниже цикл:

    1. если входной буфер начинается с префикса «../» или «./», этот префикс удаляется из буфера;

    2. если входной буфер начинается с префикса «/./» или «/.», где «.» представляет собой полный сегмент пути, этот префикс заменяется во входном буфере префиксом «/»;

    3. если входной буфер начинается с префикса «/../» или «/..», где «..» представляет собой полный сегмент пути, этот префикс заменяется во входном буфере префиксом «/», а из выходного буфера удаляется последний сегмент с предшествующим ему символом «/»;

    4. если входной буфер содержит только «.» или «..», он опустошается;

    5. первый сегмент пути из входного буфера переносится в конец выходного буфера с включением начального символа «/» (если он есть) и всеми последующими символами вплоть до следующего символа «/» (не включая его) или до конца входного буфера.

  3. Содержимое выходного буфера возвращается в качестве результата remove_dot_segments.

Отметим, что сегменты с точками предназначены для использования в ссылках URI, где нужно указать идентификатор относительно иерархии имен в базовом URI. Алгоритм remove_dot_segments учитывает эту иерархию, удаляя лишние сегменты с точками вместо их трактовки как ошибок или сохранения, ведущего к ошибочной интерпретации реализациями разыменования.

Ниже показано по шагам применение описанного алгоритма для двух примеров слияния путей.

Этап

Выходной буфер

Входной буфер

1

/a/b/c/./../../g

2E

/a
/b/c/./../../g

2E

/a/b
/c/./../../g

2E

/a/b/c
/./../../g

2B

/a/b/c
/../../g

2C

/a/b
/../g

2C

/a
/g

2E

/a/g

Этап

Выходной буфер

Входной буфер

1

mid/content=5/../6

2E

mid
/content=5/../6

2E

mid/content=5
/../6

2C

mid
/6

2E

mid/6

Некоторые приложения могут счесть более эффективной реализацию алгоритма remove_dot_segments с использованием двухсегментного стека вместо строк.

Примечание. Помните, что некоторые устаревшие реализации с ошибками могут сталкиваться с отказами при попытке выделить компоненту ссылки query из компоненты path для слияния базового и ссылочного путей, что приводит к проблемам совместимости для запросов с компонентой query, содержащей «/../» или «/./».

5.3. Сборка компонент

Разобранные компоненты URI могут быть скомпонованы заново для получения соответствующей строки ссылки URI. Ниже приведен псевдокод для такой сборки.

      result = ""

      if defined(scheme) then
         добавить scheme в конце result;
         добавить ":" в конце result;
      endif;

      if defined(authority) then
         добавить "//" в конце result;
         добавить authority в конце result;
      endif;

      добавить path в конце result;

      if defined(query) then
         добавить "?" в конце result;
         добавить query в конце result;
      endif;

      if defined(fragment) then
         добавить "#" в конце result;
         добавить fragment в конце result;
      endif;

      вернуть result;

Следует отметить, что мы стараемся сохранить различие между компонентами, которые не определены (это означает, что разделитель для компоненты не присутствует в ссылке), и пустыми компонентами (сепаратор для компоненты присутствует, но сразу за ним следует сепаратор другой компоненты или ссылка заканчивается).

5.4. Пример преобразования ссылки

В представлении с четко определенным базовым URI

      http://a/b/c/d;p?q

относительная преобразуется в целевой идентификатор URI, как показано в двух следующих параграфах.

5.4.1. Нормальные примеры

      "g:h"           =  "g:h"
      "g"             =  "http://a/b/c/g"
      "./g"           =  "http://a/b/c/g"
      "g/"            =  "http://a/b/c/g/"
      "/g"            =  "http://a/g"
      "//g"           =  "http://g"
      "?y"            =  "http://a/b/c/d;p?y"
      "g?y"           =  "http://a/b/c/g?y"
      "#s"            =  "http://a/b/c/d;p?q#s"
      "g#s"           =  "http://a/b/c/g#s"
      "g?y#s"         =  "http://a/b/c/g?y#s"
      ";x"            =  "http://a/b/c/;x"
      "g;x"           =  "http://a/b/c/g;x"
      "g;x?y#s"       =  "http://a/b/c/g;x?y#s"
      ""              =  "http://a/b/c/d;p?q"
      "."             =  "http://a/b/c/"
      "./"            =  "http://a/b/c/"
      ".."            =  "http://a/b/"
      "../"           =  "http://a/b/"
      "../g"          =  "http://a/b/g"
      "../.."         =  "http://a/"
      "../../"        =  "http://a/"
      "../../g"       =  "http://a/g"

5.4.2. Аномальные примеры

Хотя появление приведенных ниже аномальных случаев на практике не очевидно, всем анализаторам URI следует быть готовыми к таким аномалиям. Во всех приведенных ниже примерах используется та же база, что и раньше.

Анализаторы должны с осторожностью обрабатывать идентификаторы с числом сегментов «..» в ссылке с относительным путем, превышающим число уровней иерархии в пути базового URI. Отметим, что синтаксис «..» не может применяться для изменения компоненты authority в URI.

      "../../../g"    =  "http://a/../g"
      "../../../../g" =  "http://a/../../g"14

Анализаторы должны также удалять сегменты с точками «.» и «..», когда они являются полными компонентами пути, но не частью сегмента.

      "/./g"          =  "http://a/g"
      "/../g"         =  "http://a/g"
      "g."            =  "http://a/b/c/g."
      ".g"            =  "http://a/b/c/.g"
      "g.."           =  "http://a/b/c/g.."
      "..g"           =  "http://a/b/c/..g"

Менее очевидны слкчаи, когда в относительной ссылке используются ненужные или бессмысленные полные сегменты пути «.» и «..».

      "./../g"        =  "http://a/b/g"
      "./g/."         =  "http://a/b/c/g/"
      "g/./h"         =  "http://a/b/c/g/h"
      "g/../h"        =  "http://a/b/c/h"
      "g;x=1/./y"     =  "http://a/b/c/g;x=1/y"
      "g;x=1/../y"    =  "http://a/b/c/y"

Некоторые приложения сталкиваются с отказом при попытке отделить в ссылке запрос и/или фрагмент от компоненты path до слияния с базовым путем и удаления сегментов с точками. Эта ошибка встречается достаточно редко, поскольку типичное использование фрагментов никогда не включает символ иерархии (/), а компонента query обычно не применяется в относительных ссылках.

      "g?y/./x"       =  "http://a/b/c/g?y/./x"
      "g?y/../x"      =  "http://a/b/c/g?y/../x"
      "g#s/./x"       =  "http://a/b/c/g#s/./x"
      "g#s/../x"      =  "http://a/b/c/g#s/../x"

Некоторые анализаторы позволяют включать имя схему в относительные ссылки, Если оно совпадает с именем схемы в базовом URI. Это было признано «лезейкой» в предшествующих спецификациях частичных URI [RFC1630]. Следует избегать этого, но поддержка допускается в целях совместимости со старыми версиями.

      "http:g"        =  "http:g"         ; для строгого разбора
                      /  "http://a/b/c/g" ; для совместимости с ранними версиями

6. Нормализация и сравнение

Одной из наиболее распространенных операций с URI является простое сравнение — проверка эквивалентности двух URI без их использования для доступа к соответствующим ресурсам. Сравнение выполняется всякий раз при обращении к кэшу откликов, проверке браузером своей истории для подсвечивания ссылок или обработке анализатором XML тегов в пространстве имен. Поисковые и индексирующие машины зачастую используют расширенную нормализацию для сужения пространства поиска и снижения числа дублирующих операций при запросах и пространства для хранения откликов.

Сравнение URI выполняется с той или иной конкретной целью. Протоколы или реализации, сравнивающие URI с разными целями, зачастую по разному организованы для достижения компромисса в части прилагаемых для снижения числа идентификаторов-псевдонимов усилий. В этом разделе описаны разные методы, которые могут применяться для сравнения URI, компромиссы при выборе метода сравнения, а также приложения, использующие эти методы.

6.1. Эквивалентность

Поскольку URI служат для идентификации ресурсов, по-видимому два идентификатора следует считать эквивалентными, если они указывают на один и тот же ресурс. Однако такое определение эквивалентности не совсем практично, поскольку реализация не может сравнить два ресурса, пока у нее нет полной информации или контроля над ними. По этой причине определение эквивалентности разных URI основано на сравнении строк, возможно с добавлением неких правил, обеспечиваемых определением схемы URI. Для обозначения результата такого сравнения используются термины «разные» (different) и «эквивалентные» (equivalent), но может существовать множество зависимых от приложений вариантов эквивалентности.

Можно определить эквивалентность двух URI, однако сравнения строк не достаточно для того, чтобы утверждать, что два URI указывают на разные ресурсы. Например, владелец двух различающихся доменных имен может отнести тот или иной ресурс к обоим доменами, что приведет к наличию двух разных URI для одного ресурса. Следовательно, методы сравнения разрабатываются с учетом минимизации ложных различий при полном предотвращении ложных совпадений.

При проверке эквивалентности приложениям не следует напрямую сравнивать относительные ссылки, перед сравнением их следует преобразовать в целевые URI. При сравнении URI для выбора ил предотвращения сетевого действия (типа поиска представления), фрагменты следует исключать из сравнения.

6.2. Порядок сравнения

На практике для проверки эквивалентности URI применяется множество методов. Эти методы ранжируются по трудоемкости обработки и возможности разных расхождений. Как отмечено выше, полностью избежать ложных различий не удается, но снижение их числа значительно повышает трудоемкость и эффективно не для всех приложений.

Если представить ранжирование методов в форме лестницы, последующее обсуждение будет подъемом, начинающимся с простейших методов, дающих сравнительно высокую вероятность ложных различий в направлении методов с большими вычислительными издержками и меньшим риском получить ложные различия.

6.2.1. Простое сравнение строк

Если текстовые строки двух сравниваемых URI идентичны, можно безопасно считать эти URI эквивалентными. Проверка этого типа вносит очень незначительные вычислительные издержки и широко применяется в разных типах приложений (особенно при разборе).

При проверке эквивалентности строк требуются некоторые меры предосторожности. Эту процедуру часто называют побитовым (bit-for-bit) или побайтовым (byte-for-byte) сравнением, что может вводить в заблуждение. Проверка строк на совпадение обычно выполняется в виде попарного сравнеия символов разных строк, начиная с первого и до конца строки или обнаружения различия.

Для такого сравнения символов требуется, чтобы каждая пара символов была представлена в сравнимой форме. Например, если один URI хранится в виде массива байтов с кодировкой EBCDIC, а другой в объекте Java String (UTF-16), побитовое сравнение даст расхождение сразу же. Лучше говорить о посимвольной эквивалентности, а не побайтовой или побитовой. С практической точки зрения посимвольное сравнение следует выполнять путем сравнения кодов символов после перевода обеих строк в одну кодировку.

Ложные различия связаны с созданием и использованием псевдонимов URI. Ненужные псевдонимы можно частично устранить независимо от используемого метода сравнения путем представления ссылок URI в нормализованной форме (т. е., идентичной той форме, которая будет получаться на выходе описанной ниже нормализации).

Протоколы и форматы данных часто ограничиваются в сравнении URI простым сравнением символьных строк, исходя из допущения о том, что люди и программные реализации заинтересованы в том, чтобы предоставлять согласованные ссылки URI или, по крайней мере, делать их достаточно согласованными для того, чтобы нормализация ничего не давала в смысле повышения эффективности.

6.2.2. Нормализация на основе синтаксиса

Для снижения вероятности ложных расхождений реализации могут использовать логику, представленную в этой спецификации. Эта обработка требует несколько больших издержек по сравнению с посимвольным сравнением строк. Например, приложение, использующее такой подход, может считать приведенные ниже два URI эквивалентными.

      example://a/b/c/%7Bfoo%7D
      eXAMPLE://a/./b/../b/%63/%7bfoo%7d

Пользовательские агенты Web (например, браузеры) обычно используют этот тип нормализации URI при определении доступности кэшированного отклика. Основанная на синтаксисе нормализация включает такие методы, как нормализация регистра символов и %-представления, а также удаление сегментов с точками.

6.2.2.1. Нормализация регистра

Для всех URI для шестнадцатеричных цифр в триплетах %-кодирования не принимается во внимание (например, %3a и %3A), поэтому их следует нормализовать путем преобразования в верхний регистр символов A-F.

При использовании в URI компонент базового синтаксиса всегда применяются правила эквивалентности синтаксических компонент — в именах схем и хостов регистр символов не имеет значения, поэтому их следует нормализовать путем перевода в нижний регистр. Например, URI <HTTP://www.EXAMPLE.com/> является эквивалентом <http://www.example.com/>. Для других компонент базового синтаксиса считается, что регистр символов имеет значение, если в определении схемы явно не указано иное (см. параграф 6.2.3).

6.2.2.2. Нормализация %-кодирования

Механизм %-кодирования (параграф 2.1) часто служит причиной того, что идентичные URI трактуются, как разные. Кроме описанных выше различий в регистре символов некоторые создатели URI используют %-кодирование без необходимости. Такие URI следует нормализовать путем декодирования октетов с %-представлением, которые соответствуют незарезервированным символам, как описано в параграфе 2.3.

6.2.2.3. Нормализация сегмента пути

Полные сегменты пути «.» и «..» предназначены для использования только в относительных ссылках (параграф 4.1) и удаляются в процессе преобразования ссылки (параграф 5.2). Однако некоторые развернутые реализации некорректно предполагают, что преобразование ссылок не обязательно, если ссылка уже является URI и не удаляют сегменты с точками из путей, которые не являются относительными. Нормализаторам URI следует удалять сегменты с точками, используя описанный в параграфе 5.2.4 алгоритм remove_dot_segments.

6.2.3. Нормализация в зависимости от схемы

Синтаксис и семантика URI меняются от схемы к схеме и описаны в спецификации для каждой схемы. Разработчики могут применять определяемые схемой правила в качестве дополнительной обработки с целью снижения вероятности ложных различий. Например, поскольку схема http использует компоненту authority с принятым по умолчанию значением номера порта 80 и указывает, что пустой путь эквивалентен «/», приведенные ниже URI будут эквивалентны.

      http://example.com
      http://example.com/
      http://example.com:/
      http://example.com:80/

В общем случае URI, использующий базовый синтаксис для authority с пустым путем, следует нормализовать с путем «/». Аналогично, явное указание :port с пустым или принятым по умолчанию номером порта, эквивалентно отсутствию порта и разделителя «:», поэтому его следует удалять при нормализации на основании схемы. Например, второй идентификатор в приведенном выше примере является обычной формой URI для схемы http.

Другой ситуацией, когда нормализация зависит от схемы, является обработка пустой компоненты authority или пустой субкомпоненты host. Для многих схем в спецификациях указано, что пустые значения этих компонент считаются ошибкой, а в других пустые значений считают эквивалентом localhost или хоста конечного пользователя. Когда в схеме определено используемое по умолчанию значение authority и желательна ссылка URI на это значение, ссылку следует нормализовать, указав пустое значение authority в целях единообразия, краткости и поддержки других языков. Однако, если не пуста субкомпонента userinfo или port, хост должен задаваться явно, даже для используемого по умолчанию.

При нормализации не следует удалять разграничители пустых компонент, если это не задано в спецификации схемы. Например, URI «http://example.com/?» нельзя считать эквивалентом любому из приведенных выше. Аналогично, наличие или отсутствие разграничителей внутри субкомпоненты userinfo обычно важно для ее интерпретации. К фрагментам нормализация на основе схемы не применима — два URI, различающиеся лишь наличием в одном суффикса #, считаются разными независимо от схемы.

Некоторые схемы определяют дополнительные субкомпоненты, которые состоят из регистронезависимых данных, и это неявно позволяет нормализаторам преобразовывать эти данные к одном регистру (например, нижнему). Например, схемы URI, которые определяют субкомпоненту пути для включения имени хоста Internet (такие, как схема mailto), предполагают, что регистр символов в субкомпоненте не имеет значения и к ней может применяться нормализация регистра (например, mailto:Joe@Example.COM эквивалентно mailto:Joe@example.com, хотя базовый синтаксис предполагает учет регистра символов в компоненте path).

Возможны и другие, специфические для схемы варианты нормализации.

6.2.4. Нормализация в зависимости от протокола

Значительные усилия по снижению влияния ложный различий зачастую не приемлемы для систем индексации web и поэтому они пользуются более агрессивным сравнением URI. Например, встретив URI вида

      http://example.com/data

с перенаправлением на URI, отличающийся только символом / в конце

      http://example.com/data/

они в будущем станут считать эти идентификаторы эквивалентными. Такой подход приемлем лишь в тех случаях, когда эквивалентность четко демонстрируется как результатом доступа к ресурсу, так и общими соглашениями механизма разыменования схемы (в этом случае использование перенаправления HTTP служит для предотвращения проблем с относительными ссылками).

7. Вопросы безопасности

Сами по себе URI не представляют угроз безопасности. Однако, поскольку URI часто используются для предоставления краткого набора инструкций для доступа к сетевым ресурсам, следует с осторожностью интерпретировать данные в URI, чтобы предотвратить нежелательный доступ к данным и избежать включения данных, которые не следует представлять в открытом виде.

7.1. Надежность и согласованность

Нет никакой гарантии, что после использования URI для извлечения данных такая же информация будет получена и в будущем при обращении по тому же URI. Нет даже гарантии того, что информация, получаемая с помощью данного URI, будет похожа на ту, которая была получена в прошлый раз. Синтаксис URI не вносит ограничений для схем или организаций по использованию или поддержке их пространства имен. Такие гарантии могут быть получены лишь от лиц, контролирующих пространство имен и соответствующие ресурсы. Конкретная схема URI может определять дополнительную семантику (например, постоянство имен), если такая семантика требуется для всех «органов именования» в данной схеме.

7.2. Злонамеренные конструкции

Можно создать такой URI, что попытка выполнить кажущуюся безопасной и идемпотентной операцию (например, извлечение представления) будет фактически приводить к выполнению на удаленной стороне вредоносной операции. Такие опасные URI обычно создаются путем указания номера порта, отличающегося от того, который зарезервирован для соответствующего протокола. Клиент помимо своей воли соединяется с сайтом, где работает другая протокольная служба и данные в URI содержат инструкции, которые при интерпретации этим другим протоколом вызывают неожиданное воздействие. Распространенным примером такого злонамеренного применения является использование основанной на протоколе схемы с номером порта 25, для обманной отправки программой непредусмотренного сообщения через сервер SMTP.

Приложениям следует предотвращать разыменование URI, в которых указан номер порта TCP, отличающийся от общепринятого (из диапазона 0 — 1023), если протокол, который будет применяться для разыменования URI, совместим с протоколом, ожидаемом на общепринятом порту. Хотя IANA поддерживает реестр общепринятых портов, приложениям следует давать пользователю возможность настройки своих ограничений, чтобы это не препятствовало развертыванию новых приложений.

Когда URI включает октеты %представления, которые соответствуют символам разграничения для данного протокола преобразования или разыменования (например, CR и LF для протокола TELNET), такое %-представление недопустимо декодировать до прохождения через этот протокол. Передача %-кодирования, которое может нарушать протокол, менее опасна, нежели интерпретация декодированных октетов, как дополнительных операций или параметров, которые могут приводить к неожиданным и, возможно, небезопасным действиям на удаленной стороне.

7.3. Внутренняя перекодировка

При разыменовании URI разбор зачастую выполняется как пользовательским агентом, так и одним или несколькими серверами. Например, в HTTP типичный пользовательский агент будет разбирать URI на пять основных компонент, обращаться к указанному authority серверу и передавать ему данные в компонентах authority, path и query. Типичный сервер будет принимать эту информацию, разбивать путь на сегменты, а query — на пары key/value и после этого выполнять определяемую приложением обработку для отклика на запрос. В результате общей проблемой безопасности для реализаций серверов, которые обрабатывают URI целиком или по отдельным компонентам, является корректная интерпретация октетов данных, представленных символами и %-кодами в данном URI.

Октеты с %-представлением должны декодироваться в некой точке процесса разыменования. Приложение должно разделить URI на компоненты и субкомпоненты до декодирования октетов, поскольку в противном случае декодированные октеты могут быть ошибочно восприняты в качестве разделителей. Проверки безопасности данных в URI следует выполнять после декодирования октетов. Однако следует отметить, что для кодирования %00 (NUL) может потребоваться специальная обработка и такие символы следует отвергать, если приложение не предполагает получение необработанных (raw) данных внутри компонент идентификатора.

Особую осторожность следует проявлять в случаях, когда процесс интерпретации пути URI включает использование файловой системы или связанных с ней функций. Файловые системы обычно используют особую трактовку специальных символов типа «/», «\», «:», «[« и «]» и специальных имен устройств типа «.», «..», «…», «aux», «lpt» и т. п. В некоторых случаях обычная проверка существования такого имени будет приводить к паузе в работе операционной системы или ненужным вызовам системных функций, что может создавать существенные угрозы в поане отказа служб или непредусмотренного обмена данными. В данной спецификации невозможно перечислить все такие значимые символы и имена устройств. Разработчикам следует определиться с зарезервированными именами и символами для устройств хранения, которые могут быть подключены к их приложениям и соответствующим образом ограничить использование данных, получаемых из компонент URI.

7.4. Редкие форматы адресов IP

Хотя синтаксис URI для IPv4address разрешает использовать только десятичное представление адресов IPv4 с разделением точками, многие реализации, обрабатывающие URI, используют функции своей операционной системы (например, gethostbyname() и inet_aton()) для преобразования символьной строки в реальный адрес IP. К сожалению такие функции зачастую позволяют обрабатывать значительно более широкий набор форматов, нежели указано в параграфе 3.2.2.

Например, многие реализации разрешают применять адреса в форме трех разделенных точками чисел, в котором последняя часть является 16-битовым значением, определяющим два правых байта сетевого адреса (например, сеть класса B). Аналогично форма из двух разделенных точками чисел интерпретируется, как 24 бита, определяющие три правых байта сетевого адреса (класс A), а одно число (без точки) интерпретируется, как 32-битовое значение, указывающее весь адрес. В дополнение к этой путанице некоторые реализации позволяют интерпретировать каждую из разделенных точками частей, как десятичное, восьмеричное или шестнадцатеричное значение в соответствии с принятыми в языке C обозначениями (0x или 0X в начале указывает шестнадцатеричное значение, 0 — восьмеричное, остальные цифры- десятичное).

Эти дополнительные форматы адресов IP не разрешается использовать в синтаксисе URI по причине их разной интерпретации на разных платформах. Однако могут возникать проблемы безопасности, если приложение предпримет попытку фильтровать доступ к ресурсам по адресам IP в форме символьных строк. Если фильтрация нужна, символьное представление адресов следует сначала преобразовать в численное и выполнять фильтрацию по числовым значениям, а не по префиксам или суффиксам символьного представления.

7.5. Конфиденциальная информация

Создателям URI не следует выпускать идентификаторы, включающие имя пользователя или пароль, которые должны держаться в секрете. Текст URI зачастую отображается в браузерах, сохраняется в открытой форме в закладках и записывается в протокольные файлы пользовательского агента и промежуточных приложений (прокси). Включение паролей в компоненту userinfo отменено и его следует трактовать, как ошибку (или просто игнорировать), за исключением тех редких случаев, когда параметр password осознанно сделан открытым.

7.6. Семантические атаки

Поскольку субкомпонента userinfo применяется редко и указывается перед host в компоненте authority, она может служить для создания URI, предназначенных для обмана пользователя (человека), показывая один (доверенный) орган именования (authority) и скрывая «шумом» другое значение authority. Например

      ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm

может убедить пользователя в том, что идентификатор указывает хост cnn.example.com, тогда как реально это будет 10.0.0.1. Отметим, что такие вводящие в заблуждение субкомпоненты userinfo на практике могут быть значительно длиннее, нежели в приведенном примере.

Обманные URI (типа показанного выше) служат для атак на представление пользователей о значении URI, а не на сами программы. Пользовательские агент могут снизить шансы таких атак, различая компоненты URI при отображении (например, выводя userinfo другим цветом), но это не является панацеей. Дополнительная информация о семантических атаках с использованием URI приведена в работе [Siedzik].

8. Согласование с IANA

Имена схем URI, определенные как <scheme> в параграфе 3.1, образуют пространство зарегистрированных имен, поддерживаемое IANA в соответствии с процедурами [BCP35]. Данный документ не предъявляет каких-либо требований к IANA.

9. Благодарности

Эта спецификация создана на основе RFC 2396 [RFC2396], RFC 1808 [RFC1808] и RFC 1738 [RFC1738], поэтому указанные там благодарности применимы и здесь. It also incorporates the update (with corrections) for IPv6 literals in the host syntax, as defined by Robert M. Hinden, Brian E. Carpenter, and Larry Masinter in [RFC2732]. In addition, contributions by Gisle Aas, Reese Anschultz, Daniel Barclay, Tim Bray, Mike Brown, Rob Cameron, Jeremy Carroll, Dan Connolly, Adam M. Costello, John Cowan, Jason Diamond, Martin Duerst, Stefan Eissing, Clive D.W. Feather, Al Gilman, Tony Hammond, Elliotte Harold, Pat Hayes, Henry Holtzman, Ian B. Jacobs, Michael Kay, John C. Klensin, Graham Klyne, Dan Kohn, Bruce Lilly, Andrew Main, Dave McAlpin, Ira McDonald, Michael Mealling, Ray Merkert, Stephen Pollei, Julian Reschke, Tomas Rokicki, Miles Sabin, Kai Schaetzl, Mark Thomson, Ronald Tschalaer, Norm Walsh, Marc Warne, Stuart Williams, and Henry Zongaro are gratefully acknowledged.

10. Литература

10.1. Нормативные документы

[ASCII] American National Standards Institute, «Coded Character Set — 7-bit American Standard Code for Information Interchange», ANSI X3.4, 1986.

[RFC2234] Crocker, D. and P. Overell, «Augmented BNF for Syntax Specifications: ABNF», RFC 2234, November 1997.

[STD63] Yergeau, F., «UTF-8, a transformation format of ISO 10646», STD 63, RFC 3629, November 2003.

[UCS] International Organization for Standardization, «Information Technology — Universal Multiple-Octet Coded Character Set (UCS)», ISO/IEC 10646:2003, December 2003.

10.2. Дополнительная литература

[BCP19] Freed, N. and J. Postel, «IANA Charset Registration Procedures», BCP 19, RFC 2978, October 2000.

[BCP35] Petke, R. and I. King, «Registration Procedures for URL Scheme Names», BCP 35, RFC 2717, November 1999.

[RFC0952] Harrenstien, K., Stahl, M., and E. Feinler, «DoD Internet host table specification», RFC 952, October 1985.

[RFC1034] Mockapetris, P., «Domain names — concepts and facilities», STD 13, RFC 1034, November 1987.

[RFC1123] Braden, R., «Requirements for Internet Hosts — Application and Support», STD 3, RFC 1123, October 1989.

[RFC1535] Gavron, E., «A Security Problem and Proposed Correction With Widely Deployed DNS Software», RFC 1535, October 1993.

[RFC1630] Berners-Lee, T., «Universal Resource Identifiers in WWW: A Unifying Syntax for the Expression of Names and Addresses of Objects on the Network as used in the World-Wide Web», RFC 1630, June 1994.

[RFC1736] Kunze, J., «Functional Recommendations for Internet Resource Locators», RFC 1736, February 1995.

[RFC1737] Sollins, K. and L. Masinter, «Functional Requirements for Uniform Resource Names», RFC 1737, December 1994.

[RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, «Uniform Resource Locators (URL)», RFC 1738, December 1994.

[RFC1808] Fielding, R., «Relative Uniform Resource Locators», RFC 1808, June 1995.

[RFC2046] Freed, N. and N. Borenstein, «Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types», RFC 2046, November 1996.

[RFC2141] Moats, R., «URN Syntax», RFC 2141, May 1997.

[RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, «Uniform Resource Identifiers (URI): Generic Syntax», RFC 2396, August 1998.

[RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D. Jensen, «HTTP Extensions for Distributed Authoring – WEBDAV», RFC 2518, February 1999.

[RFC2557] Palme, J., Hopmann, A., and N. Shelness, «MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)», RFC 2557, March 1999.

[RFC2718] Masinter, L., Alvestrand, H., Zigmond, D., and R. Petke, «Guidelines for new URL Schemes», RFC 271815, November 1999.

[RFC2732] Hinden, R., Carpenter, B., and L. Masinter, «Format for Literal IPv6 Addresses in URL’s», RFC 2732, December 1999.

[RFC3305] Mealling, M. and R. Denenberg, «Report from the Joint W3C/IETF URI Planning Interest Group: Uniform Resource Identifiers (URIs), URLs, and Uniform Resource Names (URNs): Clarifications and Recommendations», RFC 3305, August 2002.

[RFC3490] Faltstrom, P., Hoffman, P., and A. Costello, «Internationalizing Domain Names in Applications (IDNA)», RFC 3490, March 2003.

[RFC3513] Hinden, R. and S. Deering, «Internet Protocol Version 6 (IPv6) Addressing Architecture», RFC 351316, April 2003.

[Siedzik] Siedzik, R., «Semantic Attacks: What’s in a URL?», April 2001, <http://www.giac.org/practical/gsec/Richard_Siedzik_GSEC.pdf>.

Приложение A. ABNF для URI

   URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

   hier-part     = "//" authority path-abempty
                 / path-absolute
                 / path-rootless
                 / path-empty

   URI-reference = URI / relative-ref

   absolute-URI  = scheme ":" hier-part [ "?" query ]

   relative-ref  = relative-part [ "?" query ] [ "#" fragment ]

   relative-part = "//" authority path-abempty
                 / path-absolute
                 / path-noscheme
                 / path-empty

   scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

   authority     = [ userinfo "@" ] host [ ":" port ]
   userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
   host          = IP-literal / IPv4address / reg-name
   port          = *DIGIT

   IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"

   IPvFuture     = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )

   IPv6address   =                            6( h16 ":" ) ls32
                 /                       "::" 5( h16 ":" ) ls32
                 / [               h16 ] "::" 4( h16 ":" ) ls32
                 / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
                 / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
                 / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
                 / [ *4( h16 ":" ) h16 ] "::"              ls32
                 / [ *5( h16 ":" ) h16 ] "::"              h16
                 / [ *6( h16 ":" ) h16 ] "::"

   h16           = 1*4HEXDIG
   ls32          = ( h16 ":" h16 ) / IPv4address
   IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet

   dec-octet     = DIGIT                 ; 0-9
                 / %x31-39 DIGIT         ; 10-99
                 / "1" 2DIGIT            ; 100-199
                 / "2" %x30-34 DIGIT     ; 200-249
                 / "25" %x30-35          ; 250-255

   reg-name      = *( unreserved / pct-encoded / sub-delims )

   path          = path-abempty    ; начинается с / или пуст
                 / path-absolute   ; начинается с /, но не с //
                 / path-noscheme   ; начинается не с сегмента с двоеточием
                 / path-rootless   ; начинается с сегмента
                 / path-empty      ; 0 символов

   path-abempty  = *( "/" segment )
   path-absolute = "/" [ segment-nz *( "/" segment ) ]
   path-noscheme = segment-nz-nc *( "/" segment )
   path-rootless = segment-nz *( "/" segment )
   path-empty    = 0<pchar>

   segment       = *pchar
   segment-nz    = 1*pchar
   segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
                 ; non-zero-length segment without any colon ":"

   pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"

   query         = *( pchar / "/" / "?" )

   fragment      = *( pchar / "/" / "?" )

   pct-encoded   = "%" HEXDIG HEXDIG

   unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
   reserved      = gen-delims / sub-delims
   gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
   sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
                 / "*" / "+" / "," / ";" / "="

Приложение B. Разбор ссылок URI с регулярными выражениями

Алгоритм выбора первого подходящего (first-match-wins) идентичен «всеядному» методу устранения неоднозначностей, применемому в регулярных выражениях POSIX, поэтому естественным и комфортным будет использование регулярных выражений для анализа компонент URI.

В следующей строке приведено регулярное выражение для разбора корректно сформированной ссылки URI на компоненты.

     /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/17
       12             3    4           5       6  7        8 9

Числа во второй строке приведены только для удобства понимания — они указывают «опорные точки» для каждого субвыражения (в парных скобках). Значение, соответствующее субвыражению <n> обозначается $<n>. Например, соответствие приведенному выше выражению для

      http://www.ics.uci.edu/pub/ietf/uri/#Related

будут давать следующие субвыражения:

      $1 = http:
      $2 = http
      $3 = //www.ics.uci.edu
      $4 = www.ics.uci.edu
      $5 = /pub/ietf/uri/
      $6 = <не определено>
      $7 = <не определено>
      $8 = #Related
      $9 = Related

где <не определено> говорит об отсутствии субкомпонеты (например, query в приведенном выше примере). Следовательно, мы можем определить значения пяти компонент как

      scheme    = $2
      authority = $4
      path      = $5
      query     = $7
      fragment  = $9

Выполняя операции в обратном направлении, можно восстановить ссылку URI по компонентам с использованием алгоритма, описанного в параграфе 5.3.

Приложение C. Ограничители URI в контексте

URI часто передаются через форматы, которые не обеспечивают четкого контекста для их интерпретации. Например, достаточно часто URI включают в обычный текст — примерами могут служить сообщения электронной почты, новости USENET или печатные документы. В таких случаях важна возможность отделить URI от остального текста и, в частности, от знаков препинания, которые могут быть ошибочно восприняты как часть URI.

На практике URI зачастую обозначают тем или иным способом, но чаще для этого применяются двойные кавычки «http://example.com/», угловые скобки или просто пробелы

      http://example.com/

Используемые в качестве ограничителей символы не являются частью URI.

В некоторых случаях в URI могут добавляться пробельные символы (пробел, перевод строки, табуляция и т. п.) для разбиения длинных URI на несколько строк. Эти пробельные символы следует игнорировать при извлечении URI.

Не следует добавлять пробельные символы после знака дефиса («-«). Это связано с тем, что некоторые наборные машины и принтеры могут (ошибочно) добавлять дефис в конце строки при ее разрыве, поэтому интерпретаторам URI, сталкивающимся с переводом строки сразу после символа дефиса, следует игнорировать все пробельные символы «вокруг» перевода строки, а также удостовериться, является ли дефис частью URI.

Использование угловых скобок <> для каждого URI настоятельно рекомендуется в качестве ограничителей для ссылок, включающих в себя пробельные символы.

Префикс «URL:» (с пробелом или без пробела в конце) рекомендовали раньше для того, чтобы отличить URI от другого текста в скобках, хотя это не получило широкого распространения и в настоящее время такая рекомендация не применяется.

Для отказоустойчивости приложениям, принимающим набранные пользователем URI, следует пытаться распознать и вырезать ограничители и вложенные пробельные символы.

Например, приведенный ниже текст

      Да, Джим, я нашел это по ссылке "http://www.w3.org/Addressing/",
      но, возможно, это доступно и по ссылке <ftp://foo.example.
      com/rfc/>. Обратите внимание на предупрежденеи <http://www.ics.uci.edu/pub/
      ietf/uri/historical.html#WARNING>.

содержит три ссылки URI

      http://www.w3.org/Addressing/
      ftp://foo.example.com/rfc/
      http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING

Приложение D. Отличия от RFC 2396

D.1. Дополнения

Введено правило ABNF для URI с целью соответствия общему применению термина «абсолютный URI с необязательным фрагментом».

Литералы IPv6 (и более поздние) были добавлены в список возможных идентификаторов для субкомпоненты host в authority, как описано в [RFC2732], с добавлением скобок [ ] в набор зарезервированных символов и флага версии для возможных будущих литералов IP. Квадратные скобки указаны в качестве зарезервированных символов для компоненты authority и не допускается их использование иначе, как ограничителей литерала IP в субкомпонентах host. Для того, чтобы внести это изменение без смены имеющегося технического определения компонент path, query и fragment, правила для которых были переопределены с прямым указанием разрешенных символов.

Поскольку определение литеральных адресов IPv6 из [RFC2732] было изменено в [RFC3513] определением, не содержащим описания ABNF для IPv6address, было создано новое правило ABNF для IPv6address, которое соответствует текстовому представлению, определенному в параграфе 2.2 [RFC3513]. Аналогично было изменено определение IPv4address для ограничения значений десятичного представления каждого октета диапазоном 0-255.

Раздел 6, посвященный нормализации и сравнению URI, был переписан полностью и расширен с использованием информации от Tim Bray и обсуждений в группе W3C Technical Architecture.

D.2. Изменения

Специальный синтаксис BNF RFC 2396 был заменен ABNF [RFC2234]. Это потребовало замены всех имен правил с символами подчеркивания именами, с символом дефиса. Кроме того, было исключено и упрощено множество правил, чтобы сделать общую грамматику более понятной. Спецификации, ссылающиеся на устаревшие грамматические правила можно понять, выполнив замены, указанные в приведенной ниже таблице.

Устаревшее правило

Трансляция

absoluteURI
absolute-URI
relativeURI
relative-part [ "?" query ]
hier_part
( "//" authority path-abempty / path-absolute ) [ "?" query ]
opaque_part
path-rootless [ "?" query ]
net_path
"//" authority path-abempty
abs_path
path-absolute
rel_path
path-rootless
rel_segment
segment-nz-nc
reg_name
reg-name
server
authority
hostport
host [ ":" port ]
hostname
reg-name
path_segments
path-abempty
param
*<pchar excluding ";">
uric
unreserved / pct-encoded / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," / "/"
uric_no_slash
unreserved / pct-encoded / ";" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / "," / "/"
mark
"-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")"
escaped
pct-encoded
hex
HEXDIG
alphanum
ALPHA / DIGIT

Использование приведенный в таблице устаревших правил для определения синтаксиса конкретных схем не допускается.

Раздел 2, посвященный символам, был переписан, чтобы объяснить, какие символы, когда и по каким причинам были зарезервированы, даже если эти символа не применяются в базовом синтаксисе в качестве разделителей. Символы, которые обычно не безопасны для декодирования, включая восклицательный знак, (!), звездочку (*), одинарные кавычки (‘) а также открывающие и закрывающие скобки (( и )) включены в число зарезервированных для прояснения различия между зарезервированными и незарезервированными символами ответа на наиболее частые вопросы разработчиков схем. Аналогично, был переписан раздел, посвященных %-кодированию и нормализаторы URI получили право декодировать любые %-представления, соответствующие незарезервированным символам. В общем случае термины escaped и unescaped были заменены на %-кодирование и декодирование, соответственно, для устранения путаницы с другими вариантами escape-механизмов.

ABNF для URI и ссылок URI был переработан с целью повышения уровня дружественности к анализаторам LALR и упрощения. В результате была удалена схематическая форма описания синтаксиса вместе с правилами uric, uric_no_slash, opaque_part, net_path, abs_path, rel_path, path_segments, rel_segment и mark. Все упоминания «непрозрачных» (opaque) URI были заменены более качественными описаниями, как компоненты пути могут быть непрозрачными для иерархии. Правило relativeURI было заменено на relative-ref для предотвращения ненужной путаницы с в части принадлежности к подмножеству URI. Неоднозначность при разборе ссылок URI, как URI или relative-ref с двоеточием в первом сегменте была устранена за счет использования пяти раздельных правил соответствия пути.

Идентификатор фрагмента был возвращен в раздел компонент базового синтаксиса для правил URI и relative-ref, хотя по прежнему исключается из absolute-URI. Знак номера (#) был возвращен в набор зарезервированных символов в результате возвращения синтаксиса фрагментов.

Представление ABNF было скорректировано для того, чтобы разрешить пустые компоненты пути. Это разрешает также absolute-URI, не содержащие ничего после «scheme:», как уже используется на практике в пространстве имен «dav:» [RFC2518] и схеме «about:», используемой внутри себя многими реализациями браузеров WWW. Неоднозначность границы между authority и path была устранена за счет использования пяти раздельных правил соответствия для пути.

Управляющие именованием на основе реестров, использующие базовый синтаксис, включены в правило для хоста. Это изменение позволяет современным реализациям, где любое представленное имя просто передается механизму преобразования имен, соответствовать данной спецификации, а также отменяет необходимость повторной спецификации здесь форматов имен DNS. Кроме того, это позволяет включать в компоненту host октеты %-представления, которые нужны для доменных имен на других языках, включаемых в URI, чтобы те могли обрабатываться в естественной для языка кодировке символов на прикладных уровнях выше уровня обработки URI и передаваться в библиотеку IDNA, как зарегистрированные имена с кодировкой символов UTF-8. Правила server, hostport, hostname, domainlabel, toplabel и alphanum были удалены из спецификации.

Алгоритм преобразования относительных ссылок [RFC2396] был переписан в данной версии в целях большей ясности и исправления перечисленных ниже ошибок.

  • [RFC2396], параграф 5.2, п. 6a не принимал во внимание базовый URI без path.

  • Восстановлено поведение [RFC1808] — в тех случаях, когда ссылка содержит пустой путь и присутствует компонента query, целевой URI наследует компоненту path тз базового URI.

  • Определение того, ссылается ли URI на тот же документ, было отделено от разбора URI, что позволило упростить интерфейс обработки URI в приложениях за счет возможности использования внутренней архитектуры развернутых реализаций обработки URI. Определение сейчас основывается на сравнении базового URI после преобразования ссылки в абсолютную, а не по формату самой ссылки. Это изменение может приводить к увеличению числа ссылок на тот же документ в соответствии с данной спецификацией по сравнению с RFC 2396, особенно в случаях применения нормализации для снижения числа псевдонимов. Однако это не изменит состояния существующих ссылок на тот же документ.

  • Процедура слияния пути разделена на две — собственно слияние для описания комбинации пути базового URI с путем относительной ссылки и remove_dot_segments для описания процедуры удаления специальных сегментов «.» и «..» из композитного пути. Алгоритм удаления сегментов с точками remove_dot_segments сейчас применяется для всех путей в ссылках URI с целью обеспечения однотипных реализаций и повышения производительности нормализации URI на практике. Это изменение влияет лишь на разбор аномальных ссылок и ссылок с той же схемой, где базовый URI имеет неиерархический путь.

Предметный указатель

Исключен в переводе.

Адреса авторов

Tim Berners-Lee

World Wide Web Consortium

Massachusetts Institute of Technology

77 Massachusetts Avenue

Cambridge, MA 02139

USA

Phone: +1-617-253-5702

Fax: +1-617-258-5999

EMail: timbl@w3.org

URI: http://www.w3.org/People/Berners-Lee/

Roy T. Fielding

Day Software

5251 California Ave., Suite 110

Irvine, CA 92617

USA

Phone: +1-949-679-2960

Fax: +1-949-679-2972

EMail: fielding@gbiv.com

URI: http://roy.gbiv.com/

Larry Masinter

Adobe Systems Incorporated

345 Park Ave

San Jose, CA 95110

USA

Phone: +1-408-536-3024

EMail: LMM@acm.org

URI: http://larry.masinter.net/


Перевод на русский язык

Николай Малых

nmalykh@gmail.com

Полное заявление авторских прав

Copyright (C) The Internet Society (2005).

This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an «AS IS» basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Интеллектуальная собственность

The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF’s procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79.

Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.

Подтверждение

Финансирование функций RFC Editor обеспечено Internet Society.


1Uniform Resource Identifier.

  1. 2World Wide Web — «всемирная паутина».

3Uniform Resource Locator — унифицированный локатор ресурса.

4Uniform Resource Name — унифицированное имя ресурса.

5Augmented Backus-Naur Form.

6Universal Character Set — универсальный набор символов.

7Символ À. Прим. перев.

8Японский иероглиф . Прим. перев.

9Domain Name System — система доменных имен.

10В оригинале была допущена ошибка. См. https://www.rfc-editor.org/errata_search.php?eid=4942. Прим. перев.

11В оригинале была допущена ошибка. См. https://www.rfc-editor.org/errata_search.php?eid=2033. Прим. перев.

12В оригинале была допущена ошибка. См. https://www.rfc-editor.org/errata_search.php?eid=2933. Прим. перев.

13В оригинале была допущена ошибка. См. https://www.rfc-editor.org/errata_search.php?eid=4789. Прим. перев.

14В оригинале была допущена ошибка. См. https://www.rfc-editor.org/errata_search.php?eid=4547. Прим. перев.

15Документ заменен RFC 4395, а тот — RFC 7595. Прим. перев.

16Документ заменен RFC 4291. Прим. перев.

17В оригинале была допущена ошибка. См. https://www.rfc-editor.org/errata_search.php?eid=2624. Прим. перев.




RFC 3947 Negotiation of NAT-Traversal in the IKE

Network Working Group                                         T. Kivinen
Request for Comments: 3947                                       SafeNet
Category: Standards Track                                     B. Swander
                                                               Microsoft
                                                             A. Huttunen
                                                    F-Secure Corporation
                                                                V. Volpe
                                                           Cisco Systems
                                                            January 2005

Работа IKE через трансляторы NAT

Negotiation of NAT-Traversal in the IKE

 PDF

Статус документа

Этот документ содержит спецификацию проекта стандартного протокола Internet и служит приглашением к дискуссии в целях развития протокола. Текущее состояние стандартизации и статус протокола можно узнать из документа Internet Official Protocol Standards (STD 1). Документ может распространяться свободно.

Авторские права

Copyright (C) The Internet Society (2005).

Тезисы

Этот документ описывает способы обнаружения трансляторов сетевых адресов (NAT1) между хостами IPsec и согласования применения инкапсуляции в UDP пакетов IPsec, передаваемых через NAT при обмене ключами (IKE2).

Оглавление

Исключено в версии HTML.

1. Введение

Этот документ состоит из двух частей. Первая часть описывает, что требуется сделать в фазе 1 IKE (Phase 1) для работы через трансляторы сетевых адресов (NAT-Traversal), включая обнаружение поддержки NAT-Traversal на другой стороне и обнаружения устройств NAT между партнерами.

Во второй части описано использование инкапсулированных в UDP пакетов IPsec в ускоренном режиме3 IKE. Рассматриваются также способы передачи партнеру исходных адресов отправителя и получателя, если они требуются. Эти адреса используются в транспортном режиме для инкрементального обновления контрольных сумм TCP/IP с целью сохранения их корректности после прохождения через устройства NAT (само устройство NAT не может сделать этого, поскольку контрольные суммы NAT TCP/IP находятся внутри пакета IPsec, инкапсулированного в UDP).

В [RFC3948] описаны детали инкапсуляции в UDP, а в [RFC3715] приведена базовая информация и мотивировка NAT-Traversal в целом. В комбинации с [RFC3948] данный документ представляет безусловно совместимое решение в части требований, определенных в [RFC3715].

В базовом сценарии для этого документа инициатор размещается за устройством NA(P)T, а отвечающая сторона имеет фиксированный адрес IP.

Этот документ определяет протокол, который будет работать даже при размещении обеих сторон за трансляторами NAT, но обработка случаев, когда отвечающая сторона также размещается за транслятором адресов, выходит за рамки этого документа. В одном варианте отвечающая сторона размещается за транслятором NAT со статическим адресом (для одного адреса IP может быть только один ответчик, поскольку нет возможности использовать порт получателя, отличающийся от 500/4500). Такая ситуация известна из конфигурационных параметров.

2. Уровни требований

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не следует (SHALL NOT), следует (SHOULD), не нужно (SHOULD NOT), рекомендуется (RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с [RFC2119].

3. Фаза 1

Обнаружение поддержки работы через NAT (NAT-Traversal) и присутствия устройств NAT на пути между двумя партнерами IKE выполняется в фазе 1 IKE [RFC2409] .

Транслятор NAT может сменить порт отправителя IKE UDP и получатели должны быть способны обрабатывать пакеты IKE, в которых номер порта отправителя отличается от 500. Трансляторы NAT меняют порт отправителя с учетом приведенных ниже условий.

  • порт не меняется, если за устройством NAT размещается только один хост IPsec;

  • для первого хоста IPsec устройство NAT может сохранить порт 500 и менять его только для соединений других хостов.

Получатели должны отвечать по адресу отправителя из пакета (см. [RFC3715], параграф 2.1, п. d). Это означает, что при смене исходным ответчиком ключей или отправке уведомлений исходному оператору исходный ответчик должен отправлять пакеты с тем же номером порта и адресом IP, которые использовались при последнем обращении к IKE SA.

Например, когда инициатор передает пакет с номерами портов отправителя и получателя 500, транслятор NAT может заменить порт отправителя на 12312, сохранив порт получателя 500. Отвечающий должен быть способен обработать пакет, отправленный из порта 12312 и отвечать на него пакетом из порта 500 в порт 12312. Устройство NAT тогда будет транслировать этого пакет, устанавливая для портов отправителя и получателя значение 500.

3.1. Детектирование поддержки работы через NAT

Возможность работы удаленного хоста через NAT (NAT-Traversal) определяется путем обмена идентификаторами производителей. В двух первых сообщениях фазы 1 (Phase 1) элемент данных с идентификатором производителя (vendor id payload) для данной спецификации должен передаваться, если он поддерживается (и он должен приниматься обеими сторонами) для проб NAT-Traversal. Содержимое этого элемента данных является хэш-суммой MD5 для

      RFC 3947

или (в шестнадцатеричной форме)

      4a131c81070358455c5728f20e95452f

3.2. Обнаружение присутствия NAT

Элемент данных NAT-D4 не только позволяет обнаружить присутствие NAT между партнерами IKE, но и определяет место расположения трансляторов NAT. Это имеет важное значение для передачи пакетов keepalive от устройств, расположенных «за» трансляторами NAT.

Для обнаружения устройств NAT между двумя хостами проверяется изменение адресов IP или номеров портов на пути доставки. Это выполняется путем передачи хэш-значений для адресов IP и номеров портов обоих партнеров IKE с каждой из сторон на другую. Если обе стороны рассчитывают эти хэш-значения и получают одинаковые результаты, это говорит об отсутствии преобразований NAT между ними. Если хэш-значения различаются, это говорит о том, что адрес или номер порта был где-то изменен. Это означает, что для передачи пакетов IPsec будет использоваться NAT-Traversal.

Если отправитель пакета не знает своего адреса IP (при наличии множества интерфейсов реализация может не знать конкретный интерфейс, через который будет отправлен пакет), отправитель может включить в пакет множество локальных хэш-значений (в виде отдельных элементов NAT-D). В таких случаях о наличии NAT говорит несоответствие всех таких значений.

Хэш-значения передаются в форме серий элементов NAT-D. Каждый элемент содержит одно хэш-значение, поэтому при передаче множества значений используется соответствующее число элементов NAT-D. В обычно ситуации применяется только два элемента NAT-D.

Элементы данных NAT-D включаются в третий и четвертый пакеты основного режима (Main Mode) и во второй и третий — агрессивного режима (Aggressive Mode).

Формат пакетов NAT-D показан на рисунке.

        1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
      +---------------+---------------+---------------+---------------+
      | Next Payload  | RESERVED      | Payload length                |
      +---------------+---------------+---------------+---------------+
      ~                 HASH для адреса и порта                       ~
      +---------------+---------------+---------------+---------------+

Идентификатор типа для элемента данных NAT-D имеет значение 20.

Значение HASH расcчитывается по формуле

         HASH = HASH(CKY-I | CKY-R | IP | Port)

Здесь используется согласованный алгоритм хэширования (HASH). Все данные в HASH представляются в сетевом порядке байтов. IP представляет 4 октета адреса IPv4 или 16 октетов адреса IPv6. Номер порта указывается 2-октетным значением с сетевым порядком байтов. Первый элемент NAT-D содержит IP-адрес и номер порта удаленной стороны (т. е., адрес получателя пакета UDP). Остальные элементы NAT-D содержат возможные адреса IP и номера портов для локальной стороны (т. е., все возможные адреса отправителя в пакетах UDP).

Если на пути нет устройств NAT первый полученный элемент NAT-D будет совпадать с одним из локальных элементов NAT-D (т. е., элементов NAT-D, передаваемых данным хостом), а один из оставшихся элементов NAT-D должен совпадать с адресом и портом удаленной стороны. Если первая проверка дает несовпадение (т. е., первый элемент NAT-D не соответствует ни одному из локальных адресов IP и портов), это говорит о динамическом преобразовании NAT на пути между партнерами, поэтому данной стороне соединения следует начать передачу пакетов keepalive, как описано в [RFC3948] (эта сторона расположена за NAT).

CKY-I и CKY-R указывают значения cookie инициатора и ответчика, которые добавляются при расчете хэш-функции для предотвращения атак с предварительным расчетом (precomputation attack), делающих адреса IP и порты недоступными.

Ниже приведен пример обмена Phase 1 с использованием NAT-Traversal в основном режиме (Main Mode — аутентификация с подписями).

   Инициатор                           Ответчик
   ------------                        ------------
   HDR, SA, VID                -->
                                       <-- HDR, SA, VID
   HDR, KE, Ni, NAT-D, NAT-D   -->
                                       <-- HDR, KE, Nr, NAT-D, NAT-D
   HDR*#, IDii, [CERT, ] SIG_I -->

Ниже приведен пример обмена Phase 1 с использованием NAT-Traversal в агрессивном режиме (Aggressive Mode — аутентификация с подписями).

   Инициатор                           Ответчик
   ------------                        ------------
   HDR, SA, KE, Ni, IDii, VID  -->
                                       <-- HDR, SA, KE, Nr, Idir, [CERT, ], VID, NAT-D,
                                               NAT-D, SIG_R
   HDR*#, [CERT, ], NAT-D, NAT-D,
                        SIG_I  -->

Знак # указывает, что такие пакеты передаются в измененный порт, если обнаружено присутствие NAT.

4. Смена портов

Осведомленные об IPsec трансляторы NAT могут вызывать проблемы (см. параграф 2.3 в [RFC3715]). Некоторые устройства NAT не будут менять порт отправителя IKE 500 даже при наличии за транслятором NAT множества клиентов ([RFC3715], параграф 2.3, п. n). Они также могут применять для демультиплексирования трафика IKE cookie вместо номера порта отправителя ([RFC3715], параграф 2.3, п. m). Обе эти ситуации являются проблематичными для базовой прозрачности NAT, поскольку протоколу IKE трудно определить возможности транслятора NAT. Лучшим решением будет просто максимально быстрый перенос трафика IKE из порта 500 для предотвращения описанных выше ситуаций в осведомленных об IPsec трансляторах NAT.

Наиболее часто встречаются ситуации с размещением инициатора за устройством NAT. Инициатор должен быстро переключиться на работу через порт 4500 после обнаружения присутствия NAT для минимизации окна проблем, связанных с осведомленными об IPsec трансляторами NAT.

В основном режиме (Main Mode) инициатор должен сменить порты при передаче элемента данных ID, если между хостами имеется устройство NAT. Инициатор должен установить для портов отправителя и получателя значения UDP 4500. Все последующие пакеты для этого партнера (включая информационные уведомления) должны передаваться в порт 4500. В дополнение к этому перед данными IKE должен помещаться маркер non-ESP, позволяющий демультиплексировать трафик, как описано в [RFC3948].

Таким образом, пакет IKE будет иметь вид

         IP UDP(4500,4500) <non-ESP marker> HDR*, IDii, [CERT, ] SIG_I

Это предполагает аутентификацию с использованием подписей. 4-байтовый маркер non-ESP определен в [RFC3948].

При получении этого пакета ответчиком он выполняет обычную расшифровку и обработку различных элементов данных. После успешного завершения ответчик должен обновить свое локальное состояние так, что все последующие пакеты (включая информационные уведомления) для партнера использовали новый номер порта и, возможно, новый адрес IP, полученные из корректного входящего пакета. Номера портов в общем случае будут различаться, поскольку NAT будет отображать UDP(500,500) в UDP(X,500), а UDP(4500,4500) в UDP(Y,4500). Адрес IP будет иногда отличаться от заранее измененного IP-адреса. Ответчик должен направлять все последдующие пакеты IKE данному партнеру, используя UDP(4500,Y).

Аналогично, если ответчик меняет ключи Phase 1 SA, согласование замены должно начинаться с использованием UDP(4500,Y). Все реализации, обеспечивающие работу через NAT, должны поддерживать согласование, начинающееся через порт 4500. если согласование начинается через порт 4500, номер порта не потребуется менять в течение обмена.

После смены порта получение пакета на порту 500 будет говорить о том, сто это старый пакет. Если пакет является информационным, его можно обработать в соответствии с локальной политикой (если она разрешает это). Если пакет относится к Main Mode или Aggressive Mode (с теми же значениями cookie, что и в предыдущем пакете), его следует отбросить. Если пакет относится к новому обмену основного или агрессивного режима, он обрабатывается обычным путем (другая сторона могла быть перезагружена и начала обмен по этой причине).

Ниже приведен пример обмена Phase 1 с использованием NAT-Traversal в основном режиме (аутентификация с подписями) с заменой порта.

   Инициатор                           Ответчик
   ------------                        ------------
   UDP(500,500) HDR, SA, VID -->
                                       <-- UDP(500,X) HDR, SA, VID
   UDP(500,500) HDR, KE, Ni,
                NAT-D, NAT-D -->
                                       <-- UDP(500,X) HDR, KE, Nr, NAT-D, NAT-D
   UDP(4500,4500) HDR*#, IDii,
               [CERT, ]SIG_I -->
                                       <-- UDP(4500,Y) HDR*#, Idir, [ CERT, ], SIG_R

Процедура для Aggressive Mode очень похожа. После обнаружения NAT инициатор передает пакет IP UDP(4500,4500) вида <4-байтовый маркер non-ESP> HDR*, [CERT, ], NAT-D, NAT-D, SIG_I. Ответчик выполняет обработку, подобную описанной выше, и при ее успешном завершении должен обновить свои внутренние порты IKE. Ответчик должен отправлять все последующие пакеты IKE этому партнеру, используя UDP(4500,Y).

   Инициатор                           Ответчик
   ------------                        ------------
   UDP(500,500) HDR, SA, KE,
                 Ni, IDii, VID -->
                                       <-- UDP(500,X) HDR, SA, KE, Nr, IDir, [CERT, ],
                                               VID, NAT-D, NAT-D, SIG_R
   UDP(4500,4500) HDR*#, [CERT, ],
           NAT-D, NAT-D, SIG_I -->
                                       <-- UDP(4500, Y) HDR*#, ...

При включенной поддержке работы через NAT поле номера порта в элементе данных ID для режимов Main Mode/Aggressive Mode должно иметь значение 0.

Наиболее распространенным вариантом размещения ответчика за NAT является простое преобразование адресов 1:1 в трансляторе NAT. В этом случае инициатор так же меняет номера обоих портов на 4500. Ответчик применяет алгоритм, аналогичный вышеописанному, хотя в этом случае Y = 4500 и трансляции портов не происходит.

Другой случай смены портов включает определение используемых портов внешними средствами (out-of-band), рассмотрение которых выходит за рамки этого документа. Например, если ответчик находится за устройством NAT, транслирующим номера портов, а инициатору нужно связаться с таким ответчиком, обычно инициатор определяет используемые порты через некий другой сервер. После того, как инициатор узнает номера портов, используемые для работы через NAT (обычно что-то типа UDP(Z,4500)), он инициирует соединения, используя эти порты. Это похоже на описанный выше случай смены ключей ответчиком, когда номера используемых портов известны заранее и никаких дополнительных изменений не требуется. Отсчет таймера keepalive начинается после перехода на новый номер порта и сообщения keepalive не передаются в порт 500.

5. Ускоренный режим

После фазы 1 обе стороны знают о наличии между ними транслятора NAT. Окончательное решение об использовании NAT-Traversal относится к ускоренному режиму (Quick Mode). Применение NAT-Traversal согласуется в элементах данных SA ускоренного режиме. В Quick Mode обе стороны могут также передавать исходные адреса своих пакетов IPsec (в транспортном режиме) на другую сторону и каждая из сторон может скорректировать поле контрольной суммы TCP/IP после преобразования NAT.

5.1. Согласование инкапсуляции для NAT-Traversal

Согласование работы через NAT (NAT-Traversal) добавляет два новых режима инкапсуляции, приведенных ниже.

   UDP-Encapsulated-Tunnel         3
   UDP-Encapsulated-Transport      4

Обычно не имеет смысла предлагать сразу обычный туннельный или транспортный режим и режимы UDP-Encapsulated. Инкапсуляция в UDP требуется для обеспечения передачи трафика, не относящегося к протоколам UDP/TCP, через трансляторы NAT (см. [RFC3715], параграф 2.2, п. i).

Если между хостами имеется транслятор NAT, обычная туннельная или транспортная инкапсуляция может не работать. В таких случаях следует использовать инкапсуляцию в UDP.

Если между хостами нет устройств NAT, не возникает причины для неоправданного расхода полосы, связанного с дополнительной инкапсуляцией пакетов в UDP. В таких случаях применять инкапсуляцию в UDP не следует.

Инициаторам не следует включать в свои предложения обновременно обычный туннельный или транспортный режим и режим UDP-Encapsulated-Tunnel или UDP-Encapsulated-Transport.

5.2. Передача исходных адресов отправителя и получателя

Для обновления контрольных сумм TCP оба партнера должны знать использованные партнером при создании пакета адреса IP (см. [RFC3715], параграф 2.1, п. b). Для инициатора исходным адресом будет его адрес IP, а исходным адресом ответчика будет воспринятый IP-адрес партнера. Для ответчика исходным адресом инициатора будет воспринятый адрес партнера, а исходным адресом ответчика — его собственный адрес IP.

Исходные адреса передаются с использованием элемента данных NAT-OA (NAT Original Address).

Первым является элемент Initiator NAT-OA, вторым — Responder NAT-OA.

Пример 1

         Инициатор <---------> NAT <---------> Ответчик
                  ^               ^           ^
                Iaddr           NatPub      Raddr

Инициатор, находящийся за NAT обменивается данными с публично доступным ответчиком. Адреса IP ответчика и инициатора обозначим Iaddr и Raddr, публичный адрес транслятора NAT — NatPub.

   Инициатор
                     NAT-OAi = Iaddr
                     NAT-OAr = Raddr
   Ответчик
                     NAT-OAi = NATPub
                     NAT-OAr = Raddr

Пример 2

         Инициатор <------> NAT1 <---------> NAT2 <-------> Ответчик
                  ^             ^           ^              ^
                Iaddr        Nat1Pub     Nat2Pub         Raddr

Здесь NAT2 «публикует» адрес Nat2Pub для ответчика и пересылает весь направленный по этому адресу трафик ответчику.

   Инициатор
                     NAT-OAi = Iaddr
                     NAT-OAr = Nat2Pub
   Ответчик
                     NAT-OAi = Nat1Pub
                     NAT-OAr = Raddr

В транспортном режиме обе стороны должны передавать на другую сторону исходные адреса инициатора и ответчика. В туннельном режиме обеим сторонам не следует передавать исходные адреса на другую сторону.

Элементы данных NAT-OA передаются в первом и втором пакетах ускоренного режим (Quick Mode). Инициатор должен передавать эти элементы, если он предлагает любой из режимов UDP-Encapsulated5, а ответчик должен передавать такой элемент только при выборе режима UDP-Encapsulated-Transport. Возможна передача инициатором элемента NAT-OA при одновременной поддержке транспортного и туннельного режима UDP-Encapsulated. В такой ситуации ответчик, выбравший туннельный режим UDP-Encapsulated, не возвращает элемента данных NAT-OA.

Формат пакета NAT-OA показан на рисунке.

         1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
       +---------------+---------------+---------------+---------------+
       | Next Payload  | RESERVED      | Payload length                |
       +---------------+---------------+---------------+---------------+
       | ID Type       | RESERVED      | RESERVED                      |
       +---------------+---------------+---------------+---------------+
       |           IPv4 (4 octets) or IPv6 address (16 octets)         |
       +---------------+---------------+---------------+---------------+

Идентификатор типа для элементов данных NAT-OA имеет значение 21.

Поле ID Type определено в [RFC2407]. Разрешены только типы ID_IPV4_ADDR и ID_IPV6_ADDR. Два резурвных поля после ID Type должны иметь нулевые значения.

Ниже приведен пример Quick Mode с использованием элементов данных NAT-OA.

   Инициатор                           Ответчик
   ------------                        ------------
   HDR*, HASH(1), SA, Ni, [, KE]
       [, IDci, IDcr ]
       [, NAT-OAi, NAT-OAr] -->
                                       <-- HDR*, HASH(2), SA, Nr, [, KE]
                                                 [, IDci, IDcr ] [, NAT-OAi, NAT-OAr]
   HDR*, HASH(3)            -->

6. Уведомления INITIAL-CONTACT

Адрес отправителя и номер порта6 в уведомлении INITIAL-CONTACT для расположенного за транслятором NAT хоста не имеют смысла (NAT заменит их), поэтому адреса IP и номера портов недопустимо использовать для идентификации удаляемой IKE/IPsec SA (см. [RFC3715], параграф 2.1, п. c). Взамен следует использовать элемент данных ID, переданный другой стороной. Т. е. при получении INITIAL-CONTACT от другой стороны, принимающему следует удалить все связи SA, ассоциированные с этим элементом ID.

7. Восстановление после утраты отображения NAT

В некоторых случаях транслятор NAT может удалять отображения, которые еще используются (например, при слишком редких сообщениях keepalive или в результате перезагрузки устройства NAT). В таких случаях стороне, не расположенной за транслятором NAT следует использовать последний корректный пакет IKE или IPsec, инкапсулированный в UDP, от другой стороны для определения адреса IP и номера порта, которые следует использовать. Хосту, расположенному за динамическим NAT, недопустимо делать это (такое поведение открывает возможность для DoS-атаки), поскольку адрес и номер порта другой стороны не изменились (она не находится за NAT).

Любой аутентифицированный IKE пакет ESP или IKE может служить для обнаружения смена адреса и номера порта, но сообщения keepalive не подходят для этого, поскольку они не аутентифицируются.

8. Вопросы безопасности

В тех случаях, когда предлагаются те или изменения фундаментальных частей протокола защиты, проверка влияния изменений на безопасность не может быть опущена. Поэтому ниже приводятся некоторые соображения о последствиях и оценки эффективности предложений.

  • Пробы IKE раскрывают поддержку NAT-Traversal для любого, кто может отслеживать трафик, однако раскрытие поддержки работы через трансляторы NAT не создает новых уязвимостей.

  • Значение механизмов аутентификации на основе адресов IP сразу же исчезает при появлении трансляторов NAT. Это совсем не обязательно считать недостатком (для любой реальной защиты следует использовать отличные от адресов IP способы аутентификации). Это означает, что аутентификация с заранее распространенными ключами (pre-shared key) не может применяться в основном режиме (Main Mode) без использования групповых (group-shared) ключей для находящихся за NAT хостов. Использование групповых ключей связано с огромным риском, поскольку оно позволяет любому члену группы аутентифицировать себя у любой другой стороны, заявив себя в качестве «кого-то из группы». Т. е., обычный пользователь может выдать себя за шлюз VPN и действовать, как «человек посередине» (man in the middle), читая/изменяя весь трафик, идущий другим членам группы или от них. Использование групповых ключей не рекомендуется.

  • Поскольку внутреннее адресное пространство имеет размер лишь 32 бита и обычно занято достаточно неплотно, для злоумышленника может оказаться возможным определение внутреннего адреса, используемого за транслятором NAT, путем проверки всех возможных адресов IP на предмет соответствия хэш-значению. Номера портов обычно фиксированы (500), а значения cookie можно извлечь из пакетов. Это ограничивает число рассчитываемых хэш-значений до 232. Если требуется угадать адрес из приватных блоков IP, число рассчитываемых значений снижается до 224 + 2 * (216)7.

  • Элементы данных NAT-D и Vendor ID не аутентифицируются ни в основном (Main Mode), ни в агрессивном (Aggressive Mode) режиме. Это означает, что атакующий может удалить, изменить или вставить такой элемент. Удаляя или добавляя элементы, атакующий может организовывать атаку на отказ служб (DoS8). Изменяя пакеты NAT-D, атакующий может вынудить обе стороны использовать режимы UDP-Encapsulated вместо прямой организации туннеля или транспортного соединения, что приведет к неоправданному расходу полосы.

  • Передача исходного адреса отправителя в ускоренном режиме раскрывает другой стороне внутренний адрес IP за транслятором NAT. Однако в этом случае другая сторона уже аутентифицирована (потвердила свою подлинность) и передача исходного адреса отправителя нужна только в транспортном режиме.

  • Обновление адресов и портов при инкапсуляции IKE SA/ESP в UDP для каждого приемлемого аутентифицированного пакета может вызывать отказ служб (DoS), если атакующий имеет возможность прослушивать весь трафик в сети, менять порядок пакетов и вставлять новые пакеты перед пакетом, который он уже видел. Иными словами, атакующий может взять аутентифицированный пакет от хоста, находящегося за NAT, поменять порты UDP отправителя/получателя или адрес IP и передать с нарушением порядка этот пакет перед реальным пакетом. Хост, не находящийся за NAT, обновит у себя отображение IP-адреса и порта, а потом будет передавать последующий трафик по обманным адресу и порту. Эта проблема решается сразу же, как только атакующий прекращает изменение пакетов — первый же пакет от реального хоста восстановит нормальную ситуацию. В реализациях следует поддерживать аудит событий при каждом изменении отображений и не разрешать такие изменения слишком часто.

9. Согласование с IANA

Этот документ включает два новых «магических значения», выделенные в имеющемся реестре IANA для IPsec и изменены названия для зарегистрированного ранее порта 4500. Документ также определяет два новых элемента данных для IKE.

В реестр Internet Security Association and Key Management Protocol (ISAKMP) Identifiers добавлены указанные в таблице идентификаторы режимов инкапсуляции.

Имя

Значение

Документ

UDP-Encapsulated-Tunnel

3

[RFC3947]

UDP-Encapsulated-Transport

4

[RFC3947]

В реестр номеров портов внесены изменения, указанные в таблице.

Имя

Номер/имя

Описание

Документ

ipsec-nat-t

4500/tcp

IPsec NAT-Traversal

[RFC3947]

ipsec-nat-t

4500/udp

IPsec NAT-Traversal

[RFC3947]

В веестр Next Payload Types добавлены новые типы элементов данных IKE:

         NAT-D         20         NAT Discovery Payload
         NAT-OA        21         NAT Original Address Payload

10. Согласование с IAB

Вопросы UNSAF [RFC3424] решаются требованиями совместимости IPsec-NAT, описанными в [RFC3715].

11. Благодарности

Спасибо Markus Stenberg, Larry DiBurro и William Dixon за активное участие в подготовке этого документа.

Спасибо Tatu Ylonen, Santeri Paavolainen и Joern Sierwald, которые подготовили документы, послужившие основой для данного документа.

12. Литература

12.1. Нормативные документы

[RFC2409] Harkins, D. and D. Carrel, «The Internet Key Exchange (IKE)», RFC 24099, November 1998.

[RFC2407] Piper, D., «The Internet IP Security Domain of Interpretation for ISAKMP», RFC 24071, November 1998.

[RFC3948] Huttunen, A., Swander, B., Volpe, V., DiBurro, L., and M. Stenberg, «UDP Encapsulation of IPsec Packets», RFC 3948, January 2005.

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, March 1997.

12.2. Дополнительная литература

[RFC3715] Aboba, B. and W. Dixon, «IPsec-Network Address Translation (NAT) Compatibility Requirements», RFC 3715, March 2004.

[RFC3424] Daigle, L. and IAB, «IAB Considerations for Unilateral Self-Address Fixing (UNSAF) Across Network Address Translation», RFC 3424, November 2002.

Адреса авторов

Tero Kivinen

SafeNet, Inc.

Fredrikinkatu 47

FIN-00100 HELSINKI

Finland

EMail: kivinen@safenet-inc.com

Ari Huttunen

F-Secure Corporation

Tammasaarenkatu 7,

FIN-00181 HELSINKI

Finland

EMail: Ari.Huttunen@F-Secure.com

Brian Swander

Microsoft

One Microsoft Way

Redmond, WA 98052

USA

EMail: briansw@microsoft.com

Victor Volpe

Cisco Systems

124 Grove Street

Suite 205

Franklin, MA 02038

USA

EMail: vvolpe@cisco.com

Перевод на русский язык

Николай Малых

nmalykh@gmail.com

Полное заявление авторских прав

Copyright (C) The Internet Society (2005).

This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an «AS IS» basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Интеллектуальная собственность

The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF’s procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79.

Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.

Подтверждение

Финансирование функций RFC Editor обеспечено Internet Society.

1Network address translation.

2Internet Key Exchange.

3Quick Mode.

4NAT discovery — обнаружение NAT.

5В оригинале ошибочно сказано UDP-Encapsulated-Transport. См. https://www.rfc-editor.org/errata_search.php?eid=4936. Прим. перев.

6В оригинале ошибочно сказано port address. См. https://www.rfc-editor.org/errata_search.php?eid=4937. Прим. перев.

7Суммарный размер выделенных для приватных сетей блоков адресов IP (RFC 1918). Прим. перев.

8Denial of Service.

9Этот документ признан устаревшим и заменен RFC 4306, который затем заменен RFC 5996, а после — RFC 7296. Прим. перев.




Опыт организации граничных шлюзов на основе Linux

Опыт организации граничных шлюзов на основе Linux

(тезисы доклада на конференции “open source forum ’05”)

Николай Малых

ЗАО BiLiM Systems

Санкт-Петербург

Современный бизнес практически немыслим без использования сетевых технологий хотя бы для получения доступа к информации через Internet. Следовательно для большинства организаций актуальна задача подключения своей локальной сети к внешним сетям. При организации такого подключения возникает необходимость установки на стыке сетей (периметре внутренней сети) специальных аппаратно-программных комплексов, которые будем называть далее шлюзами. В задачи граничного шлюза входит:

  • маршрутизация трафика между внутренней сетью и одним или несколькими каналами связи с внешними сетями;
  • контроль и учет трафика входящего в сеть и выходящего из него;
  • трансляция адресов сетевого уровня (IP).

Для решения такого рода задач выпускается множество устройств, однако все эти устройства рассчитаны на массовые (типовые) варианты использования и далеко не всегда соответствуют потребностям конкретной организации. Показательным примером может служить автономная система, включающая сеть одной организации. Для этого случая требуется установить на границе сети шлюз, который поддерживает протокол BGP4 и обеспечивает функции сетевого экранирования (брандмауэр). Стоимость такого шлюза (маршрутизатора) общего назначения сегодня составляет около 15 тысяч долларов США.

Операционные системы семейства UNIX содержат все, что необходимо для организации такого шлюза, в своем составе или в числе прикладных программ. Мы выбрали для организации шлюза ОС RedHat, хотя в процессе его создания и последующего развития от исходного набора файлов RedHat мало что осталось, поскольку большая часть используемых пакетов была собрана из исходных кодов с внесением во многих случаях тех или иных изменений. В качестве аппаратной платформы используется ПК общего назначения с процессором Celeron 300 МГц, оперативной памятью размеров 512 Мбайт и дисковым накопителем размером 20 Гбайт. Очевидно, что рыночная стоимость такого ПК на сегодняшний день не превышает нескольких десятков долларов.

Шлюз используется для маршрутизации пакетов между четырьмя сегментами FastEthernet – 2 внешних канала, локальная сеть компании и сегмент публичных серверов (DMZ). Наша компания имеет зарегистрированную автономную систему, поэтому на шлюзе поддерживается протокол BGP4 для анонсирования наших префиксов и получения маршрутной информации от 2 провайдеров.

Ядро Linux собрано и оптимизировано с учетом использования компьютера в качестве маршрутизатора и межсетевого экрана, поэтому в нем отключены все ненужные компоненты и отключена поддержка загружаемых модулей (LKM). Монолитное ядро позволяет повысить производительность системы и предотвращает возможность неконтролируемой загрузки модулей (например, троянских программ, выполненных в форме LKM). В ядре также отключена поддержка функций, позволяющих осуществить несанкционированный локальный доступ к шлюзу (монитор, клавиатура, мышь, порты USB, LPT)

Для обеспечения маршрутизации используется пакет Zebra с незначительными доработками, который собран с поддержкой лишь реально используемых протоколов OSPF и BGP4. Фильтрация пакетов и учет трафика осуществляются на основе Netfilter/iptables с незначительными доработками по сравнению со стандартным набором, распространяемым в составе ядра, iptables и POM. Для мониторинга целостности файловой системы шлюза используется пакет samhain, а для проверки на наличие в системе враждебного кода набор утилит, включающий chkrootkit, rkhunter и др. Контроль записей в журнальных файлах осуществляется с помощью простой утилиты logcheck. Для обеспечения дополнительной надежности некоторые записи дублируются на сервере syslog, находящемся внутри сети компании. В качестве системы детектирования попыток вторжения или иных нежелательных действий (например сканирования портов) для шлюза и внутренних сетей используется стандартный пакет Snort. В нашем случае шлюз служит лишь в качестве набора датчиков Snort, собирающих информацию и передающих ее в базу данных на один из внутренних серверов. Кроме того, попытки входа в систему или проникновения в сеть регистрируются также с помощью утилиты hostsentry и набора правил iptables. Дополнительным детектором попыток сканирования служит утилита portsentry и набор правил iptables.

Перечислим набор функций, реализованных на шлюзе:

  • маршрутизация пакетов IP с поддержкой протоколов BGP4 и OSPF;

  • трансляция адресов для входящего и исходящего трафика;

  • межсетевое экранирование с учетом состояния соединений (stateful);

  • фильтрация пакетов, входящих в сеть и выходящих наружу:

  • ingress-фильтрация в соответствии с RFC 2267;

  • фильтрация спама на основе списков доступа;

  • фильтрация спама по частоте попыток подключения;

  • фильтрация попыток несанкционированного доступа к шлюзу по протоколу SSH;

  • фильтрация нежелательного трафика по протоколам, номерам портов и адресам IP;

  • управление полосой для исходящего трафика;

  • детектирование попыток сканирования или проникновения в сеть;

  • блокирование DoS-атак на шлюз и хосты внутренних сетей;

  • мониторинг работы сервера, включая уровень загрузки внешних каналов и процессора, целостность файловой системы;

  • удаленное управление с использованием SSH-соединений и Web-интерфейса;

  • детектирование попыток вторжения и сканирования для шлюза и внутренней сети;

  • детектирование и блокирование недопустимого исходящего трафика для предотвращения возможности организации атак из сети компании;

  • система мониторинга и оповещения администратора о сигналах тревоги по электронной почте или с помощью SMS;

  • учет трафика пользователей из внутренней сети;

  • система LookingGlass для проверки связности сети из удаленных точек.

Данный шлюз в описанной конфигурации используется с начала 2002 года и доказал свою надежность и эффективность.