どの文字がURLを無効にしますか?


515

どの文字がURLを無効にしますか?

これらは有効なURLですか?

  • example.com/file[/].html
  • http://example.com/file[/].html

42
検証するときは、常に「前向きに考える」必要があります。「何が有効か」を尋ね、それ以外はすべて無効です。(いくつかの)有効な文字に対するテストは、考えられるすべての無効な文字よりもはるかに安全です(そして簡単です!)。
mfx

回答:


600

一般に、RFC 3986で定義されている URI (セクション2:文字を参照)には、次の84文字のいずれかを含めることができます。

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=

このリストには、URI内のこれらの文字が出現する可能性のある場所が記載されていないことに注意してください。

その他の文字は、パーセントエンコーディング(%hh)でエンコードする必要があります。URIの各部分には、パーセントエンコードされた単語で表す必要のある文字について、さらに制限があります。


31
(もちろん、キャラクターのリストには、URIのどこで発生するかは
明記さ

75
文字列全体が上記の文字のみを含むかどうかを判断する正規表現は次のとおりです。/ ^ [!#$&-; =?-[] _ a-
z〜

43
@techiferous、ええ、「%」のエスケープ文字を許可するのを忘れていました。それはもっと似/^([!#$&-;=?-[]_a-z~]|%[0-9a-fA-F]{2})+$/ ているはずです: あなたがそれが受け入れるべきだったと思った何か他に何かありましたか?(正確に言うと、正規表現は文字列に有効なURL文字が含まれているかどうかをチェックするだけで、文字列が整形式のURLを含んでいるかどうかをチェックしません。)
Leif Wickland

12
@Timwi RFC 3986は、「パーセントでエンコードされたオクテットは、パーセント文字「%」と、それに続く、そのオクテットの数値を表す2つの16進数で構成される文字トリプレットとしてエンコードされます。」また、「パーセント( "%")文字はパーセントエンコードされたオクテットのインジケーターとして機能するため、そのオクテットをURI内のデータとして使用するには、「%25」としてパーセントエンコードする必要があります。「%」は2桁の16進数が後に続く場合にのみ表示される可能性があると言っていると私は読んだ。どのようにそれを読みますか?
Leif Wickland 2012年

13
@Weeble私の正規表現では、範囲を使用してこれらの文字を含めました。「&」と「;」の間 そして「?」の間 と「[」では、見なかった文字がすべて見つかります。
Leif Wickland

194

いくつかの明確化を追加し、上記の質問に直接対処するために、URLとURIに問題を引き起こすいくつかのクラスの文字があります。

許可されていないためにURL / URIに表示されないはずの文字、予約文字(下記で説明)、および場合によっては問題を引き起こす可能性があるが、「賢明でない」または「安全でない」とマークされている文字があります。文字が制限されている理由の説明は、RFC-1738(URL)およびRFC-2396(URI)に明確に記載されています。新しいRFC-3986(RFC-1738への更新)は、特定のコンテキストで許可される文字の構成を定義していますが、古い仕様では、次のルールで許可されない文字のより簡単で一般的な説明を提供しています。

除外されたUS-ASCII文字は、URI構文内で許可されていません。

   control     = <US-ASCII coded characters 00-1F and 7F hexadecimal>
   space       = <US-ASCII coded character 20 hexadecimal>
   delims      = "<" | ">" | "#" | "%" | <">

文字「#」は、フラグメント識別子からURIを区切るために使用されるため、除外されます。パーセント文字「%」は、エスケープ文字のエンコードに使用されるため除外されています。つまり、「#」と「%」は、特定のコンテキストで使用する必要がある予約文字です。

賢くない文字のリストは許可されますが、問題を引き起こす可能性があります:

   unwise      = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"

クエリコンポーネント内で予約されている文字、および/またはURI / URL内で特別な意味を持つ文字:

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

上記の「予約済み」構文クラスは、URI内では許可されているが、汎用URI構文の特定のコンポーネント内では許可されていない可能性がある文字を指します。「予約済み」セットの文字は、すべてのコンテキストで予約されているわけではありません。たとえば、ホスト名にはオプションのユーザー名を含めることができるためftp://user@hostname/、「@」文字が特別な意味を持っているようなものにすることができます。

以下は、無効で無意味な文字( '$'、 '['、 ']'など)があり、適切にエンコードする必要があるURLの例です。

http://mw1.google.com/mw-earth-vectordb/kml-samples/gp/seattle/gigapxl/$[level]/r$[y]_c$[x].jpg

URI / URLの文字制限の一部は、プログラミング言語に依存しています。たとえば、 '|' (0x7C)文字は、URI仕様で「unwise」とマークされているだけですが、Java java.net.URIコンストラクターでURISyntaxExceptionをスローします。そのため、URLなどhttp://api.google.com/q?exp=a|bは許可されずhttp://api.google.com/q?exp=a%7Cb、URIオブジェクトインスタンスでJavaを使用する場合と同様にエンコードする必要があります。


2
素晴らしい、完全な答え、実際の質問に直接答える唯一の人。予約済みセクションは作業が必要な場合があります。たとえば、クエリセクション?はリテラルは問題ありませんが、それ以前は不可能であり、これらのリストに属していないと思います。ああ、そして最後の文字列の代わりに、という意味ですか?@%25%7C
ボブスタイン

1
ありがとう。良い点:%25は例のタイプミスでした。RFC-2396から直接「予約済み」構文の説明に脚注を追加しました。
JasonM1 2013

1
この答えは悪くありません、いくつかの混乱とエラーがあります。最初に、許可されていない文字と予約されている文字(非常に異なるもの)を融合し、「賢明でない」文字と他の許可されていない文字(RFC 3986で削除され、RFC 2396でも構文的に無関係)をあまりに区別しすぎて、混乱を招くようにリストを提示している「クエリコンポーネント内で」予約されたリストとしてすべての予約文字。
Mark Amery

1
ありがとう、許可されていないグループと予約されているグループを同じものとしてグループ化するつもりはありませんでした。回答を更新しました。RFC-2396のIMHOルールは古いものの、3986の更新されたルールよりも理解が簡単です。回答は、許可または許可されているコンテキストではなく、どの文字が一般に問題になるかをより反映しています。
JasonM1 2016

1
最近のリリース(7.0.73 +、8.0.39 +、8.5.7 +)のTomcatが、「unwise」カテゴリの文字を含むリクエストを拒否し、HTTP 400エラー:「リクエストターゲットに無効な文字が見つかりました。有効な文字はRFC 7230およびRFC 3986で定義されています」
Philip

101

ここにある既存の回答のほとんどは、実際のアドレスの使用を完全に無視しているため、実用的ではありません。

最初に、用語への脱線。これらのアドレス何ですか?それらは有効なURLですか?

歴史的には、答えは「ノー」でした。RFC 3986によれば、2005年以降、そのようなアドレスはURIではありません(URL はURIの一種であるため、URLでありません)。2005 IETF標準の用語に従って、RFC 3987で定義されいるように、それらをIRI(Internationalized Resource Identifiers)と適切に呼ぶ必要があります。これらは技術的にはURIではなく、IRI内のすべての非ASCII文字をパーセントエンコードするだけでURIに変換できます。 。

現代の仕様では、答えは「はい」です。WHATWG生活水準は、単に以前に「URLの」として「のURI」または「虹彩」と呼ばれることになるすべてのものを分類します。これにより、仕様の専門用語を、仕様をまだ読んでいない一般の人々が、仕様の目標の 1つである「URL」という言葉をどのように使用するかと一致させます。

WHATWGリビング標準で許可されているキャラクターは何ですか?

「URL」のこの新しい意味によれば、どの文字が許可されますか?そのようなクエリ文字列やパスなどのURLの多くの部分では、我々は、任意の使用を許可している「URL単位」です、

URLコードポイントパーセントエンコードされたバイト

「URLコードポイント」とは?

URLコードポイントのASCII英数字、U + 0021(!)され、U + 0024($)、U + 0026(&)、U + 0027( ')、U + 0028左括弧、U + 0029右括弧、U + 002A(*)、U + 002B(+)、U + 002C(、)、U + 002D(-)、U + 002E(。)、U + 002F(/)、U + 003A(:)、U + 003B (;)、U + 003D(=)、U + 003F(?)、U + 0040(@)、U + 005F(_)、U + 007E(〜)、およびU + 00A0からUの範囲のコードポイント+ 10FFFD(サロゲートと非文字を除く)。

(注「URLのコードポイント」のリストには含まれていないこと%ということが、%パーセントをコードする配列を、彼らがしている部分ならばsは、「URLのコード単位」で許可されています。)

このセットにない文字の使用が仕様で許可されている唯一の場所は、IPv6アドレスがandで囲まれているhostです。URLの他のすべての場所で、URLユニットを許可するか、さらに限定的な文字セットを許可します。[]

古いRFCで許可されていた文字は何ですか?

歴史のために、そしてここでの回答では他の場所では十分に検討されていないので、古い仕様のペアで許可されていたものを調べてみましょう。

まず、2種類のRFC 3986 予約文字があります。

  • :/?#[]@、これはRFC 3986で定義されたURIの一般的な構文の一部です
  • !$&'()*+,;=、これはRFCの一般的な構文の一部ではありませんが、特定のURIスキームの構文コンポーネントとして使用するために予約されています。例えば、セミコロンとコンマは構文の一部として使用されているデータのURIと、&及び=ユビキタスの一部として使用される?foo=bar&qux=baz(クエリ文字列にフォーマットされていない RFC 3986で指定されました)。

上記の予約文字はすべて、エンコードなしのURIで合法的に使用できます。これは、構文上の目的に使用するか、そのような使用が構文上の目的に使用される文字と誤解されない場所でデータ内のリテラル文字として使用できます。(たとえば/、URLには構文上の意味がありますが、クエリ文字列には意味がないため、クエリ文字列ではエンコードせずに使用できます。)

RFC 3986はまた、いくつかの指定予約されていない、常にエンコードせずにデータを表現するために、単純に使用できる文字を、:

  • abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~

最後に、%文字自体はパーセントエンコーディングが許可されています。

葉のみ、以下のASCII文字という禁断の URLに表示されてから:

  • 改行、タブ、キャリッジリターンなどの制御文字(文字0〜1Fおよび7F)。
  • "<>\^`{|}

ASCIIの他のすべての文字は、URLで合法的に機能できます。

次に、RFC 3987は、予約されていない文字のセットを次のUnicode文字範囲で拡張します。

  %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD

古い仕様からのこれらのブロックの選択は、最新のUnicode ブロック定義を考えると、奇妙で​​恣意的なようです。これはおそらく、RFC 3987が作成されてから10年でブロックが追加されたためです。


最後に、URLに合法的に表示できる文字を知るだけでは、特定の文字列が合法的なURLであるかどうかを認識するだけでは十分ではないことに注意してください。たとえば、予約文字[]は、http:// [1080 :: 8:800:200C:417A] / fooのようなURLのIPv6リテラルホストの一部としては有効ですが、他のコンテキストでは無効です。 OPの例http://example.com/file[/].htmlは違法です。


3
完全な参照(RFCなど)のplusone
Yan Foto

19

補足的な質問www.example.com/file[/].htmlで、有効なURL かどうかを尋ねました。

URLはURIの一種であり、有効なURIにはhttp:RFC 3986を参照)のようなスキームが必要であるため、そのURLは無効です。

http://www.example.com/file[/].htmlが有効なURL かどうかを確認するつもりなら、角かっこ文字は有効ではないため、答えはまだノーです。

角かっこ文字は、次の形式のURL用に予約されていますhttp://[2001:db8:85a3::8a2e:370:7334]/foo/bar(ホスト名ではなくIPv6リテラル)。

問題を完全に理解したい場合は、RFC 3986を注意深く読む価値があります。


RFCを読んだ後、@ Stephen Cのより詳細な説明に同意する傾向があります。
skolima

URLはURIのサブセットではありません。[そして]、私が見てきたほとんどのパーサーのための有効なURIではありません。これは実際に現実の世界で私をねじ込みました:stackoverflow.com/questions/11038967/...
アダム・ゲント

@AdamGent URLは、URIのサブセットです。それらの唯一の違いは、それらがリソースの場所を記述しているかどうかです。これは、構文上の違いではなく、意味上の違いです。「URI」パーサーとしてラベル付けされたパーサーが角括弧を「URL」パーサーとしてラベル付けされたパーサーと異なる方法で処理した場合、それは単なる偶然であり、URLとURIの違いによるものではありません。
Mark Amery

@Mark Ameryこれは、C ++がCのスーパーセットであると言っていることに類似しています。(URLとC)ははるかに古く、それほど厳密ではない動作を含める必要があるため、ほとんどの場合完全ではありません。問題は、URLパーサーが有効なURIではないものを解析することです...そして、それらのほとんどを意味します(率直に言って、非常に多くの言語でこれを指摘することにうんざりしています)下位互換性は偶然ではありません。URL仕様が少なくとも古いことに同意できますか?
アダム・ゲント

@MarkAmeryこれは、Python、C#、Java、および一部のCライブラリからのもので、パーサーはUnwiseURIに対して非常に真剣に取り組んでいますが、URLライブラリでは問題ありません。つまり、無視するフラグはありませんUnwise。URLについて、Rustのlangを確認する必要があります(ブラウザー用に構築されているため、何をするか知りたいです)。ただし、ほとんどのブラウザは「[」、「]」も問題なく通過します。したがって、理論的にはC / C ++で言ったように、それらはサブ/スーパーですが、現実はそれほど正確ではありません。スーパー/サブセットの仕様とセマンティクスの解釈に大きく依存します。
アダム・ゲント

12

URI(URLURIの一種です)で使用できるすべての有効な文字は、RFC 3986で定義されています

他のすべての文字は、最初に「URLエンコード」されていれば、URLで使用できます。これには、特定の「コード」の無効な文字の変更が含まれます(通常、パーセント記号(%)の後に16進数が続く形式です)。

このHTML HTMLエンコーディングリファレンスリンクには、無効な文字のエンコーディングのリストが含まれています。


また、Unicode文字については、Wikipediaの記事Percent-encodingで次のように述べています。「一般的なURI構文では、URI内の文字データの表現を提供する新しいURIスキームは、事実上、翻訳なしで予約されていないセットの文字を表す必要があります。他のすべての文字をUTF-8に従ってバイトに変換し、それらの値をパーセントエンコードする必要があります。」
DavidRR

9

いくつかのUnicode文字範囲は有効なHTML5ですが、それらを使用することはまだお勧めできません。

たとえば、hrefドキュメントはhttp://www.w3.org/TR/html5/links.html#attr-hyperlink-hrefと言います

aおよびarea要素のhref属性には、スペースで囲まれている可能性のある有効なURLの値が必要です。

次に、「有効なURL」の定義はhttp://url.spec.whatwg.org/を指し、次のことを目的としています。

RFC 3986とRFC 3987を最新の実装に合わせて、プロセスで廃止します。

このドキュメントでは、URLコードポイントを次のように定義しています

ASCII英数字、「!」、「$」、「&」、「 '」、「(」、「)」、「*」、「+」、「、」、「-」、「。」、「/」 、「:」、「;」、「=」、「?」、「@」、「_」、「〜」、およびU + 00A0〜U + D7FF、U + E000〜U + FDCFの範囲のコードポイント、U + FDF​​0〜U + FFFD、U + 10000〜U + 1FFFD、U + 20000〜U + 2FFFD、U + 30000〜U + 3FFFD、U + 40000〜U + 4FFFD、U + 50000〜U + 5FFFD、U +60000からU + 6FFFD、U + 70000からU + 7FFFD、U + 80000からU + 8FFFD、U + 90000からU + 9FFFD、U + A0000からU + AFFFD、U + B0000からU + BFFFD、U + C0000 U + CFFFD、U + D0000からU + DFFFD、U + E1000からU + EFFFD、U + F0000からU + FFFFD、U + 100000からU + 10FFFD。

次に、「URLコードポイント」という用語がステートメントで使用されます。

cがURLコードポイントではなく、「%」でもない場合、解析エラー。

スキーマ、権限、相対パス、クエリ、フラグメントの状態など、解析アルゴリズムのいくつかの部分で:基本的にURL全体です。

また、バリデータhttp://validator.w3.org/はのような"你好"URLに対してはパスし、スペースのような文字を含むURLに対してはパスしません"a b"

もちろん、Stephen Cが述べたように、それは文字だけでなくコンテキストについてもです。アルゴリズム全体を理解する必要があります。ただし、クラスの「URLコードポイント」はアルゴリズムの重要なポイントで使用されるため、何を使用できるか、または使用できないかについての良いアイデアが得られます。

参照:URLのUnicode文字


5

文字列でURLを分割する文字を選択する必要があるので、URLで自分で見つけることができない文字のリストを作成することにしました。

>>> allowed = "-_.~!*'();:@&=+$,/?%#[]?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
>>> from string import printable
>>> ''.join(set(printable).difference(set(allowed)))
'`" <\x0b\n\r\x0c\\\t{^}|>'

したがって、可能な選択肢は、改行、タブ、スペース、バックスラッシュ、および"<>{}^|です。私はスペースか改行で行くと思います。:)


2

本当にあなたの質問への答えではありませんが、URLの検証は本当に深刻なピタですドメイン名を検証し、URLのクエリ部分を残す方が良いでしょう。それが私の経験です。また、URLにpingを送信して有効な応答が得られるかどうかを確認することもできますが、そのような単純なタスクには多すぎる可能性があります。

URLを検出するための正規表現は豊富ですが、それをググってください:)



この回答は、URL検証が正規表現ではなく、言語/プラットフォーム固有のライブラリの仕事であることを示しています
DavidRR

0

古いhttp(0.9、1.0、1.1)リクエストとレスポンスのリーダー/ライターを実装しています。リクエストURIは最も問題の多い場所です。

RFC 1738、2396、または3986をそのまま使用することはできません。より多くの文字を許可する多くの古いHTTPクライアントとサーバーがあります。そこで、誤って公開されたウェブサーバーアクセスログに基づいて調査を行いました"GET URI HTTP/1.0" 200

以下の非標準文字がURIでよく使用されることがわかりました。

\ { } < > | ` ^ "

これらの文字は、RFC 1738安全でないと説明されています

すべての古いHTTPクライアントおよびサーバーと互換性を持たせる場合は、リクエストURIでこれらの文字許可する必要があります。

この研究の詳細については、http-ogをご覧ください。


-4

テキストのURLをアンカータグに変換するPHPの正規表現をいくつか思いつきました。(最初にすべてのwww。urlをhttp://に変換し、次にhttps?://を含むすべてのURLをhref = ... htmlリンクに変換します

$string = preg_replace('/(https?:\/\/)([!#$&-;=?\-\[\]_a-z~%]+)/sim', '<a href="$1$2">$2</a>', preg_replace('/(\s)((www\.)([!#$&-;=?\-\[\]_a-z~%]+))/sim', '$1http://$2', $string) );


4
-1; どちらもURLがある程度関与しているという事実を除けば、これは、尋ねられた質問とは関係ありません。
マークアメリー2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.