July 23, 2025

πŸ“¦ κ³Όλ„ν•œ μ„œλ“œνŒŒν‹° 슀크립트 λ‚¨μš©: μ„±λŠ₯ μ €ν•˜μ™€ λ³΄μ•ˆ μœ„ν—˜ 증가

HTML
μ„±λŠ₯
λ³΄μ•ˆ
μ›Ήν‘œμ€€
λΉŒλ“œ&λ²ˆλ“€λ§
μΊμ‹±μ „λž΅

Summary

μ›Ήμ‚¬μ΄νŠΈμ— λ„ˆλ¬΄ λ§Žμ€ μ„œλ“œνŒŒν‹° 슀크립트λ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ λΉ„νš¨μœ¨μ μœΌλ‘œ κ΄€λ¦¬ν•˜λ©΄ μ„±λŠ₯ μ €ν•˜, λ³΄μ•ˆ 취약점 증가, μœ μ§€λ³΄μˆ˜ λ³΅μž‘μ„± λ“± μ‹¬κ°ν•œ 문제λ₯Ό μ•ΌκΈ°ν•©λ‹ˆλ‹€. ν•„μš”ν•œ 슀크립트만 μ—„μ„ ν•˜κ³ , async/deferλ₯Ό ν†΅ν•œ 비동기/μ§€μ—° λ‘œλ”©, preconnect/dns-prefetch, SRI, CSP 등을 μ μš©ν•˜μ—¬ 효율적이고 μ•ˆμ „ν•˜κ²Œ μ„œλ“œνŒŒν‹° 슀크립트λ₯Ό 관리해야 ν•©λ‹ˆλ‹€.

Why Wrong?

μ›Ήμ‚¬μ΄νŠΈμ— λ„ˆλ¬΄ λ§Žμ€ μ„œλ“œνŒŒν‹°(Third-party) 슀크립트λ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ λΉ„νš¨μœ¨μ μœΌλ‘œ λ‘œλ“œν•˜λŠ” 것은 μ‹¬κ°ν•œ μ„±λŠ₯ 및 λ³΄μ•ˆ 문제λ₯Ό μ•ΌκΈ°ν•©λ‹ˆλ‹€.

πŸ“‰ μ„±λŠ₯ μ €ν•˜

각 μ„œλ“œνŒŒν‹° μŠ€ν¬λ¦½νŠΈλŠ” μƒˆλ‘œμš΄ λ„€νŠΈμ›Œν¬ μš”μ²­, λ‹€μš΄λ‘œλ“œ, νŒŒμ‹±, 컴파일, μ‹€ν–‰ 과정을 거치며 메인 μŠ€λ ˆλ“œλ₯Ό λΈ”λ‘œν‚Ήν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” First Contentful Paint (FCP), Largest Contentful Paint (LCP), Interaction to Next Paint (INP) λ“± Core Web Vitals μ§€ν‘œμ— 직접적인 μ•…μ˜ν–₯을 μ£Όμ–΄ μ‚¬μš©μž κ²½ν—˜μ„ μ €ν•˜μ‹œν‚΅λ‹ˆλ‹€. 특히, κ΄‘κ³  슀크립트, 뢄석 도ꡬ, A/B ν…ŒμŠ€νŠΈ 도ꡬ 등은 μ˜ˆμƒμΉ˜ λͺ»ν•œ λ³΅μž‘ν•œ λ‘œμ§μ„ ν¬ν•¨ν•˜μ—¬ λ Œλ”λ§μ„ μ§€μ—°μ‹œν‚€κ±°λ‚˜ λ ˆμ΄μ•„μ›ƒ λΆˆμ•ˆμ •(CLS)을 μœ λ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€. μŠ€ν¬λ¦½νŠΈκ°€ λ‹€μš΄λ‘œλ“œλ˜λŠ” λ™μ•ˆ λΈŒλΌμš°μ €μ˜ λ Œλ”λ§μ΄ 멈좜 수 μžˆμ–΄ μ‚¬μš©μžμ—κ²Œ 빈 ν™”λ©΄μ΄λ‚˜ μ§€μ—°λœ μƒν˜Έμž‘μš©μ„ μ΄ˆλž˜ν•©λ‹ˆλ‹€.

