오픈소스 NGINX 소프트웨어와 NGINX Plus는 모두 웹 서버, 역방향 프록시, 콘텐츠 캐시로 매우 안전하고 안정적입니다. 승인되지 않은 클라이언트의 접근을 추가적으로 차단하기 위해 보안 링크 모듈 의 지시문을 사용하여 클라이언트가 요청하는 자산의 URL에 특정 해시된 문자열을 포함하도록 요구할 수 있습니다.
이 블로그 게시물에서는 Secure Link 모듈에 구현된 두 가지 방법을 구성하는 방법에 대해 설명합니다. 샘플 구성 스니펫은 HTML 및 미디어 재생 목록 파일을 보호하지만 모든 유형의 HTTP URL에 적용할 수 있습니다. 이러한 방법은 NGINX와 NGINX Plus에 모두 적용되지만, 간략하게 설명하기 위해 블로그의 나머지 부분에서는 NGINX Plus에만 언급하겠습니다.
보안 링크 모듈은 HTTP 요청의 URL에 있는 인코딩된 문자열과 해당 요청에 대해 계산한 문자열을 비교하여 요청된 리소스의 유효성을 확인합니다. 링크의 수명이 제한되어 있고 시간이 만료된 경우, 해당 링크는 오래된 것으로 간주됩니다. 이러한 검사 상태는 $secure_link
변수에 캡처되어 처리 흐름을 제어하는 데 사용됩니다.
언급한 대로, 모듈은 두 가지 방법을 제공합니다. 주어진 http
, 서버
또는 위치
컨텍스트에서는 그 중 하나만 구성할 수 있습니다.
첫 번째이자 더 간단한 모드는 secure_link_secret
지시어를 통해 활성화됩니다. 인코딩된 문자열은 두 개의 텍스트 문자열(URL의 마지막 부분과 NGINX Plus 구성에서 정의된 비밀번호)을 연결하여 계산된 MD5 해시입니다. (첫 번째 텍스트 문자열에 대한 자세한 내용은 기본 보안 URL 사용을 참조하세요.)
보호된 리소스에 액세스하려면 클라이언트가 URL 접두사 바로 뒤에 해시를 포함해야 합니다. 해시는 슬래시가 없는 임의의 문자열입니다. 이 샘플 URL에서 접두사는 videos 이고 보호된 리소스는 파일 bunny.m3u8 입니다.
/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8
이 방법의 한 가지 사용 사례는 사용자가 공유를 위해 서버에 이미지나 문서를 업로드하지만 공식 링크가 게시될 때까지 파일 이름을 아는 사람이 해당 파일에 액세스하는 것을 방지하려는 경우입니다.
두 번째로, 더 유연한 방법은 secure_link
및 secure_link_md5
지침을 통해 가능합니다. 여기서 인코딩된 문자열은 NGINX Plus 구성 파일에 정의된 변수의 MD5 해시입니다. 가장 일반적으로 $remote_addr
변수는 특정 클라이언트 IP 주소에 대한 액세스를 제한하기 위해 포함되지만, 다른 값(예: $http_user_agent )
을 사용할 수도 있습니다. 이 값은 User-Agent
헤더를 캡처하여 특정 브라우저에 대한 액세스를 제한합니다.
해시가 정확하더라도 URL이 더 이상 작동하지 않는 만료 날짜를 지정할 수도 있습니다.
클라이언트는 해시를 지정하기 위해 요청 URL에 md5 인수를 추가해야 합니다. 해시된 문자열에 만료 날짜가 포함되어 있는 경우 클라이언트는 이 보호된 파일 pricelist.html을 요청하는 샘플 URL처럼 만료 인수를 추가하여 날짜를 지정해야 합니다.
/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740
Secure Link 모듈은 nginx.org의 사전 구축된 오픈 소스 NGINX 바이너리 , 운영 체제 공급업체에서 제공하는 NGINX 패키지 및 NGINX Plus 에 포함되어 있습니다. NGINX를 소스에서 빌드하는 경우 기본적으로 포함되지 않습니다. configure
명령에 --with-http_secure_link_module
인수를 포함하여 활성화하세요.
URL을 보호하는 더 기본적인 방법은 secure_link_secret
지시어를 사용하는 것입니다. 다음 샘플 스니펫에서는 /bunny.m3u8 이라는 이름의 HTTP 라이브 스트리밍(HLS) 미디어 재생 목록 파일을 보호합니다. /opt/secure/hls 디렉토리에 저장되지만 videos 접두사로 시작하는 URL을 사용하여 클라이언트에 노출됩니다.
서버 {
listen 80;
server_name secure-link-demo;
location /videos {
secure_link_secret enigma;
if ($secure_link = "") { return 403; }
rewrite ^ /secure/$secure_link;
}
location /secure {
internal;
root /opt;
}
}
이 구성을 사용하면 /opt/secure/hls/bunny.m3u8 파일에 액세스하려면 클라이언트가 다음 URL을 제시해야 합니다.
/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8
해시된 문자열은 접두사 바로 뒤에 옵니다. 접두사는 슬래시가 없는 임의의 문자열입니다(여기서는 videos ).
해시는 두 개의 요소를 연결하는 텍스트 문자열에 대해 계산됩니다.
secure_link_secret
지시어에 대한 매개변수는 enigma
입니다.클라이언트의 요청 URL에 올바른 해시가 없으면 NGINX Plus는 $secure_link
변수를 빈 문자열로 설정합니다. 그 만약에
테스트가 실패하고 NGINX Plus가 다음을 반환합니다. 403
금지됨
HTTP 응답의 상태 코드.
그렇지 않은 경우(해시가 올바르다는 의미) 재작성
지시문은 URL을 재작성합니다. 우리의 예에서는 /secure/hls/bunny.m3u8 입니다( $secure_link
변수는 해시 다음에 오는 URL 부분을 캡처합니다). /secure 로 시작하는 URL은 두 번째 위치
블록에서 처리됩니다. 해당 블록의 루트
지시문은 요청된 파일에 대한 루트 디렉토리로 /opt를 설정하고 내부
지시문은 해당 블록이 내부적으로 생성된 요청에만 사용됨을 지정합니다.
클라이언트가 URL에 포함해야 하는 16진수 형식의 MD5 해시를 얻으려면 -hex
옵션과 함께 openssl
md5
명령을 실행합니다.
# echo -n 'hls/bunny.m3u8enigma' | openssl md5 -hex (stdin)= 80e2dfecb5f54513ad4e2e6217d36fd4
프로그래밍 방식으로 해시를 생성하는 것에 대한 논의는 프로그래밍 방식으로 해시 생성을 참조하세요.
다음 샘플 curl
명령은 서버가 다양한 보안 URL에 어떻게 응답하는지 보여줍니다.
URL에 올바른 MD5 해시가 포함되어 있으면 응답은 다음과 같습니다.200
좋아요
:
# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8 | head -n 1 HTTP/1.1 200 확인
MD5 해시가 올바르지 않으면 응답은 다음과 같습니다.403
금지
:
# curl -I http://secure-link-demo/videos/2c5e80de986b6fc80dd33e16cf824123/hls/bunny.m3u8 | head -n 1 HTTP/1.1 403 금지됨
bunny.m3u8 의 해시가 다른 파일에 사용되는 경우 응답도 다음과 같습니다.403
금지
:
# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hs/oven.m3u8 | head -n 1 HTTP/1.1 403 금지됨
URL을 보호하는 보다 유연한 방법은 secure_link
및 secure_link_md5
지침을 사용하는 것입니다. 이 예에서는 이를 사용하여 IP 주소 192.168.33.14의 클라이언트에서만 /var/www/files/pricelist.html 파일에 접근을 허용하고 2016년 12월 31일까지만 접근을 허용합니다.
가상 서버는 포트 80에서 수신하고 location
/files
블록 아래에서 모든 보안 HTTP 요청을 처리합니다. 여기서 root
지시문은 요청된 파일의 루트 디렉터리를 /var/www 로 설정합니다.
secure_link
지시문은 요청 URL의 인수를 캡처하는 두 개의 변수를 정의합니다. $arg_md5는
md5 인수의 값으로 설정되고, $arg_expires는
expires 인수의 값으로 설정됩니다.
secure_link_md5
지시어는 요청에 대한 MD5 값을 생성하기 위해 해시된 표현식을 정의합니다. URL 처리 중에 해시는 $arg_md5
의 값과 비교됩니다. 여기의 샘플 표현식에는 요청에서 전달된 만료 시간( $secure_link_expires
변수에서 캡처), URL( $uri
), 클라이언트 IP 주소( $remote_addr
) 및 단어 enigma가
포함됩니다.
서버 {
listen 80;
서버 이름 secure-link-demo;
위치 /files {
root /var/www;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr enigma";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
}
이 구성을 사용하면 /var/www/files/pricelist.html 에 액세스하려면 IP 주소가 192.168.33.14인 클라이언트가 2016년 12월 31일 토요일 23:59:00 UTC 전에 이 요청 URL을 보내야 합니다.
/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740
클라이언트가 보낸 URL의 해시( $arg_md5
변수에서 캡처)가 secure_link_md5
지시문에서 계산된 해시와 일치하지 않으면, NGINX Plus는 $secure_link
변수를 빈 문자열로 설정합니다. if
테스트가 실패하고 NGINX Plus가 다음을 반환합니다.403
HTTP 응답의 금지된
상태 코드입니다.
해시가 일치하지만 링크가 만료된 경우 NGINX Plus는 다음을 설정합니다. $보안 링크
변수에 0
; 다시 만약에
테스트는 실패했지만 이번에는 NGINX Plus가 다음을 반환합니다. 410
다 쓴
HTTP 응답의 상태 코드.
이제 클라이언트가 URL에 포함할 md5 및 만료 인수를 어떻게 계산하는지 살펴보겠습니다.
첫 번째 단계는 만료 날짜의 Unix 시간 환산값을 결정하는 것입니다. 해당 값은 $secure_link_expires
변수의 형태로 해시된 표현식에 포함되기 때문입니다. Unix 시간(Epoch (1970-01-01 00:00:00 UTC) 이후의 초 수)을 얻으려면 -d
옵션과 +%s
형식 지정자와 함께 date
명령을 사용합니다.
우리의 예에서 만료 시간을 Sat Dec 31 23:59:00 UTC 2016 으로 설정했으므로 명령은 다음과 같습니다.
# 날짜 -d "2016-12-31 23:59" +%s1483228740
클라이언트는 이 값을 요청 URL에 expires=1483228740 인수로 포함시킵니다.
이제 secure_link_md5
지시문에서 정의한 문자열인 $secure_link_expires$uri$remote_addr
enigma
를 세 개의 명령을 통해 실행합니다.
openssl
md5
명령에 -binary
옵션을 사용하면 이진 형식의 MD5 해시가 생성됩니다.openssl
base64
명령은 해시된 값에 Base64 인코딩을 적용합니다.tr
명령은 더하기 기호( +
)를 하이픈( -
)으로, 슬래시( /
)를 밑줄( _
)로 바꾸고 인코딩된 값에서 등호( =
)를 삭제합니다.예를 들어, 전체 명령은 다음과 같습니다.
# echo -n '1483228740/files/pricelist.html192.168.33.14 enigma' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d = AUEnXC7T-Tfv9WLsWbf-mw
클라이언트는 이 값을 요청 URL에 md5=AUEnXC7T-Tfv9WLsWbf-mw 인수로 포함시킵니다.
NGINX Plus 웹 서버가 애플리케이션 서버에서 동적 콘텐츠를 제공하는 경우, NGINX Plus와 애플리케이션 서버는 모두 동일한 보안 URL을 사용해야 합니다. URL의 md5 인수에 대한 해시를 프로그래밍 방식으로 생성할 수 있습니다. 다음 Node.js 함수는 위의 NGINX Plus 구성 조각에 정의된 것과 일치하는 해시를 생성합니다. 만료 시간, URL, 클라이언트 IP 주소, 비밀번호를 인수로 사용하여 Base64로 인코딩된 바이너리 형식 MD5 해시를 반환합니다.
var crypto = require("crypto");
generateSecurePathHash(만료, url, 클라이언트_ip, 비밀) 함수 {
if (!만료 || !url || !클라이언트_ip || !비밀) {
반환 undefined;
}
var input = 만료 + url + 클라이언트_ip + " " + 비밀;
var binaryHash = crypto.createHash("md5").update(입력).digest();
var base64Value = 새 Buffer(binaryHash).toString('base64');
반환 base64Value.replace(/=/g, '').replace(/+/g, '-').replace(///g, '_');
}
현재 예제에 대한 해시를 계산하려면 다음 인수를 전달합니다.
generateSecurePathHash(new Date('12/31/2016 23:59:00').getTime()), '/files/pricelist.html', “192.168.33.14”, "enigma");
다음 샘플 curl
명령은 서버가 보안 URL에 어떻게 응답하는지 보여줍니다.
IP 주소가 192.168.33.14인 클라이언트가 올바른 MD5 해시 및 만료 시간을 포함하는 경우 응답은 다음과 같습니다.200
좋아요
:
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 200 확인
다른 IP 주소를 가진 클라이언트가 동일한 URL을 보내는 경우 응답은 다음과 같습니다.403
금지
:
# curl -I --interface "192.168.33.33" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 403 금지됨
md5 인수의 해시 값이 올바르지 않으면 응답은 다음과 같습니다.403
금지
:
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=qeUNjiY2FTIVMaXUsxG-7w&expires=1483228740' | head -n 1 HTTP/1.1 403 금지됨
URL이 만료된 경우( 만료 인수로 표현된 날짜가 과거인 경우) 응답은 다음과 같습니다.410
다 쓴
:
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=Z2rNva2InyVcRTlhqAkT4Q&expires=1467417540' | head -n 1 HTTP/1.1 410 사라짐
다음은 미디어 자산의 재생 목록과 세그먼트 파일을 보호하는 데 사용되는 만료 날짜가 있는 보안 URL의 또 다른 예입니다.
이전 예제와 다른 점 하나는 $file_name
변수에서 파일 이름을 캡처하여 secure_link_md5 지시문에 전달하면서 재생 목록( .m3u8 파일)과 HLS 세그먼트( .ts 파일)에서 확장자를 제거하기 위해 여기에 맵
구성 블록을 추가
한다는 것입니다. 이는 개별 .ts 세그먼트와 재생 목록에 대한 요청을 보안하는 데 도움이 됩니다.
첫 번째 예제와의 또 다른 차이점은 secure_link_md5
지시문에 $http_user_agent
변수( User-Agent
헤더를 캡처)를 포함하여 특정 웹 브라우저의 클라이언트에 대한 액세스를 제한한다는 것입니다(예를 들어, URL이 Safari에서는 작동하지만 Chrome이나 Firefox에서는 작동하지 않도록 함).
맵 $uri $file_name {
기본값 없음;
"~*/s/(?<name>.*).m3u8" $name;
"~*/s/(?<name>.*).ts" $name;
}
서버 {
수신 80;
서버 이름 보안 링크 데모;
위치 /s {
루트 /opt;
보안 링크 $arg_md5,$arg_expires;
보안 링크 md5 "$secure_link_expires$file_name$http_user_agent enigma";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
}
NGINX의 보안 링크 모듈을 사용하면 URL의 특정 부분을 해시하는 등의 인코딩된 데이터를 추가하여 파일을 무단 액세스로부터 보호할 수 있습니다. 만료 시간을 추가하면 링크의 유효 기간도 제한되어 보안이 더욱 강화됩니다.
NGINX Plus를 사용해보려면 오늘 무료 30일 체험판을 시작하거나 저희에게 연락해 사용 사례에 대해 논의해 보세요.
"이 블로그 게시물에는 더 이상 사용할 수 없거나 더 이상 지원되지 않는 제품이 참조될 수 있습니다. 사용 가능한 F5 NGINX 제품과 솔루션에 대한 최신 정보를 보려면 NGINX 제품군을 살펴보세요. NGINX는 이제 F5의 일부가 되었습니다. 이전의 모든 NGINX.com 링크는 F5.com의 유사한 NGINX 콘텐츠로 리디렉션됩니다."