다큐멘트 센터 Edge Application Developer Tools Request Signature and Legitimacy Verification

Request Signature and Legitimacy Verification

최신 업데이트: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 함수는 클라이언트를 대신하여 나가는 요청에 서명하거나 들어오는 서명된 요청을 확인하여 보안 게이트키퍼 역할을 할 수 있습니다. 권한이 없는 요청은 오류 페이지로 연결됩니다.

이점

  • 향상된 보안: 암호화 서명을 사용하면 무단 액세스를 효과적으로 방지하여 민감한 웹사이트 리소스를 보호합니다.
  • 에지 암호화: Edge Cloud Apps 함수와 Web Crypto API를 활용하면 에지에서 직접 암호화 작업을 수행할 수 있으므로 지연 시간이 단축되고 효율성이 향상됩니다.
  • 유연한 제어: 개발자는 서명 알고리즘 및 확인 논리를 사용자 지정하여 특정 요구 사항에 따라 유연한 액세스 제어 전략을 구현할 수 있습니다.

코드 예제

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 함수를 사용하여 클라이언트를 대신하여 요청에 서명하거나 들어오는 서명된 요청의 유효성을 검사하여 무단 액세스(핫링크 보호)를 효과적으로 방지할 수 있습니다.

이 문서의 내용이 도움이 되었습니까?
아니오
정상적으로 제출되었습니다.피드백을 주셔서 감사합니다.앞으로도 개선을 위해 노력하겠습니다.