πŸ›‘οΈ λ³΄μ•ˆ μœ„ν—˜

μ„œλ“œνŒŒν‹° μŠ€ν¬λ¦½νŠΈλŠ” μ—¬λŸ¬λΆ„μ˜ μ›Ήμ‚¬μ΄νŠΈμ—μ„œ μ‹€ν–‰λ˜λŠ” μ™ΈλΆ€ μ½”λ“œμž…λ‹ˆλ‹€. μ•…μ˜μ μΈ κ³΅κ²©μžκ°€ μ„œλ“œνŒŒν‹° 슀크립트 제곡자의 μ‹œμŠ€ν…œμ„ μΉ¨ν•΄(Supply Chain Attack)ν•˜μ—¬ μ•…μ„± μ½”λ“œλ₯Ό μ£Όμž…ν•˜κ±°λ‚˜, μ‚¬μš©μž 데이터λ₯Ό νƒˆμ·¨ν•  수 μžˆλŠ” ν†΅λ‘œκ°€ 될 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” ν¬λ¦¬λ΄μ…œ(인증 정보) νƒˆμ·¨, μ„Έμ…˜ ν•˜μ΄μž¬ν‚Ή, 멀웨어 배포 λ“± 치λͺ…적인 κ²°κ³Όλ₯Ό μ΄ˆλž˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, CDN을 톡해 λ‘œλ“œλ˜λŠ” 슀크립트의 경우 μ„œλΈŒλ¦¬μ†ŒμŠ€ 무결성(Subresource Integrity, SRI)을 μ μš©ν•˜μ§€ μ•ŠμœΌλ©΄ λ³€μ‘°λœ μŠ€ν¬λ¦½νŠΈκ°€ 싀행될 μœ„ν—˜μ΄ μžˆμŠ΅λ‹ˆλ‹€.

πŸŒ€ μœ μ§€λ³΄μˆ˜ 및 λ³΅μž‘μ„± 증가

λΆˆν•„μš”ν•œ μ„œλ“œνŒŒν‹° 슀크립트의 μ¦κ°€λŠ” μ „λ°˜μ μΈ μ½”λ“œ 베이슀의 λ³΅μž‘μ„±μ„ 높이고, νŠΉμ • κΈ°λŠ₯의 디버깅을 μ–΄λ ΅κ²Œ λ§Œλ“€λ©°, μ˜λ„μΉ˜ μ•Šμ€ μƒν˜Έμž‘μš©μ΄λ‚˜ μΆ©λŒμ„ μœ λ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€. 슀크립트 κ°„μ˜ μ’…μ†μ„±μ΄λ‚˜ μ „μ—­ λ³€μˆ˜ μ˜€μ—Όμ€ 예츑 λΆˆκ°€λŠ₯ν•œ λ²„κ·Έλ‘œ μ΄μ–΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.

How to Fix?

μ„œλ“œνŒŒν‹° 슀크립트의 λ„μž…μ€ μ‹ μ€‘ν•˜κ²Œ κ²°μ •ν•˜κ³ , λ„μž… ν›„μ—λŠ” μ„±λŠ₯κ³Ό λ³΄μ•ˆμ„ μ΅œμ ν™”ν•˜κΈ° μœ„ν•œ λ…Έλ ₯이 ν•„μš”ν•©λ‹ˆλ‹€.

βœ… ν•„μˆ˜ μ—¬λΆ€ 및 ν•„μš”μ„± μž¬ν‰κ°€

λͺ¨λ“  μ„œλ“œνŒŒν‹° μŠ€ν¬λ¦½νŠΈκ°€ 정말 ν•„μš”ν•œμ§€ 주기적으둜 κ°μ‚¬ν•˜κ³ , μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μŠ€ν¬λ¦½νŠΈλŠ” 과감히 μ œκ±°ν•©λ‹ˆλ‹€. μ—¬λŸ¬ μ„œλ“œνŒŒν‹° μŠ€ν¬λ¦½νŠΈκ°€ μœ μ‚¬ν•œ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” 경우, 쀑볡을 ν”Όν•˜κ³  κ°€μž₯ 효율적인 ν•˜λ‚˜λ₯Ό μ„ νƒν•©λ‹ˆλ‹€.

