Subresource Integrity (SRI)

Subresource Integrity (SRI)는 브라우저가 외부 서버(예: CDN)에서 가져오는 리소스가 예기치 않은 조작 없이 제공되었는지 확인할 수 있도록 하는 보안 기능입니다. 가져온 리소스가 일치해야 하는 암호화 해시를 제공함으로써 작동합니다.

이 글에서는 SRI가 무엇인지, 왜 필요한지, 어떻게 작동하는지, 그리고 어떻게 구현하는지에 대해 설명합니다.

What is SRI?

SRI는 웹 개발자가 CDN과 같은 제3자 서버에서 호스팅되는 리소스가 변조되지 않았음을 보장할 수 있도록 하는 W3C 사양입니다. 리소스에 대한 암호화 해시(무결성 메타데이터)를 제공함으로써 브라우저는 가져온 리소스가 예상 해시와 일치하는지 확인한 후 실행할 수 있습니다. 리소스가 일치하지 않으면 브라우저는 로드를 거부하여 잠재적인 공격을 방지합니다.

 graph LR
    subgraph Server
        A[Generate resource hash and <br>embed in HTML 'integrity' attribute]
    end

    subgraph Browser
        B[Download resource from CDN] --> C[Calculate hash from<br>the downloaded resource]
        C --> D{Compare hashes}
    end

    A --> B
    D -- Match --> E[✅ Execute script]
    D -- Mismatch --> F[❌ Block script & throw error]

Why is SRI needed?

웹사이트는 종종 JavaScript 라이브러리 및 CSS 프레임워크와 같은 공통 파일을 제공하기 위해 콘텐츠 전송 네트워크(CDN)에 의존합니다. 이는 성능과 가용성을 향상시킵니다. 그러나 CDN이 손상되면 악의적인 행위자가 이러한 파일을 수정하여 이를 사용하는 웹사이트에 악성 코드를 주입할 수 있습니다. 이로 인해 데이터 도난이나 완전한 사이트 장악과 같은 다양한 공격이 발생할 수 있습니다.

SRI는 브라우저가 개발자가 제공한 무결성 해시와 일치하는 코드만 실행하도록 보장하여 이러한 위험을 완화합니다.

How does SRI work?

SRI는 <script><link> 요소의 integrity 속성을 사용하여 작동합니다. 이 속성에는 하나 이상의 base64로 인코딩된 암호화 해시가 포함됩니다.

The integrity attribute

integrity 속성의 값은 하나 이상의 해시를 포함하는 문자열입니다. 여러 해시는 공백으로 구분하여 제공할 수 있습니다. 각 해시는 해시 알고리즘(예: sha256, sha384, sha512)을 나타내는 접두사, 하이픈, 그리고 base64로 인코딩된 해시 값으로 구성됩니다.

예시: sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC

Hash generation

SRI에 가장 일반적으로 사용되는 해시 알고리즘은 SHA-256, SHA-384 및 SHA-512입니다. SHA-384는 일반적으로 보안과 성능 간의 적절한 균형으로 권장됩니다.

Browser verification process

브라우저가 integrity 속성이 있는 <script> 또는 <link> 요소를 만나면 다음 단계를 수행합니다.

  1. 지정된 URL에서 리소스를 가져옵니다.
  2. integrity 속성에 지정된 알고리즘 중 하나를 사용하여 가져온 리소스의 암호화 해시를 계산합니다. 여러 알고리즘이 제공된 경우 브라우저는 나열된 가장 강력한 알고리즘을 사용하려고 시도합니다.
  3. 계산된 해시를 integrity 속성에 제공된 해시와 비교합니다.
  4. 해시가 일치하면 리소스가 실행되거나 적용됩니다.
  5. 해시가 일치하지 않으면 브라우저는 리소스 실행 또는 적용을 거부하고 일반적으로 콘솔에 오류를 기록합니다.

How to implement SRI?

SRI 구현은 간단합니다. 외부 리소스를 참조하는 <script><link> 태그에 integrity 속성을 추가하기만 하면 됩니다.

