ヒーロー背景(区切りなし)
ガイドライン

インジェクション - パス・トラバーサル

경로 탐색은 매우 일반적인 또 다른 유형의 인젝션 취약점입니다.이러한 문제는 URI를 생성할 때 (URL, 파일 경로 등) 완전히 확인된 경로가 루트 바깥을 가리키지 않도록 제대로 확인되지 않을 때 발생하는 경향이 있습니다. 의도 경로.

경로 탐색이 실제로 경로 *주입* 취약점으로 간주될 수도 있다는 점을 강조하는 것이 중요합니다.

경로 탐색 취약성의 영향은 탐색이 발생하는 상황과 수행된 전반적인 보안 강화에 따라 크게 달라집니다.먼저 이 취약점의 실제 사례를 통해 어떤 내용을 다루고 있는지 살펴보도록 하겠습니다.

간략한 분석

계약서 또는 구인 제안용 템플릿과 같은 문서를 제공하는 애플리케이션의 엔드포인트를 생각해 보십시오.이러한 파일은 모두 PDF와 같이 애플리케이션에 정적인 파일일 수 있습니다.

이 경우 요청 시 파일을 가져오는 다음과 같은 코드가 있을 수 있습니다.

베이스폴더 = “/var/www/api/문서/”로 설정;
경로 = 기본 폴더 + 요청.params.파일 이름;

반환 파일. 읽기 (경로);

취약점이 어떻게 발생하는지 설명하려면 애플리케이션의 루트가 어디에 있는지도 알아야 합니다. 따라서 이 예시에서는 애플리케이션의 루트가 '/var/www/api/'에 있다고 가정합니다.

애플리케이션이 'filename' 매개변수를 사용한다는 것을 알고 있습니다. 입력의 몇 가지 예와 결과를 살펴보겠습니다.

ファイル名 未解決のパス 解決済みのパス
プライバシー.pdf /var/www/api/documents/Privacy.pdf /var/www/api/documents/Privacy.pdf
../config/prod.config /var/www/api/documents/.../config/prod.config /var/www/api/config/prod.config
.../.../.../etc/shadow /var/www/api/documents/.../.../.../etc/shadow /etc/shadow

'.. /'를 사용하여 파일 시스템을 탐색하는 방법에 주목하세요.이제 PDF가 주로 저장되는 '문서' 폴더에서 'shadow' 파일이 들어 있는 '/etc/' 폴더로 이동할 수 있습니다. Linux에서는 암호 해시가 들어 있습니다.상상할 수 있듯이, 이는 이상적인 방법이 아닙니다.

URL의 트래버설 살펴보기

경로 탐색의 또 다른 변형은 API와 상호 작용하기 위한 URL을 구성할 때 발생할 수 있습니다.다음과 같은 메서드가 포함된 API가 있다고 가정해 보겠습니다.

URLパターン 説明
/api/v1/order/get/{id} 指定されたIDの注文に関する詳細を取得する
/api/v1/order/delete/{id} 特定のIDの注文を削除する

API는 예를 들어 주문에 대한 정보를 가져오려고 할 때 호출할 수 있는 다른 애플리케이션에서 API와 상호 작용합니다.

APIBase를 "https://my.api/api/v1 “로 설정합니다.
OrderAPI = APIBase + “/order/get”으로 설정하세요.

APIURL = OrderAPI+ Request.params.OrderId로 설정합니다.

ret 응답 = http.get (APIURL);

이제 사용자가 제공한 주문 ID에 따라 어떻게 되나요?아래에서 제공된 입력에 따라 호출된 유효 URL을 확인할 수 있습니다.

정규화는 보통 클라이언트 측에서 수행되지 않지만 (가능하기는 하지만), 웹 서버는 요청을 아래와 같은 형식으로 정규화합니다.

注文ID番号 実際に呼び出されたURL
1 /api/v1/order/get/1
1/.../.../削除/1 /api/v1/order/delete/1

두 번째 예제의 입력에서는 ID 번호가 '1'인 주문을 가져오는 대신 delete 메서드를 대신 호출했습니다. 그러면 당연히 주문이 삭제됩니다.

완화

경로 탐색에 대해 논의할 때는 가능한 한 자주 적용할 수 있고 적용해야 하는 간접/방어 기법과 함께 직접적인 완화 방법이 있습니다.먼저 경로를 처리하는 방법을 살펴보겠습니다.

직접 완화

경로를 처리할 때는 경로 확인, 즉 경로 정규화 프로세스와 그 중요성을 이해해야 합니다.

'/var/www/api/documents/.. /.. /.. /와 같은 경로가 있는 경우../etc/shadow'는 비정규 경로에 있습니다.파일 시스템에서 이 경로를 요청하면 '/etc/shadow'로 정규화됩니다.비정규 경로를 열려고 하지 않는 것이 중요합니다.그보다는 먼저 경로를 표준화하고 경로가 의도한 파일이나 폴더만 가리키는지 확인한 다음 읽어야 합니다.