⚑️ 비동기/μ§€μ—° λ‘œλ”©

<script> νƒœκ·Έμ— async λ˜λŠ” defer 속성을 μ‚¬μš©ν•˜μ—¬ μŠ€ν¬λ¦½νŠΈκ°€ HTML νŒŒμ‹±μ„ λΈ”λ‘œν‚Ήν•˜μ§€ μ•Šλ„λ‘ ν•©λ‹ˆλ‹€.

  • async: 슀크립트λ₯Ό λΉ„λ™κΈ°μ μœΌλ‘œ λ‹€μš΄λ‘œλ“œν•˜κ³ , λ‹€μš΄λ‘œλ“œ μ™„λ£Œ μ¦‰μ‹œ μ‹€ν–‰ν•©λ‹ˆλ‹€. HTML νŒŒμ‹±μ€ 슀크립트 λ‹€μš΄λ‘œλ“œ 쀑에 κ³„μ†λ©λ‹ˆλ‹€.
  • defer: 슀크립트λ₯Ό λΉ„λ™κΈ°μ μœΌλ‘œ λ‹€μš΄λ‘œλ“œν•˜μ§€λ§Œ, HTML νŒŒμ‹±μ΄ μ™„λ£Œλœ 후에 λ¬Έμ„œμ— λ‚˜νƒ€λ‚˜λŠ” μˆœμ„œλŒ€λ‘œ μ‹€ν–‰ν•©λ‹ˆλ‹€. DOMContentLoaded 이벀트 λ°œμƒ 전에 μ‹€ν–‰λ©λ‹ˆλ‹€. 일반적으둜 νŽ˜μ΄μ§€ μ½˜ν…μΈ  λ Œλ”λ§μ— ν•„μˆ˜μ μ΄μ§€ μ•Šμ€ μŠ€ν¬λ¦½νŠΈμ— μ ν•©ν•©λ‹ˆλ‹€. μ‚¬μš©μž μƒν˜Έμž‘μš© 후에 λ‘œλ“œλ˜λŠ” 슀크립트(예: Intersection Observerλ‚˜ 이벀트 λ¦¬μŠ€λ„ˆλ₯Ό ν™œμš©)도 κ³ λ €ν•˜μ—¬ 초기 λ‘œλ”© μ„±λŠ₯을 κ°œμ„ ν•©λ‹ˆλ‹€.

πŸš€ preconnect, dns-prefetch ν™œμš©

μŠ€ν¬λ¦½νŠΈκ°€ λ‘œλ“œλ  도메인에 λŒ€ν•΄ 미리 연결을 μ„€μ •ν•˜μ—¬ μ§€μ—° μ‹œκ°„μ„ μ€„μž…λ‹ˆλ‹€. preconnectλŠ” DNS 쑰회, TCP ν•Έλ“œμ…°μ΄ν¬, TLS ν˜‘μƒκΉŒμ§€ 미리 μˆ˜ν–‰ν•˜μ—¬ λ‹€μŒ μš”μ²­μ˜ λŒ€κΈ° μ‹œκ°„μ„ 크게 μ€„μ—¬μ€λ‹ˆλ‹€. dns-prefetchλŠ” DNS 쑰회만 미리 μˆ˜ν–‰ν•˜μ—¬ preconnect보닀 κ°€λ³μ§€λ§Œ νš¨κ³ΌλŠ” μ μŠ΅λ‹ˆλ‹€.

πŸ” μ„œλΈŒλ¦¬μ†ŒμŠ€ 무결성 (Subresource Integrity, SRI) 적용

