URL은 웹 자원의 주소이지만, 사실은 잘 정의된 여러 구성요소가 정해진 순서로 조립된 구조체입니다. 그 문법은 RFC 3986이 규정하며, 정확히 이해하면 라우팅·인코딩·보안 문제 대부분이 명료해집니다. 먼저 용어부터 정리하면, URI는 자원을 식별하는 상위 개념이고 URL은 그중 '위치까지 알려주는' 것입니다. 일상에서는 대체로 같은 의미로 씁니다.
다섯 구성요소
RFC 3986의 일반 문법은 scheme://authority/path?query#fragment 입니다. 아래 예시로 각 부분을 짚어 보겠습니다.
https://user:pass@api.example.com:8443/v1/items?sort=asc&page=2#section-3
\___/ \_______/ \_____________/ \__/ \_______/ \_____________/ \_______/
scheme userinfo host port path query fragment
\__________________________/
authority
- scheme(
https): 사용할 프로토콜·해석 규칙. 뒤에:가 붙습니다. - authority:
userinfo@host:port형태. host는 도메인이나 IP, port는 생략 시 스킴 기본값(http=80, https=443)을 씁니다. userinfo(user:pass)는 보안상 URL에 담지 않는 것이 원칙입니다. - path(
/v1/items): 계층적 자원 경로. - query(
sort=asc&page=2):?뒤의 키=값 쌍. 관례상&로 구분합니다. - fragment(
#section-3): 문서 내 위치. 서버로 전송되지 않고 클라이언트에서만 쓰입니다.
퍼센트 인코딩과 문자 집합
URL에는 아무 문자나 넣을 수 없습니다. RFC 3986은 문자를 두 부류로 나눕니다. unreserved 문자(A-Z a-z 0-9 - . _ ~)는 어디서든 그대로 써도 됩니다. reserved 문자(: / ? # [ ] @ ! $ & ' ( ) * + , ; =)는 구분자로서 특별한 의미를 가지므로, 데이터로서 그 문자를 넣으려면 퍼센트 인코딩해야 합니다. 예를 들어 공백은 %20, &는 %26, 한글 '한'은 UTF-8 바이트를 인코딩한 %ED%95%9C이 됩니다.
핵심은 문맥에 따라 인코딩 규칙이 다르다는 점입니다. 같은 /라도 path 구분자로 쓰면 그대로 두지만, 쿼리 값 안에 데이터로 넣으려면 %2F로 인코딩해야 합니다. 그래서 브라우저·언어 표준 라이브러리는 '경로 세그먼트용'과 '쿼리 컴포넌트용' 인코딩 함수를 따로 제공합니다. 잘못된 함수를 쓰면 +(쿼리에서 공백을 뜻하기도 함)나 /가 오해석되는 버그가 생깁니다.
IDN과 punycode
도메인에 비ASCII 문자(한글·한자·이모지 등)를 쓰는 것이 국제화 도메인 이름(IDN) 입니다. 그런데 DNS는 전통적으로 ASCII만 다루므로, 유니코드 도메인은 punycode라는 방식으로 ASCII 표현으로 변환됩니다. 변환된 라벨에는 xn-- 접두사가 붙습니다. 예를 들어 한국.example의 한글 라벨은 xn--3e0b707e처럼 인코딩됩니다. 시각적으로 비슷한 문자를 섞어 가짜 도메인을 만드는 호모그래프 공격의 위험 때문에, 브라우저는 상황에 따라 주소창에 유니코드 대신 punycode를 표시하기도 합니다.
상대 vs 절대, 그리고 정규화
절대 URL은 스킴부터 다 갖춘 완전한 주소이고, 상대 URL(../images/logo.png, ?page=2)은 현재 문서의 기준(base) URL에 대해 해석됩니다. 브라우저는 RFC 3986의 참조 해석(reference resolution) 규칙으로 상대 URL을 절대 URL로 풉니다.
- 정규화(normalization): 겉모습이 다른 URL이 사실 같은 자원을 가리킬 수 있습니다. 스킴·호스트는 대소문자 무시(
HTTP≡http)이고, 기본 포트(:80,:443)는 생략과 같으며,%41은A로 디코딩되고,/a/./b/../c는/a/c로 정리됩니다. - 주의: path의 대소문자와 쿼리 문자열은 서버 구현에 따라 유의미할 수 있어 함부로 정규화하면 안 됩니다.
- 보안:
../를 제대로 처리하지 않으면 경로 탐색(path traversal) 취약점이 되고, 정규화 순서를 착각하면 접근 제어를 우회당할 수 있으므로 신뢰 경계에서 특히 신중해야 합니다.