SRI 해시를 만드는 방법
- SRI 모드가 선택되어 있습니다. 해시: 에서 sha256, sha384, sha512 중 원하는 것을 선택하세요. 기본값은 sha384입니다.
- 입력을 파일로 두고
.js나.css파일을 놓으세요. 태그 종류는 파일 확장자를 따릅니다. - 또는 입력을 텍스트로 두고 파일 내용 (붙여넣기) 에 파일 내용을 붙여넣은 다음, 태그(
<script>또는<link rel="stylesheet">)를 고르고 파일이 제공될 경로나 URL을 입력하세요. integrity값이나 HTML 태그 전체를 복사하세요. 알고리즘을 여러 개 선택하면 하나의 속성 안에 공백으로 구분되어 나옵니다.
붙여넣기보다 파일을 놓는 쪽이 더 확실합니다. 브라우저 텍스트 상자는 CRLF 줄 끝을 LF로 바꾸고, 마지막 줄 바꿈이 빠지거나 더해지면 해시가 달라집니다. 도구가 두 가지 모두 알려 줍니다.
integrity 값이란
SRI 값은 알고리즘 이름, 대시, 그리고 파일의 정확한 바이트에 대한 Base64 다이제스트로 이루어집니다. console.log('hello'); 한 줄과 줄 바꿈으로 된 app.js 파일이라면 다음과 같습니다.
<script src="https://cdn.example.com/app.js"
integrity="sha384-eEqgsNuDqSzbarn2kIY7c4WH6zkoJrjJRQIhlYgVwRR+6Eb8tkfTItTNLlIjbE3O"
crossorigin="anonymous"></script>
마지막 줄 바꿈이 없으면 같은 줄의 해시는 sha384-v393mDht/MNBowq0Z9UpetDvKE6u6EdCihklP1GZs66vL1YCFm1Z4Q4wJtb94rY9입니다. 브라우저는 파일을 받아 수신한 본문을 해시하고(gzip이나 Brotli 전송 압축을 푼 뒤이므로 압축은 상관없습니다), 나열된 해시 중 일치하는 것이 없으면 실행하거나 적용하지 않습니다.
SRI가 쓸모 있는 경우
SRI는 다른 누군가가 코드를 제공할 때 보호해 줍니다. 공개 CDN, 서드파티 위젯 호스트, 다른 팀과 공유하는 스토리지 버킷 같은 곳입니다. 그 서버가 침해되어 파일이 바뀌면 브라우저는 변경된 파일을 페이지에서 실행하지 않고 차단합니다.
같은 URL에서 절대 바뀌지 않는 파일, 예를 들어 library@1.2.3/dist/lib.min.js에 알맞습니다. 다음에는 맞지 않습니다.
/latest/나@1처럼 새 릴리스로 옮겨 가는 URL.- 브라우저나 지역마다 다른 응답. 예를 들어 사용자 에이전트에 따라 다른
@font-face규칙을 주는 일부 웹 폰트 CSS. - 제공자가 의도적으로 그 자리에서 업데이트하는 스크립트. 많은 분석 도구와 채팅 로더가 그렇습니다. 이런 경우에는 SRI와 제공자의 업데이트 중 하나를 골라야 합니다.
자기 도메인의 자기 파일에는 SRI가 별 도움이 되지 않습니다. 파일을 바꿀 수 있는 공격자는 대개 HTML도 바꿀 수 있기 때문입니다. 그런 경우에는 Content Security Policy가 더 나은 도구이며, CSP nonce 생성기와 SHA-256을 Base64로의 CSP 해시가 그쪽을 다룹니다.
CORS와 crossorigin 속성
integrity 속성이 있는 다른 출처의 파일은 CORS 모드로 가져와야 하며, 서버가 Access-Control-Allow-Origin(공개 CDN은 보통 *)으로 허용해야 합니다. crossorigin="anonymous"가 바로 그것을 요청하며, 생성된 태그에는 항상 이 속성이 들어 있습니다. CORS가 없으면 브라우저가 해시할 바이트를 읽을 수 없어 파일을 차단하고, 콘솔에 integrity 또는 CORS 실패 메시지를 남깁니다.
같은 출처의 파일에는 이 속성이 필요 없지만, 있어도 해가 되지는 않습니다.
빌드에서 SRI 해시 만들기
파일이 몇 개를 넘으면 빌드 단계에서 해시를 계산하세요.
openssl dgst -sha384 -binary app.js | openssl base64 -A
const crypto = require("crypto");
const fs = require("fs");
const integrity = "sha384-" +
crypto.createHash("sha384").update(fs.readFileSync("app.js")).digest("base64");
console.log(integrity);
두 방법 모두 예시 파일에 대해 위의 eEqgsNuD… 값을 출력합니다. 번들러에는 HTML에 속성을 자동으로 써 주는 플러그인이 있는 경우가 많아, 빌드마다 해시를 맞춰 줍니다. 받은 값을 확인하려면 파일을 여기에 놓고 비교하세요. 비교는 한 글자 한 글자 정확하게 이루어집니다.
자주 묻는 질문
SRI에는 어떤 알고리즘을 써야 하나요?
보통 SHA-384를 쓰며, CDN이 흔히 게시하는 것도 이것입니다. 브라우저는 sha256, sha384, sha512를 받아들이고, 여러 개가 나열되어 있으면 그중 가장 강한 것을 쓰고 약한 것은 무시합니다.
integrity를 추가한 뒤 브라우저가 스크립트를 차단하는 이유는 무엇인가요?
바이트가 해시한 것과 다르거나, 파일이 CORS 없이 다른 출처에서 오는 경우입니다. 콘솔 메시지를 확인하고 서버가 실제로 보내는 파일과 비교하세요. 응답에 Access-Control-Allow-Origin이 있고 태그에 crossorigin="anonymous"가 있는지도 확인하세요.
"latest" URL처럼 바뀌는 파일에도 SRI를 쓸 수 있나요?
아니요. 해시는 정확히 한 버전에 고정되므로, 파일이 업데이트되면 해시를 갱신할 때까지 페이지가 깨집니다. 버전이 붙은 URL을 링크하거나, 변경을 배포하는 동안 이전 해시와 새 해시를 나란히 적으세요.
명령줄에서 SRI 해시를 만들려면 어떻게 하나요?
openssl dgst -sha384 -binary app.js | openssl base64 -A를 실행하고 결과 앞에 sha384-를 붙이세요. -binary는 빼지 마세요. 없으면 hex 텍스트를 인코딩하게 됩니다.