개발자 도구 · URL 인코더 및 디코더
이중 URL 인코딩: %2520 발생 방법 및 이를 감지하고 실행 취소하는 방법
· 작동 방식
URL 인코딩 자바스크립트 개발자 워크플로 디버깅
URL의 %2520은 공백이 두 번 인코딩되었음을 의미합니다. 이 게시물에서는 이를 유발하는 파이프라인 실수, 서명을 인식하는 방법, 안전한 디코드 패스 수에 대해 설명합니다.
이중 URL 인코딩: %2520은 공백이 두 개의 인코더를 통과했음을 의미하는 경우
"my file.pdf" 대신 "my%20file.pdf"로 도착하는 파일 이름은 이중 인코딩을 나타냅니다. 공백이 %20로 인코딩된 다음 백분율 기호 자체가 %25로 인코딩되어 최종 URL에 %2520가 생성됩니다. 클라이언트 코드, 웹 프레임워크 또는 역방향 프록시와 같은 시스템의 각 계층은 한 번 인코딩될 수 있습니다. 두 개의 개별 레이어를 인코딩하면 단일 문자가 손상됩니다.
이중 인코딩은 복잡한 리디렉션 체인 및 템플릿 시스템에서 가장 자주 나타납니다. 개발자는 기본적으로 모든 출력을 자체적으로 인코딩하는 프레임워크 내에서 인코딩된 URL을 생성할 수 있습니다. 역방향 프록시 또는 콘텐츠 전달 네트워크는 백엔드 시스템에서 이미 인코딩되어 도착한 URL을 다시 인코딩할 수 있습니다. 이미 인코딩된 값이 포함된 매개변수는 다른 URL 구조 내에 중첩되기 전에 다시 인코딩됩니다.
%25이 중요한 이유 — 백분율 기호 자체가 인코딩되므로 %20은(는) %2520(이)가 되고 %C3%A9(이)는 %25C3%25A9가 됩니다.
이중 인코딩의 숨길 수 없는 기호는 일반적으로 URL이나 데이터에서 단일 퍼센트 기호를 볼 것으로 예상되는 위치에 나타나는 %25입니다. 일반적으로 인코딩된 URL에서는 리터럴 "%25"를 전송하지 않으면 %25이 표시되지 않습니다. %20로 인코딩된 공백을 다시 인코딩하면 %2520가 됩니다.
일반적으로 %C3%A9로 인코딩되는 é와 같은 악센트 문자는 서로 다른 두 시스템에서 순서대로 두 번 인코딩되면 %25C3%25A9가 됩니다. URL 표시줄, 로그 및 오류 메시지에서 %25 패턴을 찾아내는 방법을 배우면 데이터가 여러 서비스를 통해 흐르는 프로덕션 환경에서 수많은 디버깅 작업 시간을 절약할 수 있습니다.
이중 인코딩이 도입되는 경우 — 클라이언트 코드와 프레임워크, 리디렉션, 프록시 및 템플릿 도우미
이중 인코딩은 가독성과 서버 측 시스템이 URL을 올바르게 구문 분석하는 기능을 모두 파괴합니다. "my file.pdf"라는 파일은 올바르게 인코딩되면 "my%20file.pdf"가 됩니다. 인코딩된 문자열이 양식을 통해 다시 인코딩되면 "my%2520file.pdf"가 됩니다.
서버가 이를 수신하고 한 번 디코딩하면 "my file.pdf"로 인식하지 않고 "my%20file.pdf"를 리터럴 파일 이름으로 간주합니다. 단일 디코드 패스만 수신할 것으로 예상하는 모든 애플리케이션은 잘못된 결과를 받게 됩니다. 더 나쁜 것은, 한 번만 인코딩된 값의 문제를 해결하기 위해 두 번 디코딩하는 개발자가 실제로 추가 디코드 패스를 통해 합법적인 데이터를 손상시킬 수 있다는 것입니다.
실제 예: 이중으로 인코딩된 URL을 한 번에 한 패스씩 디코딩합니다. 각 패스가 공개하는 내용과 중지 시기
클라이언트측 JavaScript 코드 및 서버측 프레임워크 기본값은 프로덕션 시스템에서 실수로 이중 인코딩을 발생시키는 가장 일반적인 소스입니다. JavaScript 애플리케이션은 값에 대해 encodeURIComponent를 사용한 다음 기본적으로 모든 문자열 출력을 인코딩하는 프레임워크에 직접 전달하여 백분율 기호를 두 번째로 인코딩할 수 있습니다. URL을 삭제하기 위한 역방향 프록시 계층은 백엔드 애플리케이션에서 이미 사전 인코딩된 매개변수를 다시 인코딩할 수 있습니다.
사용자 제공 입력을 프레임워크 도우미 함수와 연결하여 구축된 리디렉션 URL은 두 단계에서 동시에 인코딩할 수 있습니다. 실제 예: 사용자가 HTML 형식을 통해 "test&value"를 제출하면 브라우저는 이를 "test%26value"로 인코딩합니다. 프레임워크는 리터럴 백분율 텍스트를 보고 이를 인코딩하여 "test%2526value"를 생성합니다. 한 번의 디코드는 "test%26value"를 제공하지만 여전히 잘못된 것입니다.
이중 인코딩이 의도적인 경우 — 다른 URL의 쿼리 매개변수 내에 포함된 URL
의도적인 이중 인코딩은 특정 경우, 즉 URL이 다른 URL의 쿼리 매개변수 내부로 이동해야 하는 경우에 유효합니다. OAuth 흐름과 로그인 복귀 링크는 때때로 하나의 완전한 URL을 다른 URL 안에 중첩해야 합니다. 내부 URL은 먼저 완전히 퍼센트 인코딩되어야 하며, 전체 인코딩된 문자열은 외부 URL에 대한 매개변수 값으로 다시 인코딩되어야 합니다.
이 이중 인코딩은 의도적이며 이러한 경우에 절대적으로 필요합니다. 외부 매개변수 파서는 한 번 디코딩되어 여전히 인코딩된 내부 URL을 생성합니다. 그러면 내부 시스템이 다시 디코딩하여 원래 URL을 복구합니다. 중요한 핵심은 의도를 이해하고 향후 유지 관리 담당자를 위해 코드 주석에 이를 명확하게 문서화하는 것입니다.
일반적인 실수 - 아무것도 변경되지 않을 때까지 디코딩하여 합법적으로 %25을(를) 포함하는 값을 손상시킵니다.
고전적이고 위험한 실수는 아무것도 변경되지 않을 때까지 반복적으로 디코딩하여 실제 데이터에 합법적으로 백분율 기호가 포함된 값을 손상시키는 것입니다. "discount%2525"(매개변수 값으로 인코딩된 다음 전송을 위해 다시 인코딩된 리터럴 "%25"을 나타냄)와 같은 매개변수는 의도적으로 완전히 정확합니다. 한 번 디코딩하면 "discount%25"가 생성되는데 이는 여전히 정확합니다. 두 번째로 디코딩하면 "discount%"가 생성되는데, 이는 잘못된 것이며 정보가 손실됩니다.
개발자는 "%25"이(가) 실수라고 가정하고 반복적으로 디코딩하여 백분율 기호를 잃을 수 있습니다. 대신, 아키텍처가 요구하는 만큼 정확하게 디코딩하십시오. 매개변수에 대해 한 번, 중첩에 대해 두 번. 레이어 수를 세어 올바른 디코드 작업을 알아보세요.
여기서 다루지 않는 내용 — HTML 엔터티 이스케이퍼가 처리하는 URL 위에 계층화된 HTML 엔터티 인코딩
일반적인 실수에는 encodeURIComponent를 사용하여 전체 URL을 인코딩한 다음 슬래시와 콜론이 인코딩 후에는 구조적 구분 기호로 작동할 것으로 기대하는 것이 포함됩니다. 또 다른 빈번한 오류는 서로 다른 인코딩 표준을 혼합하는 것입니다. 일부 코드는 RFC 3986에 따른 백분율 인코딩을 사용하고 다른 코드는 공백을 나타내는 더하기 기호가 있는 양식 인코딩을 사용합니다. "my+file"과 같은 값은 실제로 모호해집니다. "내 파일"을 의미할 수도 있고 플러스가 있는 리터럴 텍스트 "my+file"을 의미할 수도 있습니다.
퍼센트 인코딩이 "my+file"에 먼저 닿으면 "my%2Bfile"이 됩니다. 양식 디코딩이 뒤따라 플러스를 공백으로 예상하면 잘못된 상태로 유지됩니다. 레이어 간 일관성은 필수적입니다. 모든 시스템은 동일한 인코딩 표준을 사용해야 하며, 그렇지 않으면 각 레이어를 명시적으로 문서화해야 합니다.
요점: 레이어당 정확히 한 번씩 인코딩 — URL 인코더 및 디코더를 사용하여 한 번에 하나의 패스를 디코딩하고 각 중간 결과를 확인하는 방법
프로덕션 시스템에서 발생하는 이중 인코딩을 성공적으로 식별한 후에는 파이프라인에서 중복이 발생하는 위치에 따라 수정 방법이 전적으로 달라집니다. 클라이언트 코드와 프레임워크가 모두 인코딩되는 경우 둘 중 하나에서 인코딩을 완전히 제거하세요. 매개변수가 여러 백엔드 서비스를 통해 이동하는 경우 각 서비스를 통해 전체 경로를 추적하고 인코딩해서는 안 되는 서비스가 무엇인지 찾습니다.
전체 종단 간 파이프라인을 통해 샘플 데이터를 전달하여 수정 사항을 철저하게 테스트하고 데이터가 대상에 완전히 변경되지 않은 상태로 도착하는지 확인합니다. 각 경계에서 인코딩 가정을 명확하게 문서화하십시오. "이 끝점은 백분율로 인코딩된 매개변수를 반환합니다." 또는 "이 미들웨어는 원시 UTF-8을 예상하고 여기에 인코딩을 적용합니다." 향후 개발자를 위해 해당 문서에 예상되는 디코드 패스 수를 포함하세요.