최신 업데이트:2024-09-03 17:00:38
이 예제에서는 Edge Cloud Apps 함수와 Web Crypto API를 사용하여 특정 웹사이트 리소스에 대한 액세스를 보호하는 방법을 보여줍니다. 실제 예로 http://ecatest.cdnetworks.com/ECA-test/pet-shop-website-template/about.html
에 있는 애완동물 가게의 “회사 소개” 페이지를 사용합니다. 이 페이지에 액세스하려면 HMAC 및 SHA-256 알고리즘을 사용하여 생성된 유효한 서명이 필요합니다. Edge Cloud Apps 함수는 클라이언트를 대신하여 나가는 요청에 서명하거나 들어오는 서명된 요청을 확인하여 보안 게이트키퍼 역할을 할 수 있습니다. 권한이 없는 요청은 오류 페이지로 연결됩니다.
const SECRET_KEY = "my secret symmetric key";
// 요청 메서드에 따라 서명 또는 확인을 수행하는 요청 처리기
async function handleRequest(request) {
if (request.method === "POST") {
return signRequest(request);
} else {
return verifyRequest(request);
}
}
// 요청 서명 확인
async function verifyRequest(request) {
const url = new URL(request.url);
// 요청에 필요한 쿼리 매개변수가 포함되어 있는지 확인합니다.
if (!url.searchParams.has("mac") || !url.searchParams.has("expiry")) {
return failPage("쿼리 매개변수가 누락되었습니다.");
}
const encoder = new TextEncoder();
const secretKeyData = encoder.encode(SECRET_KEY);
// 서명 확인을 위해 키를 가져옵니다.
const key = await crypto.subtle.importKey(
"raw",
secretKeyData,
{ name: "HMAC", hash: "SHA-256" },
false,
["verify"],
);
// 확인이 필요한 데이터 추출: 경로 및 만료 타임스탬프
const expiry = Number(url.searchParams.get("expiry"));
const dataToAuthenticate = url.pathname + expiry;
// 수신된 Base64로 인코딩된 MAC을 Uint8Array로 변환합니다.
const receivedMacBase64 = url.searchParams.get("mac");
const receivedMac = byteStringToUint8Array(atob(receivedMacBase64));
// 타이밍 공격을 방지하기 위해 crypto.subtle.verify()를 사용하여 서명을 확인합니다.
const verified = await crypto.subtle.verify(
"HMAC",
key,
receivedMac,
encoder.encode(dataToAuthenticate),
);
// 확인에 실패하면 오류 페이지를 반환합니다.
if (!verified) {
return failPage("잘못된 MAC");
}
// URL이 만료되었는지 확인합니다.
if (Date.now() > expiry) {
return failPage(`${new Date(expiry)}에 URL이 만료되었습니다.`);
}
// 확인 성공, 리소스에 대한 액세스 허용
return fetch(request);
}
// ByteString을 Uint8Array로 변환합니다.
function byteStringToUint8Array(byteString) {
const ui = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; ++i) {
ui[i] = byteString.charCodeAt(i);
}
return ui;
}
// 요청에 서명
async function signRequest(request) {
const url = new URL(request.url);
return generateSignedUrl(url);
}
// 서명된 URL 생성
async function generateSignedUrl(url) {
// 서명 생성을 위해 키를 가져옵니다.
const encoder = new TextEncoder();
const secretKeyData = encoder.encode(SECRET_KEY);
const key = await crypto.subtle.importKey(
"raw",
secretKeyData,
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"],
);
// URL 만료 시간 설정
const expirationMs = 18000; // 18초
const expiry = Date.now() + expirationMs;
const dataToAuthenticate = url.pathname + expiry;
// 서명 생성
const mac = await crypto.subtle.sign("HMAC", key, encoder.encode(dataToAuthenticate));
// 서명을 Base64로 인코딩된 문자열로 변환합니다.
const base64Mac = btoa(String.fromCharCode(...new Uint8Array(mac)));
// 서명 및 만료 시간을 URL 쿼리 매개변수에 추가합니다.
url.searchParams.set("mac", base64Mac);
url.searchParams.set("expiry", expiry);
return new Response(url);
}
// 오류 페이지 생성
function failPage(msg) {
let page = FAILPAGE.replace('{{error-msg}}', msg);
return new Response(page, {headers: {"Content-Type": "text/html; charset=utf-8"}});
}
// 오류 페이지 HTML 템플릿
const FAILPAGE = `
<!DOCTYPE html>
<html>
<head>
<title>오류 페이지</title>
<style>
// ... 페이지 스타일 ...
</style>
</head>
<body>
<div class="container">
<h1>오류</h1>
<p>액세스하려는 URL이 올바르게 서명되지 않았습니다: {{error-msg}}</p>
<div class="url-section">
<div class="url-wrapper">
<p><span class="url-display" id="current-url" style="display: block;"></span></p>
</div>
<div class="button-wrapper">
<button class="url-button" type="button" onclick="getSignedUrl()">URL 서명</button>
</div>
<div class="url-wrapper" id="signed-url-section">
<p><strong>서명된 URL은 18초 후에 만료됩니다.</strong></p>
<p><span class="url-display" id="signed-url"></span></p>
</div>
</div>
</div>
<script>
// ... 페이지 스크립트 ...
</script>
</body>
</html>
`;
addEventListener("fetch", event => {
return event.respondWith(handleRequest(event.request));
});
Edge Cloud Apps 함수는 Web Crypto API를 완벽하게 지원하여 에지에서 암호화 및 암호 해독 요구 사항을 충족할 수 있습니다. Edge Cloud Apps 함수를 사용하여 클라이언트를 대신하여 요청에 서명하거나 들어오는 서명된 요청의 유효성을 검사하여 무단 액세스(핫링크 보호)를 효과적으로 방지할 수 있습니다.