Examples

JavaScript 파일의 경우:

<script src="https://example.com/library.js"
        integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
        crossorigin="anonymous"></script>

CSS 파일의 경우:

<link href="https://example.com/style.css"
      rel="stylesheet"
      integrity="sha384-AbcDEfGhIjKlMnOpQrStUvWxYz1234567890AbcDEfGhIjKlMnOpQrSt="
      crossorigin="anonymous">

crossorigin="anonymous" 속성은 주의가 필요합니다. SRI가 제3자 출처에서 가져온 리소스와 함께 작동하려면 해당 리소스가 CORS(Cross-Origin Resource Sharing) 헤더와 함께 제공되어야 하며, 이를 통해 리소스를 사용자의 출처와 공유할 수 있습니다(예: Access-Control-Allow-Origin: *). crossorigin="anonymous" 속성은 브라우저에 자격 증명(쿠키, 클라이언트 측 SSL 인증서 또는 HTTP 인증) 없이 CORS 요청을 하도록 지시합니다.

SRI Hash Generation Tools

여러 가지 방법으로 SRI 해시를 생성할 수 있습니다.

  • 온라인 생성기: SRIHash.org와 같이 SRI 해시를 생성해 줄 수 있는 많은 웹사이트가 있습니다.
  • OpenSSL 명령줄 도구: openssl을 사용하여 해시를 생성할 수 있습니다. 예를 들어 SHA-384 해시를 생성하려면 다음을 수행합니다.
    curl -sL "https://code.jquery.com/jquery-3.6.0.min.js" | openssl dgst -sha384 -binary | openssl base64 -A
    # vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK
    
    이 명령은 파일을 가져와 SHA-384 해시를 계산한 다음 base64로 인코딩합니다.
  • npm 패키지: sri-toolbox 또는 webpack-subresource-integrity와 같은 도구를 사용하면 빌드 프로세스에서 SRI 해시 생성을 자동화하는 데 도움이 될 수 있습니다.

Advantages of SRI

  • CDN 손상 방지: SRI는 CDN이 침해되고 파일이 수정되더라도 웹사이트가 변조된 리소스를 로드하지 않도록 보장합니다.
  • 신뢰도 향상: 추가적인 보안 계층을 제공하여 웹사이트의 신뢰도를 높입니다.
  • 간단한 구현: integrity 속성을 추가하는 것은 비교적 쉽습니다.

Limitations of SRI

  • 동적 콘텐츠: SRI는 콘텐츠가 변경될 때마다 해시를 업데이트해야 하므로 자주 변경되거나 동적으로 생성되는 리소스에는 적합하지 않습니다.
  • HTTPS를 대체하지 않음: SRI는 특정 유형의 공격(제3자 서버의 리소스 수정)으로부터 보호합니다. 통신 채널을 암호화하고 중간자 공격으로부터 보호하는 HTTPS의 필요성을 대체하지는 않습니다.
  • 브라우저 지원: 대부분의 최신 브라우저는 SRI를 지원하지만 이전 브라우저는 지원하지 않을 수 있습니다. 그러나 이러한 브라우저는 integrity 속성을 무시하고 확인 없이 리소스를 로드하므로 기능이 중단되지는 않습니다.
  • CORS 필요: 교차 출처 리소스의 경우 리소스를 호스팅하는 서버에 적절한 CORS 헤더가 포함되어야 합니다.

Conclusion

Subresource Integrity는 손상된 제3자 호스트에서 발생하는 공격으로부터 웹사이트를 보호하는 데 도움이 되는 귀중한 보안 기능입니다. 외부 리소스의 무결성을 확인함으로써 SRI는 악성 코드 주입에 대한 중요한 방어 계층을 추가합니다. 몇 가지 제한 사항이 있지만 구현 용이성과 상당한 보안 이점으로 인해 외부 리소스에 의존하는 모든 웹사이트에 권장되는 관행입니다.