Регулярное выражение проверки URL для реальных URL - PullRequest
5 голосов
/ 15 января 2012

Я хочу проверить, что указанные строки являются URL-адресами.Соответствие URL в тексте тоже было бы неплохо, но не обязательно.Я искал и экспериментировал, но до сих пор не нашел чего-то, что отвечало бы этим требованиям:

  1. Не должен принимать строки, которые, когда рассматриваются как ссылки, представляют угрозу безопасности.Например, <a href="javascript:alert(document.cookie)">clickme</a> является допустимым элементом HTML и действительно работает (вызывает предупреждение и т. Д.) По крайней мере в некоторых браузерах.Я обеспокоен тем, что если я разрешу произвольные схемы (см. Ниже), это может поставить под угрозу безопасность (как отмечено, например, здесь: Какое регулярное выражение лучше всего проверить, является ли строка допустимым URL-адресом? ).

  2. Должно работать правильно в JavaScript.

  3. Было бы неплохо, если бы это работало так же в Java - я занимаюсь разработкой в ​​GWT,так что это было бы неплохо, но не обязательно.

  4. Должен принимать URL-адреса, используемые на практике, а не только стандартные URL-адреса. Конкретные примеры:

    а.Я хочу принять http://fr.wikipedia.org/wiki/Français,, который является нестандартным из-за неанглийского символа, но принят моим справочным браузером IE (7+) и Chrome.

    b.Я хочу принять http://fr.wikipedia.org/wiki/Fran%c3%a7ais,, что является нестандартным, потому что шестнадцатеричное кодирование в процентах должно быть в верхнем регистре, но снова принимается IE и Chrome.Я думаю, что я мог бы просто сделать нечувствительный к регистру матч - любой минус вы можете себе представить?

    c.Я хочу принять http://localhost/localpath/servlet#action?param=value,, что является нестандартным, поскольку часть фрагмента (от '#' до конца) не должна содержать '?'и другие символы, но есть приложения, которые генерируют такие URL, и браузеры принимают их.

    d.Я хочу принимать URL-адреса с любой схемой / протоколом (не только http, https и ftp), потому что все виды приложений, с которыми я интегрируюсь, и их пользователи, возможно, должны передавать такие URL-адреса.Я могу запретить «javascript:» и разрешить все остальное;если вы думаете, что это может поставить под угрозу безопасность, скажите, пожалуйста.

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

  • регулярное выражение в GWT для сопоставления URL-адресов - довольно хорошее и простое регулярное выражение, но не принимает нестандартные URL-адреса.Я могу обработать часть схемы и чувствительность к регистру кодирования процентов, но не другие вопросы.

  • https://stackoverflow.com/a/190405/96929 - Гигантское регулярное выражение (я спрашиваю себя, все ли браузерыи фреймворки, которые я использую, могут обрабатывать этот размер), который кажется очень всеобъемлющим, но говорит, что он соответствует стандарту, и я не могу сделать из него головы или хвосты.: -)

Ответы [ 2 ]

5 голосов
/ 15 января 2012

Должен принимать URL-адреса, которые используются на практике, а не только URL-адреса, соответствующие стандарту

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

Я хочу принять http://fr.wikipedia.org/wiki/Français,, что является нестандартным

Это не URI, но равно вполне стандартный IRI .

  • нестандартный, потому что шестнадцатеричное кодирование процентов должно быть в верхнем регистре
  • нестандартно, потому что фрагмент фрагмента (из '# 'в конце) не должен включать'? '

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

Я могу запретить 'javascript:' и разрешить все остальное;если вы думаете, что это может поставить под угрозу безопасность, скажите, пожалуйста.

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

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

Белый список является единственным вероятным способом продвижения вперед, поэтому вам просто нужно вручную разрешить каждую новую схему в каждом конкретном случае.Это требует некоторой осторожности;например, схема data: кажется безвредной и полезной, но потенциально страдает теми же проблемами XSS, что и javascript:.

. Вам также потребуется знать некоторую информацию о каждой схеме.Такие схемы, как http и ftp, имеют «полномочия по присвоению имен на основе сервера»: они могут включать в себя отдельное имя хоста и путь к ресурсу внутри этого хоста;Кроме того, вы, вероятно, требуете, чтобы они были абсолютными URI.Если вы хотите разрешить файловые URI, вам нужно убедиться, что они не содержат хостов (file:///).Для других схем может не быть конкретного синтаксиса, требуемого самим стандартом URI, но могут быть и другие ограничения, например, mailto: должен принимать действительный адрес электронной почты.

Гигантское регулярное выражение (IСпросите себя, могут ли все браузеры и фреймворки, которые я использую, обрабатывать этот размер), который выглядит очень всеобъемлющим

Это не сработает в JavaScript, поскольку имеет неподдерживаемый синтаксис \x{code point}.Также такие языки, как JavaScript, чьи движки регулярных выражений работают в терминах кодовых единиц UTF-16 вместо полных кодовых точек Unicode, не смогут обрабатывать диапазоны символов вне BMP.

Вам придется заменить длинный \x{A0}...\x{1FFFD} группирует что-то более простое, например \u00A0-\uFFFD, а затем проверяет наличие недопустимых суррогатных пар отдельно, а также несимвольных символов 0xnnFFFE – F, если вы заботитесь о них (вероятно, нет).

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

С заменой самой длинной части этого регулярного выражения является безумно длинная строка проверки цифр, пытающаяся проверить числовой IPадреса.Это то, что регулярные выражения вообще не годятся.Я бы настоятельно рекомендовал не беспокоиться о числовых адресах IPv6 и IPv-future: даже при условии широкого распространения IPv6 в ближайшее время никто не будет использовать их в обозримом будущем.(Вы даже хотите разрешить ссылки на числовые адреса? Зависит от того, что делает ваше приложение, но часто нет.)

Вы также можете запретить использование префиксов userinfo @ hostname (поскольку они традиционно бесполезны, кроме атак спуфинга), и имен хостов в процентах (поскольку они не служат цели, учитывая наличие Punycode, и не работают в некоторых браузерах).

Таким образом, нет единого ответа на проверку IRI, но вот то место, с которого вы могли бы начать:

(
    https?://
    (
        ([0-9]{1-3}(\.[0-9]{1-3}){3})|
        ([-0-9a-z\u00A0-\uFFFD]{1-63}(\.[-0-9a-z\u00A0-\uFFFD]{1-63})*)
    )
    (:[0-9]+)?/
    (
        %[0-9a-f][0-9a-f]|
        [-._!$&'()*+,:;=@~0-9a-z\u00A0-\uFFFD/?#]
    )*
)|(
    ftp://                                    // same again but with no ?query
    ...                                       // or port number
)|(
    mailto:                                   // specify requirements for
    ...                                       // other accepted schemes
)

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

1 голос
/ 15 января 2012

Поскольку вы используете Java на стороне сервера, я рекомендую использовать URI . Он примет все «странные» вещи, которые вы хотите, и это просто вопрос .getScheme(), чтобы убедиться, что это действительно HTTP или HTTPS.

И в отличие от URL, URI не будет пытаться выполнить разрешение имен!

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