μ€‘μš”ν•œ μ„œλ“œνŒŒν‹° 슀크립트(특히 CDNμ—μ„œ λ‘œλ“œλ˜λŠ” 슀크립트)에 λŒ€ν•΄ SRIλ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€ν¬λ¦½νŠΈκ°€ λ³€μ‘°λ˜μ§€ μ•Šμ•˜μŒμ„ ν™•μΈν•©λ‹ˆλ‹€. SRIλŠ” 슀크립트의 ν•΄μ‹œ 값을 μ§€μ •ν•˜μ—¬, λ‘œλ“œλœ 슀크립트의 ν•΄μ‹œ κ°’κ³Ό μΌμΉ˜ν•˜μ§€ μ•ŠμœΌλ©΄ λΈŒλΌμš°μ €κ°€ 슀크립트 싀행을 κ±°λΆ€ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. μ΄λŠ” 곡급망 곡격(Supply Chain Attack)μœΌλ‘œλΆ€ν„° λ³΄ν˜Έν•˜λŠ” μ€‘μš”ν•œ μˆ˜λ‹¨μž…λ‹ˆλ‹€.

🎯 νƒœκ·Έ 관리 μ‹œμŠ€ν…œ (TMS) μ‹ μ€‘ν•œ ν™œμš©

Google Tag Manager와 같은 TMSλ₯Ό μ‚¬μš©ν•˜λ©΄ 슀크립트 관리가 μš©μ΄ν•˜μ§€λ§Œ, λ„ˆλ¬΄ λ§Žμ€ νƒœκ·Έλ₯Ό μΆ”κ°€ν•˜λ©΄ 였히렀 μ„±λŠ₯이 μ €ν•˜λ  수 μžˆμœΌλ―€λ‘œ, μ΅œμ†Œν•œμ˜ ν•„μš”ν•œ νƒœκ·Έλ§Œ μΆ”κ°€ν•˜κ³  μ΅œμ ν™”ν•©λ‹ˆλ‹€. TMS λ‚΄μ—μ„œλ„ 비동기 λ‘œλ”© μ˜΅μ…˜μ„ ν™œμš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

βš™οΈ Content Security Policy (CSP) κ°•ν™”

μ‹ λ’°ν•  수 μžˆλŠ” λ„λ©”μΈμ—μ„œλ§Œ 슀크립트 λ‘œλ“œλ₯Ό ν—ˆμš©ν•˜λ„λ‘ CSPλ₯Ό κ΅¬μ„±ν•˜μ—¬ XSS 곡격 및 μ•…μ„± 슀크립트 μ£Όμž…μ„ λ°©μ§€ν•©λ‹ˆλ‹€. CSPλŠ” μ›ΉνŽ˜μ΄μ§€κ°€ λ‘œλ“œν•  수 μžˆλŠ” λ¦¬μ†ŒμŠ€(슀크립트, μŠ€νƒ€μΌ, 이미지 λ“±)의 좜처λ₯Ό λͺ…μ‹œμ μœΌλ‘œ μ§€μ •ν•˜μ—¬ λ³΄μ•ˆμ„ κ°•ν™”ν•˜λŠ” HTTP 응닡 ν—€λ”μž…λ‹ˆλ‹€.

πŸ“¦ 뢀뢄적 자체 ν˜ΈμŠ€νŒ…

일뢀 슀크립트(특히 뢄석 슀크립트)λŠ” 캐싱 이점을 μœ„ν•΄ 자체 ν˜ΈμŠ€νŒ…μ„ κ³ λ €ν•  수 μžˆμ§€λ§Œ, μ—…λ°μ΄νŠΈ κ΄€λ¦¬μ˜ 어렀움을 κ³ λ €ν•˜μ—¬ μ‹ μ€‘ν•˜κ²Œ κ²°μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. 자체 ν˜ΈμŠ€νŒ…μ€ CDN보닀 λΉ λ₯Έ λ‘œλ”©μ„ μ œκ³΅ν•  수 μžˆμ§€λ§Œ, 슀크립트 μ—…λ°μ΄νŠΈλ₯Ό 직접 관리해야 ν•˜λŠ” 단점이 μžˆμŠ΅λ‹ˆλ‹€.