베이스폴더 = “/var/www/api/문서/”로 설정;
경로 = 기본 폴더 + 요청.params.파일 이름;

해결된 경로를 경로로 설정합니다. 해결 (경로);

만약 (!해결된 경로. (기본 폴더) 로 시작)
“기본 폴더 외부에서 읽으려고 했습니다.” 를 반환합니다.
그밖에
반환 파일. 읽기 (해결된 경로);

안티 패턴 - 파일 이름 삭제 시도 중

다음과 같이 하고 싶은 마음이 들 수도 있습니다.


베이스폴더 = “/var/www/api/문서/”로 설정;
경로 = 기본 폴더 + 요청.params.filename.replace (“../”, “”);
...

그러나 이 접근 방식은 반드시 그래야 합니다. 아니 사용되다.경로 처리의 핵심은 항상 표준 경로를 살펴보는 것입니다.

표준 경로가 규칙을 위반하지 않는 한 경로가 궁극적으로 구성되는 방식은 실제로 아무런 차이가 없습니다.이와 같은 경로를 삭제하려고 하면 오류가 발생하기 쉬우며 안전할 수도 없습니다.

액세스 제한

이전 예제에서는 Linux에서 암호 해시가 있는 파일인 '/etc/shadow' 파일을 읽는 방법을 사용했습니다.하지만 애플리케이션이 루트 외부에서 해당 파일이나 다른 파일을 읽을 수 있어야 할 이유는 전혀 없습니다.

컨테이너를 사용하면 이미 많은 위험을 완화하고 있을 것입니다.컨테이너를 강화하기 위한 조치 (루트로 실행하지 않는 등) 를 취하는 것이 중요합니다.웹 프로세스에서 모든 권한을 삭제하고 파일 시스템에 대한 읽기 권한을 꼭 필요한 파일로만 제한하는 것이 좋습니다.

예시

이제 실제 상황을 좀 더 잘 설명하기 위해 다양한 언어로 몇 가지 예를 공유하겠습니다.

C# - 안전하지 않음

전체 경로를 확인하지 않거나 경로의 파일 이름 부분만 사용하도록 하면 코드가 Path Traversal에 취약해집니다.

var 기본 폴더 = “/var/www/앱/문서/”;
var 파일 이름 = “../../../../../../etc/passwd “;

//안전하지 않음: /etc/passwd를 읽습니다.
var 파일 내용 = 파일.ReadAllText (경로. 결합 (기본 폴더, 파일 이름));

C# - 보안 - 표준

이 예제에서는 전체 (절대) 경로를 확인하고 파일 확인 경로가 기본 폴더 내에 있는지 확인하여 Path Traversal을 방지합니다.

var 기본 폴더 = “/var/www/앱/문서/”;
var 파일 이름 = “../../../../../../etc/passwd “;

var 표준 경로 = 경로.getFullPath (Path.Combine (기본 폴더, 파일 이름));

//보안: 지정된 기반 외부에서 읽으려는 모든 시도를 거부합니다.
만약 (!표준 경로. (기본 폴더) 로 시작)
“기본 폴더 외부에서 파일을 읽으려고 합니다.” 를 반환합니다.

var 파일 내용 = 파일.모든 텍스트 읽기 (표준 경로);

C# - 보안 - 파일 이름

이 예제에서는 경로의 파일 이름 부분만 가져와 지정된 폴더 외부로 트래버스하는 것이 불가능하도록 하여 경로 탐사를 방지합니다.

var 기본 폴더 = “/var/www/앱/문서/”;

//다른 하위 폴더로의 탐색을 허용하지 않는 경우에만 사용하세요.
var 파일 이름 = 경로.getFileName (“../../../../../../../../etc/passwd “);

//보안: /var/www/앱/문서/암호를 읽습니다.
var 파일 내용 = 파일.ReadAllText (경로. 결합 (기본 폴더, 파일 이름));

자바 - 안전하지 않음

전체 경로를 확인하지 않거나 경로의 파일 이름 부분만 사용하도록 하면 코드가 Path Traversal에 취약해집니다.

문자열 기본 폴더 = “/var/www/app/문서/”;
문자열 파일 이름 = “../../../../../../etc/passwd “;

//안전하지 않음: /etc/passwd를 읽습니다.
경로 파일 경로 = Paths.get (기본 폴더 + 파일 이름);
목록 <String>줄 = 파일. 모든 줄 읽기 (파일 경로);

자바 - 보안 - 표준

이 예제에서는 전체 (절대) 경로를 확인하고 파일 확인 경로가 기본 폴더 내에 있는지 확인하여 Path Traversal을 방지합니다.

문자열 기본 폴더 = “/var/www/app/문서/”;
문자열 파일 이름 = “../../../../../../etc/passwd “;

