어떤 문자가 URL을 유효하지 않게합니까?


515

어떤 문자가 URL을 유효하지 않게합니까?

유효한 URL입니까?

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

42
유효성을 검사 할 때는 항상 "긍정적 인 생각"을해야합니다. "무엇이 유효합니까?" 유효하지 않은 모든 문자에 대해 테스트하는 것이 유효하지 않은 모든 문자보다 훨씬 안전하고 쉽습니다!
mfx 2009

답변:


600

RFC 3986 ( 섹션 2 : 문자 참조)에 정의 된 일반적인 URI 에는 다음 84 자 중 하나가 포함될 수 있습니다.

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

이 목록에는 URI에서 이러한 문자가 발생할 수있는 위치가 나와 있지 않습니다.

다른 문자는 퍼센트 인코딩 ( %hh) 으로 인코딩해야합니다 . URI의 각 부분에는 퍼센트 인코딩 된 단어로 표현해야하는 문자에 대한 추가 제한 사항이 있습니다.


31
(물론, 캐릭터의 목록은 그들이 어디 에서 일어날 수 있는지
말하지

75
전체 문자열에 위의 문자 만 포함되어 있는지 확인하는 정규식은 다음과 같습니다. / ^ [! # $ &-; =?-[] _ a-z ~] + $ /
Leif Wickland

43
@techiferous, 예, "%"이스케이프 문자를 허용하는 것을 잊었습니다. 좀 더 생생하게 보일 것입니다. /^([!#$&-;=?-[]_a-z~]|%[0-9a-fA-F]{2})+$/ 수락해야 할 것이 더 있습니까? (정확히
말해서

12
@Timwi RFC 3986은 "백분율로 인코딩 된 옥텟은 퍼센트 문자"% "와 그 옥텟의 숫자 값을 나타내는 두 개의 16 진수로 구성된 문자 삼중 항으로 인코딩된다"고 말했다. 또한 "백분율 ("% ") 문자는 퍼센트로 인코딩 된 옥텟에 대한 표시기 역할을하므로 해당 옥텟을 URI 내에서 데이터로 사용하려면 퍼센트로 인코딩되어"% 25 "로 표시되어야합니다." "%"는 두 개의 16 진수가 뒤에 오는 경우에만 나타날 수 있다는 것을 읽었습니다. 어떻게 읽습니까?
Leif Wickland

13
@Weeble 내 정규 표현식에는 범위를 사용하여 해당 문자가 포함되었습니다. 와 ~ 사이에있는 ';' 그리고 '?'사이 그리고 '['당신은 당신이 보지 못한 모든 문자를 찾을 수 있습니다.
Leif Wickland

193

설명을 추가하고 위의 질문을 직접 해결하기 위해 URL과 URI에 문제를 일으키는 여러 클래스의 문자가 있습니다.

허용되지 않으며 URL / URI, 예약 문자 (아래 설명) 및 경우에 따라 문제가 발생할 수 있지만 "불명확 한"또는 "안전하지 않은"문자로 표시되어서는 안되는 문자가 있습니다. 문자가 제한되는 이유에 대한 설명은 RFC-1738 (URL) 및 RFC-2396 (URI) 에서 명확하게 설명되어 있습니다. 최신 RFC-3986 (RFC-1738로 업데이트)은 주어진 컨텍스트에서 허용되는 문자 구성을 정의하지만 이전 사양은 다음 규칙에 따라 허용되지 않는 문자에 대한보다 간단하고 일반적인 설명을 제공합니다.

URI 구문에서 허용되지 않는 US-ASCII 문자는 제외했습니다.

   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의 문자 제한 중 일부는 프로그래밍 언어에 따라 다릅니다. 예를 들어, '|' URI 스펙에서 "unwise"로만 표시되었지만 (0x7C) 문자 는 Java java.net.URI 생성자 에서 URISyntaxException 을 발생 시키므로 URI와 같은 URL 은 허용되지 않으며 마치 URI 오브젝트 인스턴스에 Java를 사용 하는 것처럼 인코딩되어야 합니다.http://api.google.com/q?exp=a|bhttp://api.google.com/q?exp=a%7Cb


2
훌륭하고 철저한 답변. 실제 질문에 직접 대답하는 유일한 사람. 예약 섹션에는 작업이 필요할 수 있습니다. 예를 들어 리터럴 ?은 쿼리 섹션 에서 훌륭 하지만 그 전에는 불가능하므로 @이러한 목록에 속하지 않는다고 생각 합니다. 아, 그리고 %25마지막 문자열 대신에 , 당신은 의미하지 %7C않습니까?
Bob Stein

1
감사. 잘 잡기 : 예제에서 % 25는 오타였습니다. RFC-2396에서 직접 "예약 된"구문 설명에 각주를 추가했습니다.
JasonM1

1
이 답변은 나쁘지 않지만 혼란과 오류가 있습니다. 처음에는 허용되지 않는 문자와 예약 된 문자 (매우 다른 것)를 혼동하고 "현명하지 않은"문자와 다른 허용되지 않은 문자 (RFC 3986에서 삭제하고 RFC 2396에서도 구문 적으로 관련이 없음)를 너무 많이 구분하고 혼동하여 "쿼리 구성 요소 내에" 예약 된 모든 예약 문자 .
Mark Amery

1
감사합니다. 허용되지 않는 것과 예약 된 것을 동일하게 그룹화하지는 않았습니다. 답변을 업데이트했습니다. RFC-2396의 IMHO 규칙은 이전 버전이지만 3986의 업데이트 된 규칙보다 이해하기가 더 간단합니다. 답변은 허용 된 컨텍스트와 허용되지 않은 컨텍스트가 아니라 일반적으로 문제가있는 문자에 대한 답을 더 많이 반영합니다.
JasonM1

1
최근 릴리스 (7.0.73+, 8.0.39+, 8.5.7+)의 Tomcat이 HTTP 400 오류와 함께 "unwise"범주의 문자로 요청을 거부하기 시작했습니다. "요청 대상에 잘못된 문자가 있습니다. 유효한 문자는 RFC 7230 및 RFC 3986 "에 정의되어 있습니다.
Philip

101

여기에있는 기존 답변의 대부분은 다음과 같은 실제 주소 사용을 완전히 무시하기 때문에 비실용적입니다.

첫째, 용어로의 탈선. 이 주소 무엇입니까 ? 유효한 URL입니까?

역사적으로 대답은 "아니오"였습니다. 에 따르면RFC 3986 2005 년부터 이러한 주소는 URI가 아니므로 URL 이 URI의 유형 이므로 URL 아닙니다 . 2005 IETF 표준의 용어에 따라 RFC 3987에 정의 된 대로 IRI (Internationalized Resource Identifiers)를 적절하게 호출해야합니다. RFC 3987 은 기술적으로 URI가 아니지만 IRI에서 ASCII가 아닌 모든 문자를 퍼센트 인코딩하여 간단히 URI로 변환 할 수 있습니다. .

현대의 사양에 따라 대답은 "예"입니다. 그만큼WHATWG 생활 수준은 단순히 이전에 "URL을"로 "URI를"또는 "아이리스"라는 것 모든 것을 분류한다. 이는 스펙을 읽지 않은 일반 사람들이 스펙의 목표 중 하나 인 "URL"이라는 단어를 사용하는 방식과 스펙 용어를 정렬합니다 .

WHATWG 생활 표준에 따라 어떤 문자가 허용됩니까?

"URL"의이 새로운 의미에 따라 어떤 문자가 허용됩니까? 쿼리 문자열 및 경로와 같은 URL의 많은 부분에서 임의의 것을 사용할 수 있습니다. "URL 단위" 를 사용할 수 있습니다.

URL 코드 포인트 퍼센트 인코딩 된 바이트 .

"URL 코드 포인트"란 무엇입니까?

URL 코드 포인트 + 0,021 U (!) + 0024 U ($) + 0026 U () + 0027 U ( '), U + 0028 LEFT PARENTHESIS, U + 0029 RIGHT PARENTHESIS, U +, ASCII의 영숫자 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 코드 포인트"의 목록에 포함되지 않습니다 %,하지만% 의는 "URL 코드 단위"에서 허용되는 경우 그들이 퍼센트 인코딩 시퀀스의있는 거 부분.)

스펙 이이 세트에 없는 문자의 사용을 허용하는 유일한 장소 는 IPv6 주소 와 문자 로 묶인 호스트 입니다. URL의 다른 곳에서는 URL 단위 또는 더 제한적인 문자 집합이 허용됩니다.[]

이전 RFC에서 어떤 문자가 허용 되었습니까?

역사를 위해서, 그리고 여기에 대한 답변의 다른 곳에서 완전히 탐구되지 않았으므로, 더 오래된 사양 쌍에서 검사가 허용되었습니다.

우선, 두 가지 유형의 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은 예약되지 않은 문자 세트를 다음과 같은 유니 코드 문자 범위로 확장합니다.

  %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

구 스펙에서 이러한 블록 선택은 최신 유니 코드 블록 정의를 고려할 때 기괴하고 임의적입니다 . RFC 3987이 작성된 이후 10 년 동안 블록이 추가 되었기 때문일 수 있습니다.


마지막으로, 어떤 문자가 URL의 특정 부분에서만 유효한 것이기 때문에, 어떤 문자가 URL에 합법적으로 나타날 수 있는지 아는 것만으로는 주어진 문자열이 유효한 URL인지 아닌지를 인식하기에 충분하지 않다는 점에 주목할 가치가 있습니다. 예를 들어, 예약 문자 [와는 ]합법적 같은 URL에서의 IPv6 리터럴 호스트의 일환으로 / foo는 HTTP : // [417A 1080 :: 8 : 800 : 200C] 그렇게하지만, 다른 상황에서 불법이다 OP의 예 http://example.com/file[/].html는 불법입니다.


3
철저한 참조를위한 plusone (예 : RFC)
Yan Foto

19

보충 질문 www.example.com/file[/].html에서 유효한 URL 인지 물었습니다 .

URL이 URI 유형이고 유효한 URI와 같은 체계가 있어야하므로 해당 URL이 유효하지 않습니다 http:( RFC 3986 참조 ).

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 수 없습니다. 이것은 실제로 현실 세계에서 나를
Adam Gent

@AdamGent URL은 URI의 하위 집합입니다. 그들 사이의 유일한 차이점은 그들이 자원의 위치를 ​​기술하는지의 여부입니다-이것은 구문상의 것이 아닌 의미상의 구별입니다. "URI"로 레이블이 지정된 파서가 자신을 "URL"파서로 레이블이 지정된 파서와 다르게 대괄호를 처리 한 경우 URL과 URI의 차이로 인한 것이 아니라 순수한 우연의 일치입니다.
Mark Amery

@Mark Amery C ++이 C의 수퍼 셋이라고 말하는 것과 비슷합니다. URL과 C가 훨씬 나이가 많기 때문에 덜 엄격한 행동을 포함해야하기 때문에 대부분은 아니지만 완전히 사실이 아닙니다. 문제는 URL 파서가 유효하지 않은 URI를 구문 분석한다는 것입니다 ... 그리고 나는 대부분의 것을 의미합니다 (솔직히 말해서 많은 언어에서 이것을 지적하는 데 너무 피곤합니다) 그것은 이전 버전과의 호환성입니다. URL 사양이 오래되었다는 데 동의 할 수 있습니까?
Adam Gent

@MarkAmery Python, C #, Java 및 일부 C 라이브러리에서 파서는 UnwiseURI에 대해 매우 심각하게 생각하지만 URL 라이브러리에는 적합합니다. 그것은 무시할 플래그가 없다는 것입니다 Unwise. URL에 대해 Rust lang이 무엇인지 확인해야합니다 (브라우저 용으로 제작되었으므로 궁금합니다). 그러나 대부분의 브라우저는 "[", "]"를 행복하게 전달합니다. 그래서 이론적으로 C / C ++로 말한 것처럼 하위 / 슈퍼이지만 현실은 그렇게 사실이 아닙니다. 그것은 수퍼 / 서브셋의 사양과 의미의 해석에 크게 의존한다.
Adam Gent

12

URI에서 사용할 수있는 모든 유효한 문자 ( URLURI 유형 임 )는 RFC 3986에 정의되어 있습니다.

다른 모든 문자는 먼저 "URL 인코딩"인 경우 URL에 사용될 수 있습니다. 여기에는 특정 "코드"에 대한 유효하지 않은 문자 (일반적으로 퍼센트 기호 (%)와 16 진수)가 변경됩니다.

HTML URL 인코딩 참조 링크 에는 유효하지 않은 문자에 대한 인코딩 목록이 포함되어 있습니다.


그리고 유니 코드 문자의 경우 위키 백과 기사 Percent-encoding 은 다음과 같이 말합니다. UTF-8에 따라 다른 모든 문자를 바이트로 변환 한 다음 해당 값을 퍼센트 인코딩해야합니다 . "
DavidRR

9

여러 유니 코드 문자 범위는 유효한 HTML5 이지만 여전히 사용하지 않는 것이 좋습니다.

예를 들어 href문서는 http://www.w3.org/TR/html5/links.html#attr-hyperlink-href 라고 말합니다 .

및 영역 요소의 href 속성은 공백으로 둘러싸 일 수있는 유효한 URL 값을 가져야합니다.

그런 다음 "유효한 URL"의 정의는 http://url.spec.whatwg.org/를 가리키며 이는 다음을 목표로합니다.

RFC 3986 및 RFC 3987을 최신 구현에 맞추고 프로세스에서 사용하지 마십시오.

이 문서는 URL 코드 포인트 를 다음과 같이 정의합니다 .

ASCII 영숫자, "!", "$", "&", " '", "(", ")", "*", "+", ",", "-", ".", "/" , ":", ";", "=", "?", "@", "_", "~"및 U + 00A0 ~ U + D7FF, U + E000 ~ U + FDCF 범위의 코드 포인트 , U + FDF0 ~ 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에 유니 코드 문자


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을 감지하는 정규식은 풍부합니다 .Google :)



이 답변 은 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을 a 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을 포함한다는 사실 외에도 요청 된 질문과 관련이 없습니다.
Mark Amery
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.