Before Code (Bad)

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>문제 μžˆλŠ” μ„œλ“œνŒŒν‹° 슀크립트 μ˜ˆμ‹œ</title>

    <!-- Google Analytics (head에 동기 λ‘œλ“œ, νŽ˜μ΄μ§€ λ Œλ”λ§ λΈ”λ‘œν‚Ή) -->
    <script>
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
        ga('create', 'UA-XXXXX-Y', 'auto');
        ga('send', 'pageview');
    </script>

    <!-- Hotjar (head에 동기 λ‘œλ“œ, μ‚¬μš©μž λ™μ˜ 없이 초기 λ‘œλ“œ) -->
    <script>
        (function(h,o,t,j,a,r){
            h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
            h._hjSettings={hjid:XXXXX,hjsv:6};
            a=o.getElementsByTagName('head')[0];
            r=o.createElement('script');r.async=1;
            r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
            a.appendChild(r);
        })(window,document,'//static.hotjar.com/c/hotjar-','.js?sv=');
    </script>

    <!-- λΆˆν•„μš”ν•˜κ²Œ λ§Žμ€ μ™ΈλΆ€ μŠ€νƒ€μΌμ‹œνŠΈ (병렬 μš”μ²­ 수 μ œν•œ) -->
    <link rel="stylesheet" href="https://cdn.example.com/some-ui-kit.min.css">
    <link rel="stylesheet" href="https://cdn.example.com/another-font-awesome.min.css">
</head>
<body>
    <h1>Welcome to Our Site</h1>
    <p>This is some content.</p>

    <!-- μ™ΈλΆ€ 라이브러리 (CDN을 톡해 동기 λ‘œλ“œ, HTML νŒŒμ‹± λΈ”λ‘œν‚Ή) -->
    <script src="https://unpkg.com/some-heavy-library@1.0.0/dist/library.min.js"></script>

    <!-- Zendesk Chat Widget (body λ§ˆμ§€λ§‰μ— μžˆμ§€λ§Œ, 동기 λ‘œλ”© 방식) -->
    <script id="ze-snippet" src="https://static.zdassets.com/ekr/snippet.js?key=YOUR_ZENDESK_KEY"></script>
</body>
</html>

After Code (Good)

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>μ΅œμ ν™”λœ μ„œλ“œνŒŒν‹° 슀크립트 μ˜ˆμ‹œ</title>

    <!-- μ€‘μš”ν•œ λ¦¬μ†ŒμŠ€ λ‘œλ“œ μ „ 미리 μ—°κ²° μ„€μ • (μ„±λŠ₯ μ΅œμ ν™”) -->
    <link rel="preconnect" href="https://www.google-analytics.com">
    <link rel="preconnect" href="https://static.hotjar.com">
    <link rel="preconnect" href="https://unpkg.com">
    <link rel="dns-prefetch" href="https://static.zdassets.com">

    <!-- Content Security Policy (λ³΄μ•ˆ κ°•ν™”) -->
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://www.google-analytics.com https://static.hotjar.com https://unpkg.com https://static.zdassets.com; style-src 'self' 'unsafe-inline' https://cdn.example.com; font-src 'self' https://cdn.example.com;">

    <!-- Google Analytics (async 속성 μ‚¬μš©, ν•„μš”ν•œ 경우 head에 μœ„μΉ˜ κ°€λŠ₯) -->
    <script async src="https://www.google-analytics.com/analytics.js"></script>
    <script>
        window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
        ga('create', 'UA-XXXXX-Y', 'auto');
        ga('send', 'pageview');
    </script>

    <!-- Hotjar (defer 속성 μ‚¬μš©, ν•„μš”ν•œ 경우 μ‚¬μš©μž λ™μ˜ ν›„ λ˜λŠ” 슀크둀 μ‹œμ  λ‘œλ“œ) -->
    <script defer src="https://static.hotjar.com/c/hotjar-XXXXX.js?sv=6"></script>

    <!-- μ™ΈλΆ€ μŠ€νƒ€μΌμ‹œνŠΈλŠ” μ€‘μš”λ„μ— 따라 μ΅œμ ν™” (예: 핡심 CSS만 λ²ˆλ“€μ— 포함, λ‚˜λ¨Έμ§€λŠ” λ‚˜μ€‘μ— λ‘œλ“œ) -->
    <link rel="stylesheet" href="/styles/main.css"> <!-- 자체 ν˜ΈμŠ€νŒ… CSS -->