//안전하지 않음: /etc/passwd를 읽습니다.
경로 정규화된 경로 = 경로.get (기본 폴더 + 파일 이름). 정규화 ();
만약 (!정규화된 경로. to 문자열 (). (기본 폴더) 로 시작)
{
“루트 외부의 경로를 읽으려고 함”을 반환합니다.
}
그밖에
{
목록 <String>줄 = 파일. 모든 줄 읽기 (정규화된 경로);
}

자바 - 보안 - 파일 이름

이 예제에서는 경로의 파일 이름 부분만 가져와 지정된 폴더 외부로 트래버스하는 것이 불가능하도록 하여 경로 탐사를 방지합니다.

문자열 기본 폴더 = “/var/www/app/문서/”;

//다른 하위 폴더로의 탐색을 허용하지 않는 경우에만 사용하세요.
문자열 파일 이름 = Paths.get (“../../../../../../../etc/passwd “) .getFileName () .toString ();

//보안: /var/www/앱/문서/암호를 읽습니다.
경로 파일 경로 = Paths.get (기본 폴더 + 파일 이름);
목록 <String>줄 = 파일. 모든 줄 읽기 (파일 경로);

자바스크립트 - 안전하지 않음

전체 경로를 확인하지 않거나 경로의 파일 이름 부분만 사용하도록 하면 코드가 Path Traversal에 취약해집니다.

상수 fs = 필수 ('fs');

const 기본 폴더 = “/var/www/app/문서/”;
const 파일 이름 = “../../../../../../etc/passwd “;

//안전하지 않음: /etc/passwd를 읽습니다.
상수 데이터 = fs.ReadFileSync (기본 폴더+파일 이름, 'utf8');

자바스크립트 - 보안 - 표준

이 예제에서는 전체 (절대) 경로를 확인하고 파일 확인 경로가 기본 폴더 내에 있는지 확인하여 Path Traversal을 방지합니다.

상수 fs = 필수 (“fs”);
상수 경로 = 필수 (“경로”);

const 기본 폴더 = “/var/www/app/문서/”;
const 파일 이름 = “../../../../../../etc/passwd “;

const 정규화된 경로 = path.normalize (경로.join (기본 폴더, 파일 이름));

//보안: /var/www/앱/문서/암호를 읽습니다.
상수 데이터 = fs.ReadFileSync (정규화된 경로, 'utf8');

자바 스크립트 - 보안 - 파일 이름

이 예제에서는 경로의 파일 이름 부분만 가져와 지정된 폴더 외부로 트래버스하는 것이 불가능하도록 하여 경로 탐사를 방지합니다.

상수 fs = 필수 (“fs”);
상수 경로 = 필수 (“경로”);

const 기본 폴더 = “/var/www/app/문서/”;
const 파일 이름 = 경로.basename (“../../../../../../../etc/passwd “);

//보안: /var/www/앱/문서/암호를 읽습니다.
상수 데이터 = fs.ReadFileSync (경로.join (기본 폴더, 파일 이름), 'utf8');

파이썬 - 안전하지 않음

전체 경로를 확인하지 않거나 경로의 파일 이름 부분만 사용하도록 하면 코드가 Path Traversal에 취약해집니다.

기본 폴더 = “/var/www/앱/문서/”
파일 이름 = “../../../../../../etc/passwd”

# 안전하지 않음: /etc/passwd를 읽습니다.
파일 내용 = 열기 (기본 폴더 + 파일 이름). 읽기 ()

파이썬 - 시큐어 - 표준

이 예제에서는 전체 (절대) 경로를 확인하고 파일 확인 경로가 기본 폴더 내에 있는지 확인하여 Path Traversal을 방지합니다.

os.path 가져오기

기본 폴더 = “/var/www/앱/문서/”
파일 이름 = “../../../../../../etc/passwd”

정규화된 경로 = os.path.normpath (기본 폴더 + 파일 이름)

# SECURE: 지정된 기본 폴더 외부에서 파일을 읽으려는 모든 시도를 거부합니다.
정규화되지 않은 경우 경로. 시작 위치 (기본 폴더):
반환 “기본 폴더 읽기 시도 중”

# 보안: /var/www/앱/문서/암호를 읽습니다.
파일 내용 = 열기 (정규화된 경로). 읽기 ()

파이썬 - 보안 - 파일 이름

이 예제에서는 경로의 파일 이름 부분만 가져와 지정된 폴더 외부로 트래버스하는 것이 불가능하도록 하여 경로 탐사를 방지합니다.

os.path 가져오기

기본 폴더 = “/var/www/앱/문서/”
파일 이름 = os.path.basename (“../../../../../../../etc/passwd “)

# 보안: /var/www/앱/문서/암호를 읽습니다.
파일내용 = 열기 (os.path.join (기본 폴더, 파일 이름)). 읽기 ()