Chrome 120부터 비동기 클립보드에서 새로운 unsanitized
옵션 사용 가능
API에 액세스할 수 있습니다. 이 옵션은 HTML과 관련하여 일부 특수한 상황에서 도움이 될 수 있습니다.
복사했을 때와 동일한 클립보드의 내용을 붙여넣습니다.
즉, 브라우저가 일반적으로 수행하는 중간 정리 단계 없이
지원할 수 있습니다. 이 가이드에서 사용 방법을 알아보세요.
Async Clipboard API 대부분의 경우 개발자는 애플리케이션의 무결성에 대해 걱정할 필요가 클립보드에 작성한 내용을 클립보드 (사본)는 데이터를 읽을 때 얻는 것과 동일합니다. 클립보드 (붙여넣기)를 선택합니다.
이것은 텍스트의 경우 확실히 적용됩니다. DevTools에 다음 코드를 붙여넣어 보세요.
콘솔에서 즉시 페이지의 초점을 다시 맞춥니다. (setTimeout()
는 필수 항목입니다.
페이지에 포커스를 둘 시간이 충분합니다. 이는 비동기 API의
Clipboard API). 입력은 출력과 정확히 동일합니다.
setTimeout(async () => {
const input = 'Hello';
await navigator.clipboard.writeText(input);
const output = await navigator.clipboard.readText();
console.log(input, output, input === output);
// Logs "Hello Hello true".
}, 3000);
이미지의 경우에는 조금 다릅니다. 소위 말하는 압축 폭탄 공격, 브라우저 PNG와 같은 이미지를 다시 인코딩하지만 입력 및 출력 이미지는 시각적으로 정확히 동일한 픽셀당 픽셀입니다.
setTimeout(async () => {
const dataURL =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
const input = await fetch(dataURL).then((response) => response.blob());
await navigator.clipboard.write([
new ClipboardItem({
[input.type]: input,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const output = await clipboardItem.getType(input.type);
console.log(input.size, output.size, input.type === output.type);
// Logs "68 161 true".
}, 3000);
그렇다면 HTML 텍스트는 어떻게 될까요? 짐작하셨겠지만 HTML의 경우
상황이 달라집니다 여기에서는 브라우저가 HTML 코드를 정리하여 잘못된 콘텐츠가
예를 들어 HTML에서 <script>
태그를 제거하면
CSS를 인라인 처리하여 (예: <meta>
, <head>
, <style>
)
다음 예를 살펴보고 DevTools 콘솔에서 시도해 보세요. 사용자는 다음 작업을 수행합니다.
출력이 입력과 상당히 다르다는 것을 알 수 있습니다.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read();
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
HTML 정리는 일반적으로 바람직합니다. 자신을 노출하고 싶지 않은 경우 대부분의 경우 확인되지 않은 HTML을 허용하여 보안 문제에 대응합니다. 거기 하지만 개발자가 자신이 무엇을 하고 있는지 정확히 알고 있으며 이 경우 내부 및 출력 HTML의 무결성이 올바른 앱의 작동에 영향을 줍니다. 이러한 상황에서는 다음 두 가지 옵션 중 하나를 선택할 수 있습니다.
- 복사와 붙여넣기를 모두 제어하는 경우(예: 같은 방법으로 앱에 붙여넣으려면 Async Clipboard API의 웹 맞춤 형식 여기를 읽지 않고 링크된 도움말을 확인하세요.
- 앱의 붙여넣기 끝만 제어하고 복사 끝은 제어하지 않는 경우
지원되지 않는 기본 앱에서 복사 작업이 발생하기 때문일 수 있습니다.
웹 맞춤 형식을 사용하려면
unsanitized
옵션을 사용해야 합니다. 이 도움말의 나머지 부분에 설명되어 있습니다.
정리에는 script
태그 삭제, 인라인 스타일 지정,
HTML 형식이 올바른지 확인해야 합니다. 포괄적이지 않은 목록 등
향후 추가될 수 있습니다.
정리되지 않은 HTML을 복사하여 붙여넣기
Async Clipboard API를 사용하여 HTML을 클립보드에 write()
(복사)할 때
브라우저는 DOM 파서를 통해 실행하여 형식이 올바른지 확인합니다.
결과 HTML 문자열을 직렬화하는 동시에
다음 단계를 따르세요. 별도의 조치가 필요하지 않습니다. HTML 페이지에 배치된 read()
를
클립보드를 사용하고 웹 앱이
자체 코드에서 정리 작업을 수행해야 하는 경우
속성을 사용하여 옵션 객체를 read()
메서드에 전달할 수 있습니다.
unsanitized
및 ['text/html']
의 값 격리하면 다음과 같이 표시됩니다.
navigator.clipboard.read({ unsanitized: ['text/html'] })
다음 코드 샘플
아래는 이전에 표시된 것과 거의 동일하지만 이번에는 unsanitized
를 사용합니다.
옵션을 선택합니다. DevTools 콘솔에서 실행해 보면 입력과
출력은 동일합니다.
setTimeout(async () => {
const input = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="ProgId" content="Excel.Sheet" />
<meta name="Generator" content="Microsoft Excel 15" />
<style>
body {
font-family: HK Grotesk;
background-color: var(--color-bg);
}
</style>
</head>
<body>
<div>hello</div>
</body>
</html>`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html'],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
console.log(input, output);
}, 3000);
브라우저 지원 및 기능 감지
이 기능이 지원되는지 확인할 수 있는 직접적인 방법은 없으므로
감지는 행동 관찰을 기반으로 합니다. 따라서 다음 예는
<style>
태그가 유지되는지 여부를 감지하는 기능을 사용합니다.
는 지원을 나타내거나 인라인으로 표시되어 지원되지 않음을 나타냅니다. 참고:
이 기능이 작동하려면 페이지에 이미 클립보드가 있어야 합니다.
권한을 부여했는지 확인합니다.
const supportsUnsanitized = async () => {
const input = `<style>p{color:red}</style><p>a`;
const inputBlob = new Blob([input], { type: 'text/html' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': inputBlob,
}),
]);
const [clipboardItem] = await navigator.clipboard.read({
unsanitized: ['text/html],
});
const outputBlob = await clipboardItem.getType('text/html');
const output = await outputBlob.text();
return /<style>/.test(output);
};
데모
unsanitized
옵션의 작동 방식을 확인하려면 다음을 참고하세요.
Glitch에 대한 데모를 살펴보고
소스 코드를 참고하세요.
결론
소개에서 설명한 것처럼 대부분의 개발자는
기본 정리 옵션을 그대로 사용할 수 있습니다.
만드는 것입니다. 개발자가 신경 써야 하는 드문 경우에는
unsanitized
옵션이 존재합니다.
유용한 링크
감사의 말씀
이 도움말은 Anupam Snigdha에서 검토했으며 레이첼 앤드류. API가 지정되었으며 Microsoft Edge팀에서 구현합니다.