</head>
<body>
    <h1>Welcome to Our Site</h1>
    <p>This is some content.</p>

    <!-- μ™ΈλΆ€ 라이브러리 (async/defer 속성, SRI 적용) -->
    <script async defer
        src="https://unpkg.com/some-heavy-library@1.0.0/dist/library.min.js"
        integrity="sha384-XXXXXX..." <!-- μ‹€μ œ 라이브러리 ν•΄μ‹œκ°’μœΌλ‘œ λŒ€μ²΄. ν•„μˆ˜! -->
        crossorigin="anonymous">
    </script>

    <!-- Zendesk Chat Widget (μ‚¬μš©μž μƒν˜Έμž‘μš© λ˜λŠ” ν•„μš”ν•œ μ‹œμ μ— 동적 λ‘œλ“œ) -->
    <button id="openChat">Open Chat</button>
    <div id="chat-widget-container"></div>
    <script>
        document.getElementById('openChat').addEventListener('click', () => {
            // μŠ€ν¬λ¦½νŠΈκ°€ λ‘œλ“œλ˜μ—ˆλŠ”μ§€ ν™•μΈν•˜μ—¬ 쀑볡 λ‘œλ“œ λ°©μ§€
            if (!window.ZendeskLoaded) {
                const script = document.createElement('script');
                script.id = 'ze-snippet';
                script.src = 'https://static.zdassets.com/ekr/snippet.js?key=YOUR_ZENDESK_KEY';
                script.async = true; // 비동기 λ‘œλ”©
                script.onload = () => {
                    window.ZendeskLoaded = true;
                    // Zendesk μ΄ˆκΈ°ν™” μ½”λ“œ (if any)
                };
                document.body.appendChild(script);
            }
        });
    </script>
</body>
</html>

You Might Also Like

MDN Web Docs의 <script> μš”μ†Œ λ¬Έμ„œλŠ” `async`와 `defer` 속성을 μ‚¬μš©ν•˜μ—¬ 슀크립트 λ‘œλ”©μ΄ HTML νŒŒμ‹±μ„ λΈ”λ‘œν‚Ήν•˜μ§€ μ•Šλ„λ‘ ν•˜λŠ” 방법을 μƒμ„Ένžˆ μ„€λͺ…ν•©λ‹ˆλ‹€.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
web.dev의 'Optimize third-party resources' κ°€μ΄λ“œλŠ” μ„œλ“œνŒŒν‹° μŠ€ν¬λ¦½νŠΈκ°€ μ›Ή μ„±λŠ₯에 λ―ΈμΉ˜λŠ” 영ν–₯κ³Ό 이λ₯Ό μ΅œμ ν™”ν•˜κΈ° μœ„ν•œ λ‹€μ–‘ν•œ μ „λž΅(preconnect, dns-prefetch, async/defer, self-hosting, SRI λ“±)을 ν¬κ΄„μ μœΌλ‘œ μ„€λͺ…ν•©λ‹ˆλ‹€.
https://web.dev/optimize-third-party-resources/
MDN Web Docs의 Subresource Integrity λ¬Έμ„œλŠ” μ™ΈλΆ€ μŠ€ν¬λ¦½νŠΈκ°€ λ³€μ‘°λ˜μ§€ μ•Šμ•˜μŒμ„ 보μž₯ν•˜κΈ° μœ„ν•œ SRI의 κ°œλ…κ³Ό μ‚¬μš©λ²•μ„ μ„€λͺ…ν•˜μ—¬ λ³΄μ•ˆ μœ„ν—˜μ„ μ€„μ΄λŠ” 데 도움을 μ€λ‹ˆλ‹€.
https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
MDN Web Docs의 Content Security Policy (CSP) λ¬Έμ„œλŠ” μ›Ήμ‚¬μ΄νŠΈλ₯Ό XSS 곡격 및 데이터 μΈμ μ…˜μœΌλ‘œλΆ€ν„° λ³΄ν˜Έν•˜λŠ” CSP의 원리와 ꡬ성을 μ„€λͺ…ν•˜μ—¬ μ„œλ“œνŒŒν‹° μŠ€ν¬λ¦½νŠΈλ‘œλΆ€ν„° λ°œμƒν•  수 μžˆλŠ” λ³΄μ•ˆ 취약점을 μ™„ν™”ν•˜λŠ” 방법을 μ œκ³΅ν•©λ‹ˆλ‹€.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy