웹 개발 데일리 브리핑 — 2026-11-11
Soshy··조회수 —

기준 시점: 2026-11-11 06:00 KST
조사 범위: 전일 2026-11-10 06:00 ~ 당일 2026-11-11 06:00 KST
추천 글 범위: 기준 시점 당시 최근 7일
1️⃣ 프론트엔드
Astro 7.4.9·7.4.10 공개 — 엄격한 CSP 환경의 Hydration 오류, 정적 경로 생성 및 중복 CSS 로딩 수정
- 발표일: 2026-11-10
- GitHub 릴리스 표시 시각: 7.4.9는 18:33, 7.4.10은 20:09 — 표시 시간대 미확인
- 버전: Astro 7.4.9, 7.4.10
- 안정화 단계: 정식 안정 버전의 패치 릴리스
- 적용 대상: Astro, 정적 페이지 생성, Content Security Policy, Hydration, CSS 번들링, 개발 도구
- 원문: https://github.com/withastro/astro/releases/tag/astro@7.4.9
- 후속 패치: https://github.com/withastro/astro/releases/tag/astro@7.4.10
Astro가 7.4 계열의 두 패치를 공개했다.
이번 업데이트는 새로운 프레임워크 API를 추가하는 릴리스가 아니다. 대신 실제 배포 환경에서 페이지 생성이나 클라이언트 JavaScript 실행이 실패할 수 있던 문제를 수정했다.
특히 엄격한 Content Security Policy를 사용하는 사이트에서 Hydration에 필요한 Script가 차단되던 문제와 서버가 이미 제공한 CSS를 클라이언트 번들이 중복으로 로딩하던 문제가 중요하다.
엄격한 CSP에서 번들 Script가 차단되던 문제
Astro는 정적 HTML을 기본으로 생성하면서 실제 상호작용이 필요한 컴포넌트에만 클라이언트 JavaScript를 제공하는 구조를 지원한다.
예를 들어 제품 소개 페이지를 생각할 수 있다.
페이지의 대부분은 정적인 HTML이다.
하지만 상품 검색이나 필터 UI는 React 또는 Vue 컴포넌트로 구현할 수 있다.
이러한 컴포넌트는 브라우저에서 Hydration을 수행해야 할 수 있다.
Hydration은 서버가 생성한 HTML에 클라이언트의 이벤트 처리와 상태를 연결하는 과정이다.
문제는 CSP 설정이 엄격한 경우다.
CSP(Content Security Policy)는 웹페이지가 어떤 Script와 리소스를 로딩하거나 실행할 수 있는지 제한하는 보안 정책이다.
예를 들어 다음과 같은 정책을 사용할 수 있다.
script-src 'strict-dynamic'
strict-dynamic은 신뢰할 수 있는 Script를 기준으로 다른 Script의 로딩을 제어하는 정책과 연결된다.
하지만 실제 번들에 포함된 Script의 신뢰 정보를 올바르게 제공하지 않으면 필요한 JavaScript가 차단될 수 있다.
기존 Astro에서는 security.csp.scriptDirective.strictDynamic을 활성화한 환경에서 이러한 문제가 발생할 수 있었다.
결과적으로 다음 상황이 가능했다.
- 서버가 HTML을 정상적으로 생성한다.
- 브라우저가 페이지를 표시한다.
- CSP가 일부 번들 Script를 차단한다.
- Hydration이 실행되지 않는다.
- 상호작용해야 하는 컴포넌트가 정상적으로 동작하지 않는다.
이번 7.4.9에서는 이 문제를 수정했다.
Astro는 번들에 포함된 각 Script의 Hash를 CSP의 script-src에 추가한다.
또한 <head>에 생성하는 Import Map에도 해당 리소스의 Integrity 정보를 포함한다.
이렇게 하면 실제 빌드 결과물과 브라우저가 실행할 수 있는 Script 사이의 관계를 명확하게 표현할 수 있다.
다만 이번 변경이 모든 CSP 설정에서 모든 외부 Script를 자동으로 허용한다는 의미는 아니다.
애플리케이션이 사용하는 외부 SDK나 직접 작성한 Inline Script에는 별도의 정책이 필요할 수 있다.
또한 이번 수정은 CSP를 비활성화하는 방식이 아니다.
엄격한 CSP를 유지하면서 Astro가 생성한 정상적인 번들 Script를 실행할 수 있도록 신뢰 정보를 보완한 변경이다.
getStaticPaths()의 특수문자 처리
정적 페이지 생성과 관련된 문제도 수정됐다.
Astro에서는 동적 경로를 정적으로 생성할 때 다음 함수를 사용할 수 있다.
getStaticPaths()
예를 들어 기술 블로그의 게시글 경로를 생성한다고 가정해 보자.
다음과 같은 경로가 존재할 수 있다.
/posts/hello/posts/vue/posts/nextjs
이러한 경로는 일반적인 영문자만 포함하므로 문제가 드러나지 않을 수 있다.
하지만 실제 URL Parameter에는 특수문자가 포함될 수 있다.
이번 수정에서 언급된 대표적인 문자는 다음과 같다.
%\
기존에는 이러한 문자가 getStaticPaths()의 Parameter에 포함됐을 때 정적 빌드가 실패하거나 일부 페이지가 건너뛰어질 수 있었다.
이번 패치는 해당 경로의 처리 방식을 수정했다.
또한 Prerendering 중 빈 오류 응답 때문에 페이지를 건너뛰었다면 경고를 출력하도록 변경했다.
이러한 변경은 빌드가 완료됐다는 사실만으로 모든 페이지가 생성됐다고 판단하기 어려운 문제를 줄인다.
예를 들어 CMS에서 가져온 Slug에 특수문자가 포함돼 있다면 실제 생성된 파일과 URL의 관계를 확인할 필요가 있다.
하지만 이번 수정이 모든 문자열을 별도 검증 없이 안전한 URL로 변환한다는 의미는 아니다.
콘텐츠의 Slug를 생성하고 인코딩하는 규칙은 애플리케이션에서도 관리해야 한다.
Root-relative Script의 번들링
다음과 같은 Script를 생각할 수 있다.
<script src="/lib/analytics.ts">
실제 파일은 프로젝트 안에 존재한다.
하지만 해당 파일이 src/ 바깥에 있을 수 있다.
기존 Astro에서는 이러한 Root-relative 경로를 잘못 판단해 is:inline을 사용하라는 오류를 출력할 수 있었다.
이번 7.4.9에서는 해당 오류의 발생 조건을 수정했다.
실제 경로가 public/ 안의 파일을 가리키는 경우에만 관련 오류를 표시하도록 변경했다.
이는 Script의 경로가 Root-relative라는 사실과 해당 파일을 Bundler가 처리할 수 있는지를 구분하는 수정이다.
이미 응답을 스트리밍한 뒤 발생한 오류
SSR 환경에서는 서버가 HTML을 한 번에 반환하지 않고 스트리밍할 수 있다.
예를 들어 페이지 상단의 HTML을 먼저 전달한다.
이후 서버에서 데이터를 가져와 나머지 콘텐츠를 전달한다.
그런데 일부 HTML을 이미 전송한 이후 오류가 발생할 수 있다.
이 시점에는 HTTP 응답 전체를 처음부터 다시 생성하기 어려울 수 있다.
따라서 실제 오류의 기록과 처리 방식이 중요하다.
기존 Astro에서는 응답 스트리밍이 시작된 이후 발생한 일부 오류가 설정한 Logger를 거치지 않을 수 있었다.
이번 수정은 해당 오류를 Logger를 통해 한 번만 기록하도록 한다.
개발 환경인 astro dev와 실제 운영 환경 모두에 적용된다.
이러한 변경은 오류 자체를 자동으로 복구하는 기능이 아니다.
실제로 문제가 발생했을 때 로그가 누락되거나 중복으로 기록되는 상황을 줄이기 위한 것이다.
7.4.10: Hydrated Island의 CSS 중복 로딩 방지
후속 패치인 7.4.10에서는 CSS 로딩 문제가 수정됐다.
Astro에서는 React나 Vue 등의 컴포넌트를 Island 형태로 사용할 수 있다.
Island는 페이지 전체가 아니라 실제 상호작용이 필요한 일부 UI에만 클라이언트 JavaScript를 사용하는 구조다.
문제는 여러 Island가 동일한 Module을 참조하는 경우였다.
예를 들어 다음 컴포넌트가 있다고 가정해 보자.
- 검색 필터
- 정렬 버튼
- 페이지 이동 컴포넌트
세 컴포넌트는 동일한 UI 라이브러리의 CSS를 사용할 수 있다.
서버 빌드는 해당 CSS를 HTML에 연결한다.
하지만 기존 클라이언트 빌드에서도 같은 CSS를 다시 포함하거나 Preload할 수 있었다.
이러한 문제는 다음 상황에서 발생할 수 있었다.
- 여러 Island가 같은 Module 사용
- Path Alias를 통해 동일한 Module Import
7.4.10에서는 클라이언트 빌드가 서버에서 이미 연결한 Stylesheet를 다시 출력하거나 Preload하지 않도록 수정했다.
이렇게 하면 불필요한 CSS 요청과 자산 중복을 줄일 수 있다.
다만 공식 발표에는 중복 CSS가 실제로 몇 KB 감소했는지에 관한 수치가 포함되지 않았다.
따라서 모든 Astro 프로젝트에서 CSS 전송량이 특정 비율만큼 감소한다고 판단할 수 없다.
SVGO의 지연 로딩
7.4.10에는 CLI 시작 과정의 최적화도 포함됐다.
기존에는 astro/config를 Import하는 과정에서 SVGO가 함께 로딩될 수 있었다.
SVGO는 SVG를 최적화하는 도구다.
하지만 실제로 모든 Astro 명령이 SVG를 최적화하는 것은 아니다.
예를 들어 단순히 설정 정보를 읽는 작업에서는 SVG 최적화가 필요하지 않을 수 있다.
이번 변경에서는 svgoOptimizer()가 실제로 SVG를 최적화할 때만 SVGO를 로딩하도록 변경했다.
이는 사용하지 않는 Module의 초기화 비용을 줄이기 위한 것이다.
하지만 공식 릴리스에는 CLI 시작 시간이 얼마나 감소했는지에 관한 Benchmark가 포함되지 않았다.
Safari의 개발 도구 오류
Astro Dev Toolbar의 Audit 기능도 수정됐다.
기존에는 Safari에서 이미지의 크기를 확인하는 과정이 CSS Animation을 멈추게 할 수 있었다.
새로운 방식에서는 이미지를 다시 가져오는 대신 해당 이미지를 로딩한 기존 요청에서 크기 정보를 읽는다.
따라서 개발 도구의 검사 작업이 실제 페이지의 애니메이션에 영향을 주는 문제를 줄인다.
적용 범위와 한계
이번 두 릴리스는 정식 안정 패치다.
특히 다음 환경에서 관련성이 높다.
- 엄격한 CSP 사용
- React·Vue Island Hydration 사용
- 정적 경로에 특수문자가 포함될 가능성
- SSR Streaming 사용
- 여러 Island가 공통 CSS Module 사용
하지만 이번 발표에는 전체 페이지의 LCP나 INP, 빌드 시간에 관한 정량적인 비교 결과가 없다.
따라서 기능의 정확성 수정과 일반적인 성능 개선을 구분해야 한다.
이번 업데이트는 Astro의 정적 생성과 SSR, CSP 및 클라이언트 자산 처리에서 발생하던 실제 호환성 문제를 수정한 안정 패치다.
Vercel Speed Insights·Web Analytics, Custom Environment별 통계 정식 지원 — Staging·QA·Canary 트래픽 분리
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: Vercel
- 안정화 단계: 정식 기능
- 적용 대상: Speed Insights, Web Analytics, Vercel Custom Environments
- 지원 요금제: Pro, Enterprise
- 원문: https://vercel.com/changelog/speed-insights-and-web-analytics-now-support-custom-environments
Vercel이 Speed Insights와 Web Analytics에서 Custom Environment별로 성능 및 트래픽을 분리해 확인할 수 있도록 기능을 확장했다.
이번 변경은 새로운 분석 SDK를 도입하는 업데이트가 아니다.
기존에 수집하던 데이터를 어떤 배포 환경에 연결할지 결정하는 방식을 변경한 것이다.
기존 Preview 환경의 문제
예를 들어 하나의 웹 애플리케이션에 다음 환경이 존재한다고 가정해 보자.
- Production
- Preview
- Staging
- QA
- Canary
Production은 실제 사용자가 사용하는 환경이다.
Preview는 일반적으로 개발 중인 변경 사항을 확인하는 데 사용할 수 있다.
Staging과 QA는 배포 전 검증에 사용할 수 있다.
Canary는 새로운 버전을 제한된 사용자에게 먼저 제공하는 데 사용할 수 있다.
문제는 기존 분석 데이터의 분류 방식이었다.
Vercel의 Custom Environment에서 발생한 트래픽과 성능 정보가 Preview 환경에 포함됐다.
따라서 Staging의 성능과 일반적인 Preview Deployment의 성능을 정확하게 구분하기 어려웠다.
이번 변경에서는 데이터를 실제 Custom Environment에 연결하도록 수정했다.
환경별 성능 비교
예를 들어 Staging에 새로운 이미지 최적화 기능을 배포했다고 가정해 보자.
개발자는 실제 운영 환경과 Staging의 LCP를 비교하고 싶을 수 있다.
LCP(Largest Contentful Paint)는 화면의 주요 콘텐츠가 표시되는 시점을 측정하는 웹 성능 지표다.
기존에는 Staging의 측정 결과가 다른 Preview 데이터와 섞일 수 있었다.
새로운 방식에서는 다음 환경을 독립적으로 선택할 수 있다.
- Production
- Preview
- Staging
- QA
- Canary
따라서 실제 배포 환경별로 측정 결과를 확인할 수 있다.
하지만 환경별 데이터가 분리됐다는 사실만으로 같은 조건의 성능 비교가 이루어지는 것은 아니다.
실제로 다음 조건이 서로 다를 수 있다.
- 접속한 사용자의 기기
- 네트워크 환경
- 데이터베이스의 데이터량
- 접속 지역
- 트래픽 규모
따라서 Staging의 성능 점수가 Production보다 높다고 해서 새로운 코드가 반드시 더 빠르다고 단정해서는 안 된다.
Dashboard와 CLI
새로운 환경 정보는 여러 인터페이스에서 사용할 수 있다.
| 인터페이스 | 지원 내용 |
|---|---|
| Speed Insights Dashboard | 환경별 성능 데이터 선택 |
| Web Analytics Dashboard | 환경별 트래픽 분석 |
vc metrics | CLI에서 환경별 Metric 조회 |
| Query Builder | 환경별 필터 및 분석 |
| Aggregation API | 환경별 Web Analytics 데이터 조회 |
여기서 중요한 제한이 존재한다.
Aggregation API의 이번 지원은 Web Analytics에 한정된다.
따라서 Speed Insights의 모든 데이터를 같은 Aggregation API에서 동일하게 가져올 수 있다고 가정해서는 안 된다.
새로운 데이터 수집이 아님
Vercel은 이번 변경이 실제로 데이터를 새롭게 수집하는 기능이 아니라고 명시했다.
기존에 수집하던 데이터의 귀속 환경을 변경한다.
따라서 다음 작업은 필요하지 않다.
- 분석 SDK 교체
- 새로운 Script 설치
- 별도 설정 변경
다만 해당 기능을 사용하려면 Custom Environment를 지원하는 요금제와 프로젝트 구성이 필요하다.
이번 발표에는 실제 사용자 성능의 개선 수치가 포함되지 않았다.
이는 분석의 정확성을 높이는 변경이지 페이지를 더 빠르게 렌더링하는 기능이 아니다.
여러 배포 환경을 운영하는 팀이 실제 환경별 성능과 트래픽을 분리해 분석할 수 있도록 Observability의 데이터 분류 방식을 개선한 업데이트다.
React, Vue, Nuxt, Angular, Svelte, SvelteKit, Remix의 공식 블로그와 릴리스 채널에서도 조사 범위에 해당하는 주요 신규 안정 기능은 확인하지 못했습니다.
Next.js 16.5.0-canary.46에서는 Parallel Route Parameter 처리와 Prerendering, Fetch Cache Lock 관련 수정이 확인됐다.
하지만 Canary 개발 버전이며, 이번 변경을 새로운 안정 기능의 출시로 취급하기는 어려워 별도 주요 뉴스로 선정하지 않았다.
2️⃣ 웹 플랫폼·브라우저
Firefox 160 정식 출시 — WebTransport 표준 정합성 개선, 기기 내 음성 인식과 다수의 보안 취약점 수정
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: Mozilla
- 버전: Firefox 160
- 안정화 단계: 정식 안정 버전
- 적용 대상: WebTransport, Web Speech API, CSS, Web Extensions, 브라우저 보안
- 원문: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/160
- 공식 보안 권고: https://www.mozilla.org/en-US/security/advisories/mfsa2026-125/
Mozilla가 Firefox 160을 정식 출시했다.
이번 버전에서 웹 개발자가 주목할 부분은 WebTransport API의 표준 정합성 개선과 데스크톱 기기 내 음성 인식 지원이다.
또한 다수의 보안 취약점이 수정됐다.
다만 이번 업데이트에 포함된 모든 실험 기능이 일반 사용자에게 기본 활성화된 것은 아니다.
특히 Render Blocking과 미디어 Lazy Loading 등 일부 기능은 별도의 설정을 활성화해야 한다.
WebTransport의 역할
WebTransport는 웹 애플리케이션에서 서버와 데이터를 주고받기 위한 기술이다.
일반적인 HTTP 요청과 다른 통신 요구사항을 처리할 수 있다.
대표적으로 다음 기능을 제공한다.
- 양방향 Stream
- 단방향 Stream
- Datagram
- 연결 상태 관리
예를 들어 실시간 협업 서비스나 게임을 생각할 수 있다.
일부 데이터는 반드시 순서대로 전달돼야 한다.
반면 현재 커서 위치처럼 최신 상태가 중요하고 과거 데이터의 손실을 허용할 수 있는 정보도 존재한다.
WebTransport는 이러한 서로 다른 전송 요구사항을 처리하는 데 활용할 수 있다.
Session 생성 시 Custom Header
Firefox 160에서는 다음 생성자의 옵션이 확장됐다.
new WebTransport(url, options)
새로운 옵션은 다음과 같다.
headers
이는 WebTransport Session을 생성할 때 사용하는 Extended CONNECT 요청에 Custom HTTP Header를 추가하도록 한다.
서버가 반환한 Response Header는 Session이 생성된 이후 다음 속성에서 확인할 수 있다.
WebTransport.responseHeaders
이러한 기능은 연결 설정 과정에서 추가적인 Metadata를 교환하는 데 도움이 된다.
다만 Custom Header를 사용할 수 있다고 해서 모든 종류의 인증 정보를 임의로 전달하는 것이 안전하다는 의미는 아니다.
실제 인증 방식은 서버의 정책과 WebTransport 규격의 제약을 고려해야 한다.
exportKeyingMaterial()의 호환성 변경
이번 릴리스에는 기존 코드의 수정이 필요할 수 있는 변경도 존재한다.
대상 메서드는 다음과 같다.
WebTransport.exportKeyingMaterial()
이 메서드는 연결에서 사용하는 암호학적 정보를 바탕으로 추가적인 Keying Material을 생성하는 기능이다.
기존 Firefox에서는 출력 크기가 32바이트로 고정돼 있었다.
새로운 버전에서는 표준에 맞춰 다음 인자를 요구한다.
contextoutputLength
context는 이제 필수 인자다.
outputLength는 생성할 Byte 수를 지정한다.
따라서 기존 코드에서 인자 없이 호출했다면 새로운 Firefox에서는 수정이 필요할 수 있다.
이번 변경은 단순한 성능 최적화가 아니다.
기존 구현과 최신 표준 사이의 차이를 줄이는 과정에서 사용자 코드의 호환성에 영향을 줄 수 있는 API 변경이다.
Datagram Buffer 속성 변경
WebTransport의 Datagram 처리 속성도 변경됐다.
새로운 속성은 다음과 같다.
incomingMaxBufferedDatagramsoutgoingMaxBufferedDatagrams
기존의 비표준 속성은 제거됐다.
incomingHighWaterMarkoutgoingHighWaterMark
새로운 속성은 실제 Datagram의 Buffer에 들어갈 수 있는 개수와 Backpressure 관련 동작을 표현한다.
Backpressure는 데이터를 생성하거나 전송하는 속도가 실제로 처리할 수 있는 속도보다 빠를 때 작업을 제한하는 방식이다.
예를 들어 서버가 매우 빠르게 데이터를 전송하지만 브라우저가 이를 처리하지 못한다고 가정해 보자.
Buffer에 데이터가 계속 쌓이면 메모리 사용량이 증가할 수 있다.
따라서 Buffer의 허용 범위와 전송 속도를 제어해야 한다.
이번 변경을 적용할 때는 기존 비표준 속성에 의존한 코드가 존재하는지 확인할 필요가 있다.
BYOB 방식의 Datagram 읽기
이번 릴리스에서는 다음 옵션도 지원한다.
datagramsReadableType: "bytes"
이 설정을 사용하면 Datagram의 Readable Stream을 Byte Stream으로 처리할 수 있다.
이후 다음 Reader를 사용할 수 있다.
ReadableStreamBYOBReader
BYOB는 Bring Your Own Buffer의 약자다.
일반적인 방식에서는 새로운 Datagram이 도착할 때마다 새로운 Uint8Array를 생성할 수 있다.
반면 BYOB 방식에서는 개발자가 준비한 Buffer를 전달하고 해당 Buffer에 데이터를 읽을 수 있다.
이렇게 하면 특정 상황에서 불필요한 객체 할당을 줄일 수 있다.
하지만 실제 성능 개선은 데이터 크기와 빈도, Buffer 재사용 방식에 영향을 받는다.
Firefox는 이번 변경에 관한 정량적인 성능 Benchmark를 공개하지 않았다.
동시 Stream 수 관련 설정
다음 속성도 추가됐다.
anticipatedConcurrentIncomingUnidirectionalStreamsanticipatedConcurrentIncomingBidirectionalStreams
이 값은 애플리케이션이 동시에 열릴 것으로 예상하는 Incoming Stream의 수를 표현한다.
따라서 WebTransport를 사용하는 애플리케이션에서 전송 구조를 보다 명확하게 설정할 수 있다.
다만 실제 연결의 최대 처리량과 서버의 허용 범위는 별도의 조건에 영향을 받을 수 있다.
기기 내 음성 인식
Firefox 160에서는 데스크톱 환경에서 Web Speech API를 이용한 기기 내 음성 인식이 제공된다.
Mozilla는 40개 언어의 실시간 Speech-to-text 변환을 지원한다고 설명한다.
예를 들어 사용자가 웹 애플리케이션의 입력창에 음성으로 내용을 입력하는 기능을 생각할 수 있다.
브라우저는 사용자의 음성을 텍스트로 변환할 수 있다.
이번 기능은 기기 내 인식 방식이다.
다만 중요한 제한사항이 있다.
- Android에서는 지원하지 않는다.
- 원격 Cloud 기반 음성 인식도 지원하지 않는다.
따라서 Firefox 160을 사용한다는 사실만으로 모든 데스크톱과 모바일 환경에서 같은 음성 입력 기능을 사용할 수 있다고 판단해서는 안 된다.
실제로 어떤 언어 모델을 사용할 수 있는지도 확인해야 한다.
CSS 호환성 개선
Firefox 160에서는 다음 Pseudo-element를 지원한다.
::-webkit-input-placeholder
이 값은 다음 표준 Pseudo-element의 Alias로 처리된다.
::placeholder
이는 기존 WebKit 계열의 문법을 사용한 웹사이트와의 호환성을 높이기 위한 것이다.
예를 들어 어떤 사이트가 Placeholder의 색상을 비표준 WebKit Prefix로만 지정했다고 가정해 보자.
기존 Firefox에서는 해당 스타일이 적용되지 않을 수 있었다.
새로운 버전에서는 해당 표현을 표준 Placeholder 스타일과 연결해 처리할 수 있다.
하지만 새로운 프로젝트에서 비표준 Prefix만 사용해야 한다는 의미는 아니다.
가능하면 표준 ::placeholder를 사용하는 편이 적절하다.
제거된 비표준 이벤트
Firefox 160은 다음 이벤트를 웹페이지에 더 이상 전달하지 않는다.
MozScrolledAreaChanged
이 이벤트는 문서의 스크롤 가능한 영역 크기가 변경될 때 발생하던 Firefox 전용 이벤트다.
기존 코드가 해당 이벤트를 사용했다면 동작이 변경될 수 있다.
Mozilla는 내부 설정을 이용해 이전 동작을 복원할 수 있다고 설명한다.
하지만 웹 애플리케이션의 일반적인 사용자에게 브라우저 설정 변경을 요구하는 것은 적절하지 않다.
실제 필요한 기능에 따라 표준 API로 이전하는 방법을 검토해야 한다.
기본 비활성화된 실험 기능
이번 버전에는 실험 기능도 포함됐다.
대표적으로 다음과 같다.
blocking="render"<video loading="lazy"><audio loading="lazy">
하지만 이러한 기능은 기본적으로 비활성화돼 있다.
예를 들어 blocking="render"는 특정 리소스의 처리 완료까지 렌더링을 지연할 수 있도록 하는 기능이다.
또한 Video와 Audio의 Lazy Loading은 실제로 필요한 시점까지 미디어 로딩을 지연하는 데 사용할 수 있다.
그러나 Firefox 160에서 관련 코드를 작성했다고 해서 모든 사용자에게 동작한다고 가정해서는 안 된다.
실제 기능 활성화 상태와 다른 브라우저의 지원 범위를 확인해야 한다.
Firefox 160의 보안 수정
Mozilla는 이번 버전과 함께 보안 권고 MFSA 2026-125를 공개했다.
공식 권고에는 High Impact로 분류된 취약점들이 포함돼 있다.
대표적인 항목은 다음과 같다.
| CVE | 문제 |
|---|---|
| CVE-2026-124853 | Graphics: Text의 경계 조건 오류를 이용한 Sandbox Escape |
| CVE-2026-124854 | DOM Navigation의 권한 상승 |
| CVE-2026-124855 | DOM Navigation의 Sandbox Escape |
| CVE-2026-124857 | Canvas2D의 Use-after-free |
| CVE-2026-124858 | HTML Parser의 Use-after-free |
| CVE-2026-124859 | Cache API 관련 Sandbox Escape |
| CVE-2026-124864 | Service Workers의 Use-after-free 관련 Sandbox Escape |
Use-after-free는 이미 해제된 메모리에 다시 접근하는 문제다.
이러한 취약점은 실제 프로그램의 실행 상태와 메모리 안전성에 영향을 줄 수 있다.
Sandbox Escape는 격리된 실행 환경의 경계를 벗어나는 공격과 관련된다.
브라우저에서는 웹 콘텐츠가 운영체제나 다른 프로세스의 권한에 직접 접근하지 못하도록 격리하는 것이 중요하다.
이번 수정은 이러한 경계를 강화한다.
다만 공식 권고에서 High Impact로 분류됐다는 사실만으로 해당 취약점이 실제 공격에서 활발하게 악용됐다고 판단해서는 안 된다.
이번 확인 범위에서는 실제 악용 여부를 별도로 확정할 수 있는 근거가 없었다.
적용 범위와 한계
Firefox 160은 정식 안정 버전이다.
하지만 이번 릴리스에 포함된 모든 기능이 동일한 지원 범위를 가지는 것은 아니다.
특히 다음 세 가지를 구분해야 한다.
- 기본적으로 제공되는 WebTransport API 변경
- 데스크톱에 한정된 기기 내 음성 인식
- 별도 설정이 필요한 실험 기능
또한 WebTransport의 일부 변경은 기존 Firefox 전용 구현에 의존한 코드를 수정해야 할 수 있다.
이번 릴리스는 실시간 전송 API의 표준 정합성과 브라우저 기능을 확대하면서 여러 보안 취약점을 수정한 정식 브라우저 업데이트다.
W3C, WHATWG, TC39, MDN, Chromium, WebKit·Safari의 이번 조사 범위에서 이외에 포함할 만한 주요 신규 발표는 확인하지 못했습니다.
이번 기간의 브라우저 개발 빌드와 표준화 논의는 정식 기능 출시와 구분했으며, 이전 브리핑에서 다룬 Chrome 158 Beta와 Firefox 159의 내용은 반복하지 않았다.
3️⃣ 백엔드·인프라
Cloudflare Workflows, Workflow별 동시 실행 제한 정식 지원 — 초과 작업은 거부하지 않고 대기열로 이동
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: Cloudflare
- 안정화 단계: 정식 기능
- 적용 대상: Cloudflare Workflows, Workers
- 필요 버전: Wrangler 4.127.0 이상
- 원문: https://developers.cloudflare.com/changelog/post/2026-11-10-per-workflow-concurrency-limits/
Cloudflare가 각 Workflow에 서로 다른 동시 실행 제한을 설정할 수 있도록 기능을 확장했다.
이번 변경은 실제 서버리스 작업의 부하를 관리하는 데 영향을 준다.
특히 여러 Workflow가 같은 데이터베이스나 외부 API를 사용하는 서비스에서 활용할 수 있다.
기존 동시 실행 제한의 문제
예를 들어 다음 세 가지 Workflow를 운영한다고 가정해 보자.
- 사용자 이메일 발송
- PDF 문서 생성
- 대규모 데이터 동기화
세 Workflow는 서로 다른 자원을 사용한다.
이메일 발송은 외부 이메일 API에 요청을 보낸다.
PDF 생성은 CPU와 메모리를 사용한다.
데이터 동기화는 데이터베이스에 많은 요청을 보낼 수 있다.
따라서 세 Workflow의 적절한 동시 실행 수는 서로 다를 수 있다.
하지만 전체 계정의 동시 실행 한도만 존재한다면 특정 Workflow가 전체 실행 용량의 대부분을 사용할 수 있다.
예를 들어 대량의 PDF 생성 작업이 시작됐다고 가정해 보자.
이때 다른 중요한 작업이 실행할 자원을 확보하지 못할 수 있다.
이번 기능에서는 Workflow마다 별도의 제한을 설정할 수 있다.
concurrency.limit
새로운 설정은 다음과 같다.
concurrency.limit
Wrangler 설정에서는 특정 Workflow Binding에 해당 값을 추가한다.
예를 들어 다음과 같이 설정할 수 있다.
limit: 10
이 경우 동시에 실행할 수 있는 해당 Workflow의 인스턴스 수를 10개로 제한한다.
중요한 점은 동시 실행 한도를 초과한 작업을 실패 처리하지 않는다는 사실이다.
실행 중인 인스턴스가 이미 10개라면 추가 인스턴스는 Queue에 들어간다.
이후 실행 중이던 작업이 완료되면 대기 중인 작업이 시작된다.
또한 기존 인스턴스가 waiting 상태로 이동해 실행 용량을 반환하는 경우에도 다음 작업을 시작할 수 있다.
실행 중인 작업과 대기 중인 작업
예를 들어 제한이 10인 Workflow에 100개의 작업이 도착했다고 가정해 보자.
처음에는 10개 인스턴스가 실행된다.
나머지 작업은 대기한다.
실행 중인 작업이 완료되면 다음 작업이 실행된다.
이러한 구조는 외부 API의 동시 요청 수를 제한하는 데 사용할 수 있다.
예를 들어 외부 문서 생성 API가 동시에 20개 이상의 요청을 처리하면 응답 시간이 증가한다고 가정해 보자.
개발자는 실제 Workflow의 동시 실행 수를 제한할 수 있다.
하지만 여기에는 중요한 차이가 있다.
Workflow의 동시 실행 제한과 특정 외부 API의 실제 동시 요청 수가 반드시 일치하는 것은 아니다.
예를 들어 하나의 Workflow 인스턴스가 외부 API를 동시에 다섯 번 호출할 수 있다.
이 경우 Workflow가 10개 실행된다면 실제 외부 API 요청은 50개까지 증가할 수 있다.
따라서 Workflow의 실행 구조를 함께 고려해야 한다.
계정 전체 한도
Workflow별 제한은 계정 전체 한도보다 높게 설정할 수 없다.
Cloudflare가 공개한 한도는 다음과 같다.
| 요금제 | 계정 전체 동시 실행 한도 |
|---|---|
| Workers Free | 100 |
| Workers Paid | 50,000 |
개별 Workflow의 concurrency.limit는 양의 정수여야 한다.
따라서 0이나 음수는 사용할 수 없다.
또한 제한을 설정하지 않은 Workflow는 계정 전체 동시 실행 한도까지 사용할 수 있다.
즉 개별 Workflow 제한을 설정했다고 해서 계정 전체의 실행 한도가 변경되는 것은 아니다.
실행 중인 인스턴스의 처리
예를 들어 기존에 제한 없이 50개의 인스턴스가 실행되고 있다고 가정해 보자.
개발자가 해당 Workflow의 동시 실행 한도를 10으로 변경한다.
이 경우 이미 실행 중인 50개 인스턴스를 강제로 종료하지 않는다.
새로운 제한은 이후 실행되는 작업의 배치에 적용된다.
따라서 실제로 실행 중인 작업을 즉시 중단하는 기능으로 사용해서는 안 된다.
배포 설정의 중요한 제한사항
Cloudflare는 다음 사항을 명시했다.
Workflow의 동시 실행 제한을 유지하려면 매 배포마다 concurrency.limit를 설정해야 한다.
예를 들어 개발자가 첫 번째 배포에서는 제한을 10으로 설정했다고 가정해 보자.
하지만 다음 배포의 설정 파일에서는 해당 값을 제거했다.
그러면 Workflow별 제한도 제거된다.
따라서 이 기능은 Dashboard에 한 번 설정한 뒤 영구적으로 유지되는 독립적인 정책이 아니다.
실제 배포 설정의 일부로 관리해야 한다.
적용 범위와 한계
이번 기능은 정식 지원된다.
Wrangler 4.127.0 이상이 필요하다.
공식 발표에는 실제 Workflow의 실행 처리량이나 외부 API 오류율이 얼마나 개선되는지에 관한 Benchmark가 포함되지 않았다.
또한 동시 실행을 제한하면 전체 처리 시간이 늘어날 수 있다.
예를 들어 100개의 작업을 동시에 실행하던 서비스를 10개로 제한한다면 나머지 작업은 기다려야 한다.
따라서 제한의 목적은 모든 작업을 더 빨리 완료하는 것이 아니라 특정 Workflow가 사용하는 동시 실행 자원을 관리하고 외부 시스템의 처리 용량을 초과하지 않도록 하는 것이다.
Amazon OpenSearch Service, Clone 기반 버전 업그레이드와 Rollback 지원 — 기존 클러스터를 유지한 채 새 버전 검증
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: AWS
- 안정화 단계: 정식 기능
- 적용 대상: Amazon OpenSearch Service
- 지원 원본 버전: OpenSearch 1.1 이상 또는 Elasticsearch 7.10
- 원문: https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-opensearch-service/upgrades/
AWS가 OpenSearch Service의 버전을 업그레이드할 때 기존 클러스터를 유지하면서 새로운 버전의 클러스터를 먼저 검증할 수 있는 기능을 공개했다.
이번 기능은 실제 서비스의 검색 엔진을 업그레이드하는 과정에서 발생하는 위험을 줄이기 위한 것이다.
특히 검색 결과의 정확성과 응답 지연이 중요한 서비스에서 의미가 크다.
기존 버전 업그레이드의 어려움
예를 들어 전자상거래 웹서비스에서 OpenSearch를 사용한다고 가정해 보자.
사용자는 검색창에 상품 이름을 입력한다.
서버는 OpenSearch Query를 실행한다.
이후 검색 결과를 사용자에게 반환한다.
문제는 검색 엔진의 버전을 변경하는 경우다.
새로운 버전에서는 다음 부분의 동작이 달라질 수 있다.
- Query 처리
- 검색 결과 정렬
- Analyzer
- Index 설정
- 일부 API
- Plugin 호환성
- 메모리 및 CPU 사용량
따라서 단순히 새 버전이 출시됐다는 이유로 실제 서비스의 검색 클러스터를 즉시 교체하기 어렵다.
특히 문제가 발생했을 때 이전 버전으로 돌아갈 방법이 필요하다.
Clone 기반 업그레이드
새로운 기능에서는 다음 두 클러스터를 사용한다.
첫 번째는 Primary Cluster다.
현재 실제 서비스를 처리하는 클러스터다.
두 번째는 Cloned Cluster다.
새로운 OpenSearch 버전으로 실행하는 검증용 클러스터다.
전체 흐름은 다음과 같다.
- 기존 Primary Cluster를 유지한다.
- 새로운 버전의 Cloned Cluster를 생성한다.
- 기존 데이터를 Clone으로 복사한다.
- 같은 검색 Query를 두 클러스터에서 실행한다.
- 결과와 성능을 비교한다.
- 문제가 없으면 새로운 클러스터로 전환한다.
중요한 점은 실제 운영 중인 Primary Cluster가 검증 기간에도 계속 서비스를 처리할 수 있다는 사실이다.
따라서 실제 사용자 요청을 중단하고 새 버전의 동작을 확인하는 방식보다 전환 위험을 줄일 수 있다.
실제 Query 결과 비교
예를 들어 다음 Query를 생각할 수 있다.
상품 이름에 "wireless"가 포함된 상품 검색
기존 버전에서는 100개의 결과가 반환된다.
하지만 새로운 버전에서는 일부 Analyzer 동작이 변경돼 결과가 달라질 수 있다.
이러한 차이를 업그레이드 이전에 확인할 수 있다.
또한 실제 검색 결과의 정확성뿐 아니라 응답 지연도 비교할 수 있다.
AWS는 CloudWatch Metric을 이용해 두 클러스터의 성능을 비교하도록 안내한다.
하지만 실제 비교에서는 다음 조건을 고려해야 한다.
- 두 클러스터의 인스턴스 크기
- 데이터의 양
- Query의 종류
- Cache의 준비 상태
- 동시 요청 수
따라서 Cloned Cluster의 응답 시간이 낮다는 사실만으로 새 버전이 항상 더 빠르다고 판단해서는 안 된다.
Cutover
검증을 완료하면 새로운 클러스터로 전환할 수 있다.
이 과정을 Cutover라고 한다.
하지만 업그레이드 이후 실제 서비스에서 예상하지 못한 문제가 발생할 수 있다.
예를 들어 새로운 버전에서 특정 Query의 응답이 느려질 수 있다.
또는 기존에 사용하던 Plugin의 호환성 문제가 발견될 수 있다.
이번 기능에서는 일정 기간 이전 클러스터를 유지할 수 있다.
Rollback
개발자는 이전 버전을 보존할 기간을 선택할 수 있다.
해당 기간에는 이전 버전으로 Rollback할 수 있다.
따라서 새 버전으로 전환한 뒤 문제가 발생했더라도 처음부터 이전 클러스터를 구축하는 부담을 줄일 수 있다.
하지만 Rollback을 사용할 수 있다는 사실만으로 모든 데이터 변경을 자동으로 완벽하게 되돌릴 수 있다는 의미는 아니다.
실제 전환 이후에 발생한 쓰기 작업과 인덱스의 상태를 고려해야 한다.
따라서 실제 서비스의 쓰기 패턴과 전환 정책을 함께 검토해야 한다.
지원 범위와 제한사항
이번 기능은 다음 원본 버전을 지원한다.
- OpenSearch 1.1 이상
- Elasticsearch 7.10
AWS 상용 리전 가운데 OpenSearch Service를 지원하는 대부분의 리전에서 사용할 수 있다.
다만 다음 리전은 제외된다.
- Asia Pacific (New Zealand)
- Asia Pacific (Taipei)
- Asia Pacific (Thailand)
- Mexico (Central)
관리 방법은 다음과 같다.
- AWS Management Console
- AWS CLI
- OpenSearch Service API
이번 발표에는 버전 업그레이드 시간이 몇 퍼센트 감소하는지에 관한 Benchmark가 포함되지 않았다.
또한 추가 클러스터를 사용하는 만큼 실제 리소스 및 비용을 고려해야 한다.
이번 업데이트는 운영 중인 검색 서비스를 즉시 새로운 버전으로 교체하지 않고 실제 Query와 성능을 검증한 뒤 전환할 수 있도록 업그레이드 절차를 확장한 기능이다.
Amazon CloudWatch, PromQL Alarm으로 EC2·Application Auto Scaling 직접 제어 — OpenTelemetry Metric과 확장 정책 연결
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: AWS
- 안정화 단계: 정식 기능
- 적용 대상: Amazon CloudWatch, EC2 Auto Scaling, Application Auto Scaling
- 지원 정책: Simple Scaling, Step Scaling
- 미지원 정책: Target Tracking
- 원문: https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-cloudwatch-alarms-autoscaling-group-actions/
AWS가 PromQL을 사용하는 CloudWatch Alarm에서 EC2 및 Application Auto Scaling을 직접 실행할 수 있도록 기능을 확장했다.
이번 업데이트는 Observability와 실제 인프라의 확장 정책을 연결하는 기능이다.
특히 OpenTelemetry를 사용하는 백엔드 서비스에서 의미가 크다.
PromQL과 OpenTelemetry
PromQL(Prometheus Query Language)은 시계열 Metric을 조회하고 계산하는 데 사용하는 Query 언어다.
예를 들어 다음 정보를 분석할 수 있다.
- HTTP 요청 수
- 오류율
- 응답 시간
- CPU 사용량
- Queue의 대기 작업 수
OpenTelemetry는 애플리케이션의 Metric과 Trace, Log를 수집하고 전달하는 데 사용할 수 있는 관측성 기술이다.
예를 들어 Node.js API 서버에서 다음 정보를 수집한다고 가정해 보자.
http_server_request_duration
이 Metric은 실제 HTTP 요청의 지연 시간을 분석하는 데 사용할 수 있다.
CloudWatch에서는 이러한 Metric을 기준으로 Alarm을 생성할 수 있다.
하지만 기존에는 PromQL Alarm에서 직접 사용할 수 있는 Auto Scaling Action의 범위에 제한이 있었다.
이번 업데이트는 이를 확장한다.
실제 Auto Scaling 예제
예를 들어 하나의 Node.js API 서버가 EC2 Auto Scaling Group에서 실행된다고 가정해 보자.
일반적으로 인스턴스 수를 조절하기 위해 CPU 사용량을 사용할 수 있다.
하지만 실제 서비스의 병목이 CPU가 아닐 수도 있다.
예를 들어 다음 상황이다.
- 외부 API 응답 대기
- 데이터베이스 Connection 부족
- Queue 대기 작업 증가
- 특정 Endpoint의 요청량 급증
이러한 경우 애플리케이션에서 수집한 Metric을 직접 활용하는 편이 적합할 수 있다.
예를 들어 Queue에 대기 중인 작업이 1,000개를 초과하면 인스턴스를 늘리도록 구성할 수 있다.
CloudWatch는 PromQL로 계산한 결과를 Alarm에 연결한다.
이후 Alarm의 상태에 따라 Auto Scaling Action을 실행한다.
Simple Scaling과 Step Scaling
이번 기능에서 지원하는 정책은 다음 두 가지다.
첫 번째는 Simple Scaling이다.
예를 들어 Alarm이 발생하면 인스턴스를 두 개 추가하도록 설정할 수 있다.
두 번째는 Step Scaling이다.
이 경우 실제 Metric이 Threshold를 얼마나 초과했는지에 따라 확장량을 다르게 설정할 수 있다.
예를 들어 다음 정책을 생각할 수 있다.
| 대기 작업 수 | 확장 정책 예시 |
|---|---|
| 1,000개 초과 | 인스턴스 1개 추가 |
| 3,000개 초과 | 인스턴스 3개 추가 |
| 5,000개 초과 | 인스턴스 5개 추가 |
이러한 정책은 실제 서비스의 처리량에 맞춰 설정해야 한다.
단순히 대기 작업 수가 많다는 이유로 인스턴스를 무한히 늘리는 것은 적절하지 않을 수 있다.
예를 들어 실제 병목이 데이터베이스에 존재한다면 애플리케이션 서버를 더 많이 생성해도 처리량이 증가하지 않을 수 있다.
PromQL 결과의 제한사항
이번 기능에서는 PromQL Query가 하나의 Time Series를 반환해야 한다.
즉 여러 서버나 Endpoint의 Metric을 조회하더라도 실제 Alarm은 하나의 결과값을 기준으로 판단할 수 있어야 한다.
예를 들어 Endpoint별 오류율이 각각 반환되는 Query를 생각할 수 있다.
이 경우 여러 Series가 생성된다.
그 상태로는 이번 기능의 조건을 충족하지 못할 수 있다.
따라서 필요한 Aggregate를 적용해 하나의 값으로 계산해야 한다.
또한 실제 결과를 Threshold와 비교해야 한다.
Target Tracking은 지원하지 않음
이번 발표의 중요한 제한사항은 다음과 같다.
Target Tracking Scaling Policy는 아직 지원하지 않는다.
Target Tracking은 실제 Metric이 특정 목표값을 유지하도록 인스턴스 수를 조절하는 방식이다.
예를 들어 평균 CPU 사용량을 50%로 유지하도록 구성할 수 있다.
하지만 이번 PromQL Alarm의 새로운 Auto Scaling 지원은 Simple 및 Step Scaling에 한정된다.
따라서 기존 Target Tracking 정책을 그대로 PromQL로 대체할 수 있다고 판단해서는 안 된다.
설정 방법과 비용
새로운 Alarm은 다음 인터페이스에서 구성할 수 있다.
- CloudWatch Console
PutMetricAlarmAPI- AWS CLI
- AWS SDK
- CloudFormation
지원 범위는 CloudWatch PromQL Alarm을 제공하는 모든 AWS 리전이다.
기존 CloudWatch Alarm 요금이 적용된다.
이번 발표에는 Scaling 정책을 변경한 이후 실제 서비스의 응답 시간이 얼마나 개선되는지에 관한 Benchmark가 포함되지 않았다.
PromQL과 OpenTelemetry로 수집한 애플리케이션 Metric을 인프라의 확장 정책에 직접 연결할 수 있도록 한 운영 기능이다.
Amazon Bedrock AgentCore, 독립 Web Search API 정식 출시 — MCP Gateway 없이 단일 API 호출로 웹 검색
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: AWS
- 안정화 단계: Generally Available
- 적용 대상: Amazon Bedrock AgentCore, AI 에이전트 및 백엔드 애플리케이션
- API:
InvokeWebSearch - 요금: 검색 1,000회당 7달러
- 원문: https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-bedrock-agentcore-web-search-api/
AWS가 Amazon Bedrock AgentCore에서 웹 검색을 독립적인 API로 호출할 수 있도록 기능을 정식 출시했다.
기존에도 AgentCore에서는 MCP Tool을 통해 웹 검색 기능을 사용할 수 있었다.
이번 변경은 검색 기능을 처음 도입한 것이 아니다.
MCP Gateway를 별도로 구성하지 않아도 애플리케이션에서 직접 웹 검색 결과를 가져올 수 있도록 호출 방식을 확장한 것이다.
AI 에이전트에서 웹 검색이 필요한 상황
예를 들어 AI 기반 기술지원 서비스를 운영한다고 가정해 보자.
사용자는 다음과 같이 질문할 수 있다.
최근 공개된 React 보안 업데이트가 뭐야?
모델이 이미 학습한 데이터만으로 답변한다면 실제 최신 정보를 놓칠 수 있다.
따라서 외부 웹 검색이 필요할 수 있다.
애플리케이션은 다음 작업을 수행한다.
- 사용자의 질문 확인
- 웹 검색 API 호출
- 관련 문서와 검색 결과 수집
- 실제 원문 검증
- 사용자에게 답변 생성
기존 AgentCore에서는 이러한 기능을 MCP Gateway를 통해 호출할 수 있었다.
이번 업데이트에서는 InvokeWebSearch API를 직접 사용할 수 있다.
검색 결과의 구조
Web Search API는 Amazon이 운영하는 웹 검색 Index를 사용한다.
검색 결과에는 다음 정보가 포함될 수 있다.
- 검색 결과의 순위
- 페이지의 일부 텍스트
- 제목
- URL
- 게시 시각
다만 모든 검색 결과에 모든 Metadata가 존재한다는 의미는 아니다.
AWS는 제목과 URL, 게시 시각을 사용할 수 있는 경우에 제공한다고 설명한다.
따라서 실제 애플리케이션에서는 일부 필드가 누락된 결과도 처리해야 한다.
Domain과 게시 기간 필터
이번 API에서는 요청별로 검색 범위를 제한할 수 있다.
대표적인 조건은 다음과 같다.
- Domain
- 게시 기간
예를 들어 공식 기술 문서만 검색하려고 한다고 가정해 보자.
검색 대상 Domain을 특정 사이트로 제한할 수 있다.
또한 최근 24시간에 공개된 자료만 검색하도록 기간을 설정할 수 있다.
하지만 검색 API가 반환한 게시 시각이 존재한다는 사실만으로 실제 원문의 정확한 최초 게시 시각이 검증됐다고 판단해서는 안 된다.
실제 최신성 검증이 중요한 서비스에서는 검색 결과에서 제공한 URL을 열고 원문을 확인하는 과정이 필요할 수 있다.
특히 오래된 문서가 수정되면서 검색 Index의 날짜가 갱신되는 상황을 구분해야 한다.
IAM과 VPC PrivateLink
새로운 API는 AWS SDK와 CLI로 호출할 수 있다.
접근 권한은 IAM으로 관리한다.
따라서 애플리케이션별로 웹 검색 API를 호출할 수 있는 권한을 제한할 수 있다.
또한 AWS PrivateLink를 지원한다.
따라서 필요한 경우 VPC 안에서 PrivateLink를 통해 API에 접근하도록 구성할 수 있다.
CloudTrail Data Event로 호출 기록을 남길 수도 있다.
하지만 검색 API에 대한 IAM 권한을 부여했다는 사실만으로 검색 결과에 포함된 외부 콘텐츠가 안전해지는 것은 아니다.
AI 에이전트가 외부 웹페이지의 내용을 처리하는 경우에는 Prompt Injection과 신뢰할 수 없는 데이터의 처리 문제를 별도로 고려해야 한다.
비용과 지원 리전
공식 요금은 다음과 같다.
검색 1,000회당 7달러
이는 기존 AgentCore Gateway의 Web Search와 같은 요금이다.
새로운 API를 직접 호출하는 경우에는 별도의 Gateway 요금이 발생하지 않는다.
하지만 AI 모델에 검색 결과를 입력한다면 실제 모델의 Token 사용 비용은 별도로 발생할 수 있다.
지원 리전은 다음과 같다.
- US East (N. Virginia)
- US East (Ohio)
- US West (Oregon)
- Asia Pacific (Sydney)
- Asia Pacific (Tokyo)
- Europe (Ireland)
따라서 모든 AWS 리전에서 사용할 수 있는 것은 아니다.
이번 발표에는 다른 검색 API와 비교한 검색 품질이나 지연 시간에 관한 독립적인 Benchmark가 포함되지 않았다.
AI 에이전트가 최신 외부 정보를 가져오는 검색 기능을 MCP Gateway와 별개로 호출할 수 있도록 API 접근 방식을 확장한 정식 기능이다.
Cloudflare Flagship, 공식 Rust SDK 공개 — OpenFeature와 로컬 Feature Flag 평가 지원
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: Cloudflare
- 안정화 단계: 공식 SDK 공개
- 적용 대상: Rust 기반 서버 애플리케이션, Cloudflare Flagship
- 필요 환경: Rust 1.88 이상, Tokio Runtime
- 원문: https://developers.cloudflare.com/changelog/post/2026-11-10-rust-sdk/
Cloudflare가 Flagship Feature Flag를 Rust 서버 애플리케이션에서 평가할 수 있는 공식 SDK를 공개했다.
이번 기능은 기존 Feature Flag 서비스를 새로운 제품으로 교체하는 업데이트가 아니다.
Flagship을 실제 Rust 백엔드에서 사용할 수 있도록 공식 언어 지원 범위를 확장한 것이다.
Feature Flag와 Rust 서버
Feature Flag는 특정 기능의 활성화 여부를 코드 배포와 분리해 관리하는 데 사용한다.
예를 들어 Rust로 작성한 API 서버가 있다고 가정해 보자.
개발자는 새로운 추천 알고리즘을 배포했다.
하지만 모든 사용자에게 즉시 적용하지 않고 일부 사용자에게만 제공하고 싶을 수 있다.
이 경우 다음 Flag를 사용할 수 있다.
new-recommendation
특정 사용자에게는 true를 반환한다.
다른 사용자에게는 false를 반환한다.
서버는 반환된 값에 따라 기존 추천 알고리즘 또는 새로운 알고리즘을 실행할 수 있다.
OpenFeature 지원
이번 Rust SDK는 OpenFeature를 사용한다.
OpenFeature는 Feature Flag를 평가하기 위한 공통 인터페이스를 제공하는 프로젝트다.
애플리케이션은 특정 Flag 제공업체의 API를 직접 호출하는 대신 공통 인터페이스를 사용할 수 있다.
Cloudflare는 다음 Provider를 제공한다.
FlagshipServerProvider
이 Provider를 OpenFeature에 등록할 수 있다.
이후 실제 Flag를 평가할 수 있다.
예를 들어 다음 함수를 사용할 수 있다.
get_bool_value()
이 함수는 Boolean 형태의 Feature Flag를 평가한다.
사용자별 Targeting
실제 Feature Flag는 단순히 전체 사용자에게 같은 값을 반환하지 않을 수 있다.
예를 들어 사용자 ID에 따라 다른 결과를 반환할 수 있다.
이번 SDK에서는 Evaluation Context를 사용할 수 있다.
대표적으로 다음 값을 지정할 수 있다.
with_targeting_key("user-42")
Targeting Key는 실제 Flag를 평가할 사용자를 구분하는 데 사용할 수 있다.
예를 들어 전체 사용자의 10%에게 새로운 기능을 제공한다고 가정해 보자.
동일한 사용자에게 반복해서 일관된 결과를 제공하기 위해 Targeting Key를 사용할 수 있다.
하지만 어떤 정보를 Targeting Key로 사용할지는 실제 서비스의 개인정보 처리 정책과 연결될 수 있다.
따라서 불필요한 민감 정보를 전달하지 않도록 해야 한다.
HTTP 기반 평가와 로컬 평가
새로운 SDK는 기본적으로 HTTP를 통해 Feature Flag를 평가한다.
이 방식에서는 서버가 Flagship 서비스에 요청을 보낼 수 있다.
하지만 모든 요청에서 원격 Flag 평가가 발생하면 네트워크 비용이 추가될 수 있다.
예를 들어 초당 수천 개의 API 요청을 처리하는 서버를 생각할 수 있다.
각 API 요청마다 Feature Flag를 평가하기 위해 별도의 HTTP 요청을 실행한다면 추가적인 지연과 네트워크 사용량이 발생할 수 있다.
이번 SDK에서는 로컬 평가도 지원한다.
로컬 평가에서는 Flag 정의를 다운로드한다.
이후 실제 평가를 애플리케이션 프로세스 안에서 수행한다.
따라서 매번 원격 네트워크 요청을 실행할 필요가 없다.
하지만 로컬 평가에서는 다운로드한 Flag 정의가 언제 갱신되는지 고려해야 한다.
원격 설정이 변경됐더라도 로컬에 저장된 정의가 즉시 변경되지 않을 수 있기 때문이다.
Cache와 Telemetry
새로운 SDK는 다음 기능도 제공한다.
- 구조화된 Evaluation Context
- 선택적인 Response Cache
- Logging Hook
- Telemetry Hook
이러한 기능은 실제 Flag 평가 결과와 실행 상태를 관찰하는 데 활용할 수 있다.
하지만 공식 발표에는 HTTP 평가와 로컬 평가 사이의 실제 지연 시간을 비교한 Benchmark가 포함되지 않았다.
따라서 모든 Rust 서비스에서 특정한 성능 개선이 발생한다고 단정할 수 없다.
이번 업데이트는 Rust 서버에서도 공통 OpenFeature 인터페이스를 사용해 Flagship의 Targeting과 Percentage Rollout을 적용할 수 있도록 한 공식 SDK 확장이다.
이번 조사 범위에서 이외에 포함할 만한 주요 신규 백엔드·인프라 발표는 확인하지 못했습니다.
Cloudflare Stream에서는 MP4 다운로드용 파일 생성 시간이 최대 40% 단축됐다는 별도의 최적화도 공개됐다.
이 수치는 Cloudflare의 자체 발표 기준이다. 특히 1분 이상인 On-demand Video에서 영향이 크다고 설명한다. 이는 MP4 파일을 생성하는 작업의 최적화이며, 최종 사용자의 파일 다운로드 속도 자체가 40% 빨라졌다는 의미는 아니다.
이번 조사에서는 보다 광범위한 백엔드 구조와 운영 정책에 영향을 주는 발표를 우선해 상세 항목을 선정했다.
4️⃣ 개발 도구 및 보안
GitHub Dependabot, 2026년 12월 8일부터 1년 이상 비활성 Repository의 보안 Alert 자동 일시 중단
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 기본 정책 적용 예정일: 2026-12-08
- 발표 주체: GitHub
- 안정화 단계: 정식 정책 변경 예고
- 적용 대상: github.com의 모든 요금제, GitHub Enterprise Cloud Data Residency
- 제외 대상: GitHub Enterprise Server
- 원문: https://github.blog/changelog/2026-11-10-dependabot-alerts-will-pause-on-inactive-repositories/
GitHub가 1년 이상 활동이 없는 Repository에서 Dependabot Alert를 자동으로 중단하는 정책을 발표했다.
이번 변경은 JavaScript 패키지의 보안 취약점 탐지 정확도를 개선하는 업데이트가 아니다.
실제로 어떤 Repository를 계속 보안 모니터링 대상으로 유지할지 결정하는 정책의 변경이다.
특히 오래된 프로젝트와 장기간 유지보수하지 않는 Repository를 가진 개발자에게 영향을 줄 수 있다.
Dependabot Alert의 역할
Dependabot은 Repository의 의존성 정보를 분석한다.
예를 들어 다음 파일을 생각할 수 있다.
package.jsonpackage-lock.jsonpnpm-lock.yamlyarn.lock
이러한 파일에는 프로젝트에서 사용하는 패키지와 버전 정보가 포함될 수 있다.
GitHub는 알려진 취약점이 존재하는 의존성을 발견하면 Dependabot Alert를 생성할 수 있다.
예를 들어 오래된 HTTP Client 라이브러리에 취약점이 발견됐다고 가정해 보자.
해당 라이브러리를 사용하는 Repository에 Alert가 생성될 수 있다.
하지만 실제 Repository가 몇 년 동안 변경되지 않았더라도 계속 같은 방식으로 Alert를 생성한다면 매우 많은 비활성 Repository를 모니터링해야 한다.
GitHub는 이러한 사용량을 관리하기 위해 새로운 정책을 도입한다.
비활성 Repository의 기준
새로운 정책은 다음 날짜부터 적용된다.
2026-12-08
GitHub는 지난 1년 동안 활동이 없었던 대부분의 Repository에서 Dependabot Alert를 비활성화한다.
GitHub가 활동으로 인정하는 이벤트는 다음과 같다.
- Branch 또는 Tag에 Push
- Repository 생성
- Dependabot Alert 활성화
중요한 점은 모든 GitHub 활동이 같은 방식으로 인정되는 것은 아니라는 사실이다.
예를 들어 단순히 Repository 페이지를 조회하거나 다른 개발자가 Issue를 읽었다는 사실은 이번 발표에서 활동 기준으로 제시되지 않았다.
따라서 실제 Repository의 유지보수 여부를 판단할 때 GitHub가 정의한 활동 조건을 기준으로 해야 한다.
기존 Alert는 삭제되지 않음
이번 정책에서 중요한 부분은 다음과 같다.
기존 Dependabot Alert는 삭제되지 않고 보관된다.
예를 들어 Repository에 20개의 기존 Alert가 존재한다고 가정해 보자.
해당 Repository가 비활성 상태로 분류돼 Dependabot Alert가 중단된다.
이 경우 기존 Alert의 기록이 완전히 사라지는 것은 아니다.
GitHub는 해당 정보를 보관한다.
이후 Dependabot Alert를 다시 활성화하면 이전 Alert를 복원할 수 있다.
따라서 새로운 정책은 과거의 보안 정보를 영구적으로 삭제하는 기능이 아니다.
Push하면 자동 재활성화
비활성 Repository에 새로운 Commit을 Push하면 Dependabot Alert가 다시 활성화된다.
예를 들어 오래된 프로젝트를 다시 유지보수하기 시작했다고 가정해 보자.
개발자는 새로운 코드를 Push한다.
GitHub는 해당 Repository를 다시 활동 중인 Repository로 판단한다.
이후 기존 Dependabot Alert를 복원하고 새로운 취약점 정보를 확인할 수 있도록 한다.
또한 Repository Settings에서 직접 활성화할 수도 있다.
다시 활성화한 시점부터 1년의 활동 기간이 새롭게 시작된다.
보안 정책이 강제된 Repository의 예외
이번 변경에는 중요한 예외가 존재한다.
첫 번째는 Enforced Security Configuration이다.
조직 또는 Enterprise의 보안 설정이 해당 Repository에서 Dependabot Alert를 강제로 활성화하도록 구성돼 있다면 자동으로 중단하지 않는다.
두 번째는 Enterprise 정책이다.
Repository 관리자가 Dependabot Alert의 활성화 여부를 직접 변경하지 못하도록 하는 정책이 존재할 수 있다.
이러한 경우에도 이번 자동 중단 대상에서 제외된다.
따라서 모든 비활성 Repository의 Dependabot Alert가 12월 8일에 무조건 중단되는 것은 아니다.
실제 조직의 보안 정책에 따라 달라진다.
기존 배포 서비스와의 관계
오래된 Repository라고 해서 실제로 사용하지 않는 코드라는 의미는 아니다.
예를 들어 다음 상황을 생각할 수 있다.
- 오래전에 개발한 웹 애플리케이션
- 현재도 정상 운영 중
- 최근 1년 동안 새로운 Commit 없음
- 의존성은 이전 버전 그대로 유지
이러한 Repository는 GitHub의 활동 기준에서는 비활성 상태일 수 있다.
하지만 실제 운영 환경에서는 중요한 서비스일 수 있다.
따라서 실제 배포된 코드의 보안 모니터링과 GitHub의 Repository 활동 여부를 구분해야 한다.
이번 정책에서는 비활성 Repository의 Dependabot Alert가 중단될 수 있으므로 실제 운영 서비스의 취약점 관리 방식에 영향을 줄 수 있다.
적용 범위
이번 정책은 다음 환경에 적용된다.
- github.com의 모든 요금제
- GitHub Enterprise Cloud
- Data Residency 환경
GitHub Enterprise Server에는 적용되지 않는다.
Data Residency 환경에서 보관된 Alert는 해당 Enterprise 데이터와 같은 리전에 저장된다.
이번 발표는 의존성 분석 속도의 성능 개선이나 새로운 취약점 탐지 기술을 발표한 것이 아니다.
Repository의 최근 활동을 기준으로 Dependabot Alert의 기본 활성화 여부를 변경하면서 기존 Alert의 기록과 재활성화 경로를 유지하는 정책 업데이트다.
Gemini 4 Carbon, GitHub Copilot·Vercel AI Gateway에 정식 제공 — 코딩 에이전트와 웹 애플리케이션에서 모델 선택 가능
- 발표일: 2026-11-10 — 정확한 게시 시각 미확인
- 발표 주체: GitHub, Vercel
- 모델 제공업체: Google
- GitHub Copilot 안정화 단계: Generally Available, 순차 배포
- Vercel AI Gateway 상태: 정식 모델 제공
- 모델 Context Window: 100만 Token
- GitHub 원문: https://github.blog/changelog/2026-11-10-gemini-4-carbon-in-github-copilot/
- Vercel 원문: https://vercel.com/changelog/gemini-4-carbon-now-available-on-ai-gateway
GitHub와 Vercel이 Gemini 4 Carbon을 각각 코딩 도구와 AI Gateway에서 사용할 수 있도록 지원한다고 발표했다.
두 발표는 같은 모델에 관한 것이므로 하나의 소식으로 묶었다.
다만 실제 제공 방식은 다르다.
GitHub Copilot에서는 개발자가 사용하는 AI 코딩 도구의 모델을 선택할 수 있다.
반면 Vercel AI Gateway에서는 웹 애플리케이션의 백엔드나 AI SDK에서 해당 모델을 API로 호출할 수 있다.
GitHub Copilot에서의 제공 범위
GitHub는 Gemini 4 Carbon을 Generally Available 상태로 제공한다고 발표했다.
지원 대상은 다음 요금제다.
- Copilot Pro+
- Copilot Max
- Copilot Business
- Copilot Enterprise
사용할 수 있는 환경은 다음과 같다.
- Visual Studio Code
- Visual Studio
- Copilot CLI
- GitHub Copilot Coding Agent
- GitHub Copilot App
- github.com
- GitHub Mobile
- JetBrains IDE
- Xcode
- Eclipse
다만 실제 배포는 순차적으로 진행된다.
따라서 해당 요금제를 사용한다고 해서 모든 계정에서 발표 즉시 모델이 나타난다는 의미는 아니다.
기업의 모델 접근 정책
Business와 Enterprise 관리자는 Copilot Settings에서 모델 사용 정책을 관리할 수 있다.
예를 들어 특정 기업이 새롭게 출시된 모델을 내부 보안 검토 이후에만 사용하도록 제한한다고 가정해 보자.
관리자는 해당 모델을 비활성화할 수 있다.
반면 새로운 모델을 자동으로 허용하는 정책을 사용한다면 모델이 기본 활성화될 수 있다.
따라서 실제 개발자가 모델을 선택할 수 있는지는 계정의 요금제뿐 아니라 조직의 정책에도 영향을 받는다.
Vercel AI Gateway에서 사용
Vercel AI Gateway에서는 다음 모델 식별자를 사용한다.
google/gemini-4-carbon
예를 들어 AI SDK의 streamText()에 해당 모델을 전달할 수 있다.
이렇게 하면 웹 애플리케이션에서 Gemini 4 Carbon의 스트리밍 응답을 사용할 수 있다.
또한 Gateway의 기존 기능과 연결할 수 있다.
대표적으로 다음과 같다.
- 요청 추적
- 사용량 확인
- 비용 확인
- 모델 Routing
- 재시도 및 장애 대응 정책
하지만 이러한 Gateway 기능이 Gemini 4 Carbon의 제공과 동시에 처음 출시된 것은 아니다.
이번 변경은 기존 Gateway에서 사용할 수 있는 모델의 범위를 확대한 것이다.
모델의 주요 특성
공식 발표에서는 Gemini 4 Carbon을 다음 작업에 적합한 모델로 소개한다.
- 복잡한 소프트웨어 엔지니어링
- 장시간 실행되는 AI 에이전트
- 전체 웹 애플리케이션 개발
- 보안 취약점 분석
- 보안 수정 코드 생성
- 다단계 작업 계획
또한 100만 Token의 Context Window를 지원한다고 발표했다.
하지만 큰 Context Window와 실제 작업 정확성은 별개의 문제다.
예를 들어 매우 큰 Repository의 전체 코드를 입력할 수 있다고 가정해 보자.
모델이 모든 파일의 관계를 완벽하게 이해하거나 실제 변경 영향을 정확하게 분석한다는 보장은 없다.
실제 작업에서는 필요한 코드를 검색하고 관련 파일을 선별하는 과정도 중요하다.
성능 수치의 해석
Google과 Vercel은 Gemini 4 Carbon의 소프트웨어 개발 및 보안 관련 성능 개선을 설명한다.
하지만 이번 GitHub와 Vercel의 제공 발표만으로 다른 모델과의 동일 조건 독립 Benchmark를 확정할 수는 없다.
따라서 모든 코딩 작업에서 특정 모델보다 빠르거나 정확하다고 단정해서는 안 된다.
또한 코딩 에이전트가 생성한 코드는 실제 테스트와 보안 검증이 필요하다.
특히 자동으로 외부 명령을 실행하거나 Repository를 수정하는 에이전트에서는 모델의 성능과 실행 권한을 구분해야 한다.
가격과 제한사항
GitHub Copilot에서는 사용량 기반 과금이 적용된다.
GitHub는 모델 제공업체의 목록 가격을 기준으로 과금한다고 설명한다.
Vercel AI Gateway에서는 2026년 11월 30일까지 해당 모델을 50% 할인된 가격으로 제공한다고 발표했다.
두 서비스의 과금 정책은 서로 다르다.
따라서 Vercel의 할인 기간을 GitHub Copilot에도 동일하게 적용된다고 해석해서는 안 된다.
또한 모델의 실제 사용 가능 여부는 계정과 조직 정책, 순차 배포 상태에 따라 달라질 수 있다.
이번 발표는 복잡한 코딩 및 에이전트 작업을 위한 신규 모델을 기존 개발 도구와 웹 애플리케이션 API에 연결하도록 제공 범위를 확대한 업데이트다.
이번 조사 범위에서 이외에 포함할 만한 주요 신규 개발 도구 및 보안 발표는 확인하지 못했습니다.
Node.js, Deno, Bun, Vite, webpack, Rollup, esbuild, Babel, Biome, ESLint, Prettier, npm, pnpm, Yarn 및 GitLab의 공식 릴리스와 변경 기록을 검토했다.
또한 OWASP와 주요 공급망 보안 권고를 확인했다.
개발 브랜치의 Commit이나 개별 Issue만 존재하는 항목을 정식 보안 수정으로 취급하지 않았다.
Firefox 160의 보안 취약점 수정은 이번 브리핑의 웹 플랫폼·브라우저 섹션에서 공식 보안 권고와 함께 다뤘으므로 반복하지 않았다.
📚 추천 글
I set the Chinese line 3px smaller than the English. It still rendered larger.
- 저자: Melisa Wong
- 매체: DEV Community
- 게시일: 2026-11-09
- 기술: CSS, Typography, Canvas API, Font Metrics, 다국어 UI
- 원문: https://dev.to/melisawrites/i-set-the-chinese-line-3px-smaller-than-the-english-it-still-rendered-larger-34al
영어와 중국어를 함께 표시하는 애플리케이션에서 중국어의 Font Size를 영어보다 작게 설정했는데도 실제 화면에서는 중국어가 더 크게 보이는 문제를 분석한 글이다.
저자는 실제 앱에 존재하는 영어·중국어 텍스트 조합 62개를 조사했다.
그리고 CSS의 font-size만 확인하지 않고 실제 Glyph의 높이를 측정했다.
특히 같은 14px Font Size라도 영문 대문자와 소문자, 한자의 실제 시각적 높이는 서로 다르다는 점을 구체적인 측정 결과로 보여준다.
실제 문제
애플리케이션에서는 영어 텍스트 아래에 중국어 번역을 표시하고 있었다.
디자인에서는 중국어를 보조적인 정보로 취급했다.
따라서 중국어의 Font Size를 영어보다 조금 작게 지정했다.
예를 들어 다음과 같은 구조다.
- 영어: 14px
- 중국어: 11px
CSS 수치만 보면 중국어가 약 21% 작다.
하지만 실제 화면에서는 중국어가 예상보다 크게 보였다.
저자는 이를 해결하기 위해 단순히 Font Size를 더 줄이려고 했다.
하지만 11px에서 10px으로 변경해도 시각적 차이가 충분히 나타나지 않았다.
실제로는 Font Size와 Glyph의 시각적인 높이가 같은 비율로 변하지 않았기 때문이다.
Canvas로 실제 Glyph 높이 측정
저자는 Canvas API를 이용해 실제 텍스트의 크기를 측정했다.
대표적인 API는 다음과 같다.
measureText()
이 API는 텍스트의 너비와 실제 Bounding Box에 관한 정보를 제공할 수 있다.
저자는 다음 문자를 측정했다.
- 영문 대문자
H - 영문 소문자
x - 한자
你
측정에 사용한 Font Size는 14px이다.
결과는 다음과 같았다.
| 측정 대상 | 실제 높이 | Font Size 대비 비율 |
|---|---|---|
| 영문 대문자 H | 9.864px | 0.705 |
| 영문 소문자 x | 7.369px | 0.526 |
| 한자 你 | 11.508px | 0.822 |
같은 14px을 사용하더라도 한자의 실제 높이는 영문 대문자보다 약 16.7% 컸다.
영문 소문자의 X-height와 비교하면 약 56% 컸다.
물론 실제 문장은 여러 문자의 조합으로 이루어진다.
따라서 문자 하나의 높이만으로 모든 텍스트의 시각적인 크기를 완전히 설명할 수는 없다.
하지만 Font Size와 실제 시각적 높이의 차이를 이해하는 데는 유용한 측정이다.
62개 텍스트 조합의 실제 결과
저자는 실제 앱에서 62개 조합을 조사했다.
결과는 다음과 같았다.
| 항목 | 결과 |
|---|---|
| 조사한 텍스트 조합 | 62개 |
| 서로 다른 Font Size 비율 | 24개 |
| 중국어/영어 Font Size 비율의 중앙값 | 0.923 |
| 실제 시각적 높이 비율의 중앙값 | 1.077 |
| 중국어가 영어와 같거나 더 크게 보인 조합 | 40개 |
| 두 언어에 같은 Font Size를 사용한 조합 | 23개 |
중국어의 Font Size는 중앙값 기준으로 영어보다 작았다.
하지만 실제 시각적인 높이는 오히려 중국어가 더 컸다.
이러한 차이는 실제 Glyph의 크기 때문이다.
저자는 다음 관계를 사용했다.
optical ratio = size ratio × 1.167
이 식에서 1.167은 실제 테스트한 Font Stack에서 한자와 영문 대문자의 시각적 높이를 비교한 값이다.
하지만 모든 Font에서 이 값이 동일하게 적용되는 것은 아니다.
실제 사용하는 Font Family와 Font Weight에 따라 달라질 수 있다.
Font Metrics 검사가 문제를 발견하지 못한 이유
저자는 이미 Font 크기를 검사하는 코드를 사용하고 있었다.
대표적으로 다음 값을 읽었다.
fontBoundingBoxAscentfontBoundingBoxDescent
하지만 검사 결과는 정상으로 나타났다.
이유는 이러한 값이 실제로 해당 문자를 그린 Fallback Font의 크기와 반드시 일치하지 않기 때문이다.
예를 들어 CSS에 영문 Font를 먼저 지정했다고 가정해 보자.
하지만 해당 Font에는 실제 한자 Glyph가 존재하지 않을 수 있다.
브라우저는 다른 Font를 찾아 한자를 렌더링한다.
이때 Font Stack의 기본 Metrics와 실제 Glyph의 Metrics가 다를 수 있다.
저자는 실제로 두 Font Stack에서 같은 한자를 측정했다.
실제 Ink의 크기는 같았다.
하지만 Font Bounding Box Metrics는 서로 다르게 나타났다.
따라서 현재 CSS에 지정한 기본 Font의 Metrics만 확인하면 실제 Fallback Font가 렌더링한 글자의 크기를 잘못 판단할 수 있다는 것이다.
Chrome의 -apple-system 처리
저자는 또 다른 문제를 발견했다.
CSS에서 다음 Font Stack을 사용하고 있었다.
-apple-system, BlinkMacSystemFont, ...
그리고 중국어에는 다음과 같은 Stack을 사용했다.
-apple-system, "PingFang SC", ...
저자는 -apple-system이 먼저 적용될 것으로 예상했다.
하지만 Chrome 156에서 실제로 측정한 결과는 달랐다.
일부 경우에는 -apple-system이 기대한 방식으로 사용되지 않았다.
브라우저가 이후의 다른 Font를 선택했다.
그 결과 영어와 중국어는 서로 다른 실제 Font를 사용하고 있었다.
저자는 WebKit에서는 다른 동작이 가능하다고 설명한다.
하지만 WebKit에서 동일한 비교 실험을 수행한 결과는 제공하지 않았다.
따라서 Chrome에서 확인한 결과를 모든 브라우저의 동작으로 일반화해서는 안 된다.
line-height: normal의 문제
두 언어에서 사용하는 Font가 달라지면 Line Box의 높이도 달라질 수 있다.
저자가 측정한 값은 다음과 같았다.
| Font | line-height: normal에 해당하는 비율 |
|---|---|
| 영문 Font | 약 1.18em |
| PingFang SC | 약 1.40em |
같은 14px Font Size에서 실제 Line Box는 다음처럼 나타났다.
- 영어: 약 17px
- 중국어: 약 20px
즉 Font Size가 같더라도 줄의 높이는 약 3px 차이가 발생했다.
이러한 차이는 두 줄의 텍스트 사이의 간격에 영향을 준다.
저자는 이를 줄이기 위해 명시적인 Unitless Line Height를 사용하도록 변경했다.
예를 들어 다음과 같다.
line-height: 1.5
이렇게 하면 Font Size에 같은 비율을 적용할 수 있다.
다만 실제 Glyph 자체의 높이가 같아지는 것은 아니다.
Line Box의 계산 방식을 더 일관되게 만드는 것이다.
시각적 계층을 Font Size에만 의존하지 않음
저자는 영어 14px에 대해 중국어를 실제로 20% 작게 보이게 하려면 중국어를 약 9.6px로 줄여야 한다고 계산했다.
하지만 이는 실제 모바일 환경에서 읽기 어려운 크기가 될 수 있다.
따라서 모든 시각적 계층을 Font Size 차이만으로 표현하는 것은 적절하지 않을 수 있다.
저자는 다음 요소를 함께 사용하는 방법을 설명한다.
- 색상
- Font Weight
- 줄 간격
- 실제 콘텐츠 사이의 간격
예를 들어 중국어를 지나치게 작게 만드는 대신 두 줄의 색상과 굵기를 다르게 설정할 수 있다.
실제 측정의 한계
이번 글은 실제 코드베이스의 62개 조합을 분석했다.
따라서 구체적인 수치가 존재한다.
하지만 해당 결과는 저자가 사용하는 Font Stack과 브라우저에 한정된다.
특히 다음 조건에서 결과가 달라질 수 있다.
- 운영체제
- 실제 설치된 Font
- 브라우저 엔진
- Font Fallback
- Font Weight
- 사용자 설정
이번 글은 다국어 UI에서 CSS의 Font Size가 실제 시각적 크기와 동일한 개념이 아니며, 특히 한자와 영문을 함께 표시할 때 실제 Glyph와 Line Box를 구분해 측정해야 한다는 점을 보여준다.
Upgrading three Tailwind projects to v4 in one sprint
- 저자: Richard Lemon
- 매체: DEV Community / 개인 기술 블로그
- 게시일: 2026-11-10
- 기술: Tailwind CSS 3·4, Design Tokens, Custom Plugin, CSS Migration
- 원문: https://dev.to/richardlemon/upgrading-three-tailwind-projects-to-v4-in-one-sprint-5gfa
Tailwind CSS 3을 사용하는 세 개의 실제 클라이언트 프로젝트를 한 번의 Sprint에서 Tailwind CSS 4로 이전한 과정을 설명한 글이다.
저자는 모든 프로젝트를 같은 방식으로 업그레이드하지 않았다.
대신 실제 프로젝트의 복잡도에 따라 순서를 정했다.
특히 Custom Plugin과 Design Token이 많은 프로젝트를 마지막에 처리했다.
이번 글은 Tailwind CSS 4의 새로운 릴리스를 소개하는 자료가 아니다.
이미 공개된 버전으로 실제 프로젝트를 이전한 경험을 정리한 것이다.
세 프로젝트의 차이
저자가 이전한 프로젝트는 다음과 같다.
| 프로젝트 | 특징 |
|---|---|
| 단순한 마케팅 사이트 | 기본 Utility 중심 |
| 공통 디자인 시스템 | 여러 앱이 공유하는 Token과 설정 |
| Gate Seal 사이트 | 복잡한 Custom Plugin 및 Gradient Border 사용 |
첫 번째 프로젝트에서는 비교적 적은 변경으로 새로운 Tailwind 버전의 기본 동작을 확인할 수 있었다.
두 번째 프로젝트에서는 실제 디자인 시스템의 Token과 Utility를 유지하는 것이 중요했다.
세 번째 프로젝트에서는 Custom Plugin의 호환성 문제가 발생할 가능성이 높았다.
따라서 저자는 세 번째 프로젝트를 마지막에 처리했다.
이러한 순서는 단순히 작업량이 적은 프로젝트부터 처리하기 위한 것이 아니다.
간단한 프로젝트에서 새로운 버전의 동작을 이해한 뒤 복잡한 프로젝트에 적용하기 위한 선택이었다.
마이그레이션 이전의 검사
저자는 설정 파일을 변경하기 전에 세 가지를 확인했다.
첫 번째는 Custom Tailwind 코드의 양이다.
대표적으로 다음 항목을 검사했다.
- Custom Plugin
@apply- Theme 확장
- Design Token
- 기존 JIT 동작에 의존하는 코드
두 번째는 실제 Tailwind Class가 존재하는 위치다.
예를 들어 Class는 React 컴포넌트 파일에만 존재하지 않을 수 있다.
다음 파일에도 포함될 수 있다.
- CMS의 HTML
- Markdown
- JSON
- Template
- Data Attribute
이러한 위치를 놓치면 새로운 빌드 설정에서 필요한 CSS가 생성되지 않을 수 있다.
세 번째는 실제 사용 중인 Utility의 종류다.
예를 들어 간격과 Typography, 색상 관련 Utility를 확인했다.
이렇게 하면 업그레이드 이후 문제가 발생할 가능성이 높은 영역을 먼저 검사할 수 있다.
기본 Utility는 대부분 유지됐다
저자는 기본적인 Tailwind Utility가 예상보다 안정적으로 동작했다고 설명한다.
대표적으로 다음 항목이다.
- Flex
- Grid
- 기본 Spacing
- Typography
- Border Radius
- Shadow
- Background Color
즉 Tailwind CSS 4로 변경했다고 해서 모든 Layout을 처음부터 다시 작성할 필요는 없었다.
실제 문제는 기본 Utility보다 Custom Configuration에 집중됐다.
특히 오래전에 추가한 설정과 현재 사용하지 않는 확장 코드가 유지보수를 어렵게 만들었다.
오래된 설정 제거
저자는 이전 버전에서 사용하던 설정을 정리했다.
대표적으로 다음 항목이다.
- 이전 Purge 설정
- 이전 Content Scan 설정
- 사용하지 않는 Theme Extension
- 중복된 Spacing Token
- 실제로 사용하지 않는 Custom Variant
예를 들어 어떤 프로젝트에 색상 Token이 100개 존재한다고 가정해 보자.
하지만 실제 컴포넌트에서는 20개만 사용하고 있을 수 있다.
이 경우 나머지 Token을 그대로 새로운 버전에 옮기는 것이 반드시 적절한 것은 아니다.
저자는 실제 사용처를 확인한 뒤 필요하지 않은 설정을 제거했다.
이렇게 하면 새로운 Tailwind CSS 4의 동작과 기존 설정 사이의 충돌 가능성을 줄일 수 있다.
Gradient Border Plugin의 실패
가장 복잡했던 문제는 Gate Seal 사이트에서 발생했다.
이 프로젝트에는 Gradient Border를 생성하는 Custom Plugin이 존재했다.
Tailwind CSS 3에서는 해당 Plugin이 정상적으로 동작했다.
Plugin은 다음 요소를 조합해 Gradient Border를 생성했다.
- Background Image
- Padding
- Pseudo-element
- Theme Token
하지만 Tailwind CSS 4에서는 해당 Plugin이 정상적으로 동작하지 않았다.
결과적으로 일부 컴포넌트에서 Gradient Border가 사라졌다.
저자는 처음에 이 문제를 몇 시간 안에 해결할 수 있을 것으로 예상했다.
하지만 실제 작업은 예상보다 오래 걸렸다.
원인은 단순한 CSS 선언 하나가 아니었다.
Plugin이 Tailwind의 기존 내부 동작과 Theme 조회 방식에 의존하고 있었기 때문이다.
Plugin의 설계 선택
저자는 Plugin을 유지해야 하는지 먼저 판단했다.
예를 들어 단순히 몇 개의 정적 Class를 생성하는 Plugin이라면 실제 CSS로 교체할 수 있다.
이러한 경우 Custom Plugin을 유지하는 것보다 일반적인 CSS를 사용하는 편이 단순할 수 있다.
반면 여러 Variant와 Theme Token을 조합하는 Plugin은 다르다.
실제 디자인 시스템과 깊이 연결돼 있을 수 있다.
따라서 단순히 Plugin을 제거하면 여러 컴포넌트에서 같은 스타일을 다시 구현해야 할 수 있다.
저자는 Custom Plugin을 다음 두 종류로 구분했다.
- 간단한 정적 Utility 생성
- 복잡한 Theme 및 Variant 처리
첫 번째는 일반적인 CSS로 교체하는 방법을 검토했다.
두 번째는 실제 사용처와 Tailwind CSS 4의 호환성을 자세히 확인했다.
마이그레이션의 실제 순서
저자가 선택한 진행 방식은 다음과 같다.
- 가장 단순한 사이트 업그레이드
- 오래된 설정과 사용하지 않는 Token 제거
- 실제 Class 사용처 확인
- 공통 디자인 시스템 업그레이드
- Custom Plugin이 많은 프로젝트 업그레이드
- 문제가 발생한 Plugin의 유지 또는 교체 결정
이러한 방식은 세 프로젝트를 동시에 무작정 변경하는 것보다 실제 변경의 위험을 관리하기 위한 것이다.
특히 공통 디자인 시스템을 사용하는 여러 앱에서는 Token 하나의 변경이 여러 페이지에 영향을 줄 수 있다.
따라서 단순한 빌드 성공만으로 실제 마이그레이션이 완료됐다고 판단하기 어렵다.
실제 화면과 컴포넌트의 동작도 확인해야 한다.
수치와 한계
이번 글은 실제 세 프로젝트의 마이그레이션 경험을 제공한다.
하지만 다음 수치를 제공하지는 않는다.
- 전체 빌드 시간의 전후 비교
- CSS Bundle 크기 감소량
- 실제 작업 시간
- Lighthouse 성능 변화
- 전체 프로젝트의 테스트 통과율
따라서 Tailwind CSS 4로 업그레이드하면 모든 프로젝트가 특정 비율만큼 빨라진다고 판단할 수 없다.
또한 모든 Custom Plugin이 Tailwind CSS 4에서 동일한 방식으로 실패하는 것은 아니다.
이번 글은 프론트엔드 도구의 메이저 버전을 업그레이드할 때 기본 기능보다 프로젝트가 자체적으로 추가한 확장 코드와 디자인 시스템의 의존성이 더 큰 비용을 만들 수 있다는 점을 보여주는 실제 경험 자료다.
Stop Using JavaScript to Strip Units. CSS Typed Arithmetic Is Baseline
- 저자: JKC
- 매체: DEV Community
- 게시일: 2026-11-10
- 기술: CSS, Typed Arithmetic, calc(), Container Query Units, Custom Properties
- 원문: https://dev.to/iamprincejkc/stop-using-javascript-to-strip-units-css-typed-arithmetic-is-baseline-154
CSS Typed Arithmetic를 이용해 길이 단위의 값을 일반적인 숫자로 변환하고, 기존에 JavaScript로 계산하던 일부 반응형 값을 CSS만으로 처리하는 방법을 설명한 글이다.
이번 글은 새로운 CSS 기능의 최초 출시를 소개하는 자료가 아니다.
저자에 따르면 Typed Arithmetic는 Firefox 158에서 지원되면서 2026년 10월부터 Baseline Newly Available 상태가 됐다.
11월 10일은 해당 기능을 활용하는 기술 글의 게시일이다.
기존 JavaScript의 역할
예를 들어 화면의 너비에 따라 배경 이미지의 불투명도를 변경한다고 가정해 보자.
화면이 좁을 때는 배경을 연하게 표시한다.
화면이 넓을 때는 배경을 더 진하게 표시한다.
기존에는 JavaScript에서 화면의 너비를 읽을 수 있었다.
대표적으로 다음 API를 사용할 수 있다.
ResizeObserver
이후 실제 너비를 계산한다.
그리고 CSS Custom Property에 숫자를 저장한다.
이러한 방식은 정상적으로 동작할 수 있다.
하지만 실제로 필요한 작업이 단순히 CSS 길이 값에서 단위를 제거하는 것뿐이라면 불필요한 JavaScript가 존재할 수 있다.
Typed Arithmetic는 이러한 상황을 줄이도록 한다.
길이 값을 나누면 숫자가 된다
기존 CSS에서는 다음과 같은 계산이 제한됐다.
200px / 4px
하지만 Typed Arithmetic에서는 같은 종류의 단위를 가진 두 값을 나눌 수 있다.
결과는 단위가 없는 숫자다.
예를 들어 다음과 같다.
calc(100vw / 1px)
이 표현은 현재 Viewport 너비를 숫자로 변환한다.
예를 들어 Viewport 너비가 400px이라면 결과는 400이다.
저자는 이 기능을 이용해 다음 속성의 값을 계산했다.
opacityline-heightfont-weightz-index
이렇게 하면 단순한 숫자 계산을 위해 JavaScript를 실행할 필요가 줄어든다.
실제 브라우저 측정
저자는 Chrome 157에서 직접 테스트했다.
Viewport 너비에 따라 다음 CSS 값을 계산했다.
opacity: calc(100vw / 2000px)
결과는 다음과 같았다.
| Viewport 너비 | 계산된 Opacity |
|---|---|
| 400px | 0.2 |
| 800px | 0.4 |
| 1200px | 0.6 |
이 결과는 실제 브라우저의 Computed Style에서 확인했다.
따라서 단순히 CSS 문법이 정상적으로 파싱되는 것뿐 아니라 계산 결과가 실제 스타일에 반영되는지도 검증한 것이다.
다만 이 결과는 Chrome 157에서 수행한 저자의 실험이다.
모든 브라우저에서 같은 방식으로 측정한 독립적인 비교 Benchmark는 아니다.
Container Query Unit과 결합
저자는 Viewport 너비보다 실제 컴포넌트의 크기를 기준으로 계산하는 방법도 소개한다.
대표적인 단위는 다음과 같다.
cqi
이는 Container Query와 연결된다.
예를 들어 하나의 Card 컴포넌트가 있다고 가정해 보자.
해당 Card는 다음 두 위치에 사용될 수 있다.
- 전체 너비가 넓은 메인 화면
- 좁은 Sidebar
같은 브라우저의 Viewport 안에 존재하더라도 실제 Card의 너비는 다르다.
따라서 vw보다 실제 Container의 크기를 사용하는 편이 적합할 수 있다.
저자는 다음 값들을 계산했다.
- 제목의 Line Height
- Font Weight
- 배경 이미지의 Opacity
그리고 다음 함수를 조합했다.
clamp()
clamp()는 계산 결과가 실제로 허용된 범위를 벗어나지 않도록 제한하는 데 사용할 수 있다.
예를 들어 Font Weight가 지나치게 커지지 않도록 최소값과 최대값을 지정할 수 있다.
실제 Container별 결과
저자는 다음 결과를 측정했다.
| Container 너비 | Line Height | Font Weight | Opacity |
|---|---|---|---|
| 360px | 1.375 | 400 | 0.3 |
| 720px | 1.15 | 480 | 0.6 |
| 1200px | 1.05 | 800 | 0.6 |
이러한 구조에서는 컴포넌트의 실제 너비를 하나의 기준으로 사용할 수 있다.
하지만 모든 스타일을 화면 너비에 비례해 변경해야 하는 것은 아니다.
예를 들어 실제 디자인 시스템에서 Font Weight를 특정 단계로만 사용한다면 연속적으로 값을 변경하는 방식이 적절하지 않을 수 있다.
따라서 실제 UI의 요구사항에 맞게 선택해야 한다.
지원 브라우저
저자가 정리한 지원 범위는 다음과 같다.
| 브라우저 | 지원 시작 버전 |
|---|---|
| Chrome·Edge | 140 |
| Safari | 26 |
| Firefox | 158 |
따라서 지원 범위에 포함되지 않는 오래된 브라우저에서는 Typed Arithmetic가 적용되지 않을 수 있다.
이러한 상황에서는 Fallback이 필요하다.
기존 브라우저를 위한 Fallback
예를 들어 다음 두 선언을 함께 작성할 수 있다.
opacity: 0.4;
opacity: calc(100vw / 2000px);
Typed Arithmetic를 지원하는 브라우저에서는 두 번째 값을 사용할 수 있다.
반면 지원하지 않는 브라우저에서는 두 번째 선언을 무효로 처리하고 첫 번째 값을 유지할 수 있다.
또한 다음 기능으로 지원 여부를 확인할 수 있다.
@supports
이러한 방식은 새로운 CSS 기능을 도입하면서 기존 브라우저에 기본 동작을 제공하는 Progressive Enhancement 패턴에 해당한다.
em의 의미
이번 글에서 중요한 제한사항은 em이다.
예를 들어 다음 계산을 생각할 수 있다.
calc(100vw / 1em)
여기서 em은 실제 요소의 Font Size에 영향을 받는다.
따라서 같은 Viewport 너비라도 요소의 Font Size가 다르면 결과가 달라진다.
예를 들어 360px Viewport에서 다음 결과가 가능하다.
- Font Size 16px: 약 22.5
- Font Size 20px: 18
따라서 em을 단순한 고정된 길이 단위로 취급해서는 안 된다.
두 길이 값의 곱셈은 허용되지 않음
Typed Arithmetic가 모든 종류의 단위 계산을 허용하는 것도 아니다.
예를 들어 다음 표현은 여전히 무효다.
calc(2px * 3px)
두 길이를 곱하면 길이의 제곱에 해당하는 차원이 만들어진다.
하지만 일반적인 CSS의 길이 속성은 해당 차원을 사용하지 않는다.
따라서 동일한 종류의 단위를 나눌 수 있다는 사실과 모든 단위 연산이 가능하다는 사실은 다르다.
Custom Property의 계산 위치
저자는 Custom Property에서도 흥미로운 문제를 발견했다.
예를 들어 다음 값을 저장한다고 가정해 보자.
--w: calc(100cqi / 1px)
이 Custom Property를 중첩된 Container 안에서 사용한다.
문제는 cqi가 어떤 Container를 기준으로 계산되는지다.
등록되지 않은 Custom Property는 실제로 사용되는 위치에서 값이 계산될 수 있다.
따라서 선언한 위치와 사용하는 위치가 다르면 예상하지 못한 결과가 발생할 수 있다.
저자는 다음 CSS 기능을 이용해 이를 비교했다.
@property
Custom Property를 <number>로 등록하면 실제 계산 시점과 값의 전달 방식이 달라질 수 있다.
따라서 Container Unit을 사용하는 Custom Property에서는 어디에서 값을 계산하고 어디에서 사용할 것인지 명확하게 정의해야 한다.
실제 적용 범위와 한계
이번 기능은 모든 ResizeObserver를 제거하기 위한 것이 아니다.
예를 들어 다음 작업은 여전히 JavaScript가 필요할 수 있다.
- 실제 요소 크기를 외부 API에 전달
- Canvas 크기 변경
- JavaScript 기반 Chart의 좌표 계산
- 서버로 화면 크기 전달
- 복잡한 Resize 상태 처리
Typed Arithmetic는 CSS에서 필요한 숫자를 계산하기 위해 JavaScript를 사용하던 일부 경우에 적합하다.
이번 글은 CSS의 계산 기능이 확대되면서 기존에 JavaScript가 담당하던 일부 반응형 스타일 계산을 CSS 자체로 옮길 수 있다는 점과 그 과정에서 발생하는 단위 및 Custom Property의 제약을 설명한다.
My screenshot was 1080x1350. The page was 1722 pixels tall.
- 저자: Jonas Francisco de Lima Filho
- 매체: DEV Community
- 게시일: 2026-11-09
- 기술: HTML, CSS, Headless Chromium, Chrome DevTools Protocol, Screenshot Testing
- 원문: https://dev.to/jonasfilhodev/my-screenshot-was-1080x1350-the-page-was-1722-pixels-tall-57c2
웹페이지를 이미지로 변환하는 자동화 시스템에서 생성된 이미지의 크기는 정확했지만 실제 페이지의 하단 콘텐츠가 잘려 있었던 문제를 분석한 글이다.
저자는 소셜미디어용 이미지를 생성하는 작업을 수행하고 있었다.
목표 이미지의 크기는 다음과 같았다.
1080 × 1350
하지만 실제로 생성한 이미지에는 Footer의 연락처 정보가 포함되지 않았다.
문제는 해당 이미지가 배포되기 전에 세 가지 자동 검사를 모두 통과했다는 사실이다.
실제 페이지의 크기
저자는 문제가 발생한 HTML을 다시 구성했다.
페이지는 다음 요소를 포함했다.
- 하나의 Flex Column
- 좌우 90px Padding
- 아홉 개의 문단
- Footer
- Footer 위의 3px 구분선
디자인의 목표 높이는 1350px이었다.
하지만 실제 콘텐츠는 해당 높이에 들어가지 않았다.
브라우저가 Layout을 계산한 결과 문서의 높이는 다음과 같았다.
1722px
즉 목표 이미지보다 372px 길었다.
저자는 다음 정보를 확인했다.
- Document 높이: 1722px
- Viewport 높이: 1350px
- Footer의 하단 위치: 1652px
Footer는 실제로 1350px보다 아래에 존재했다.
따라서 1350px 높이의 Screenshot에서는 해당 Footer가 포함될 수 없었다.
기존 검사가 성공한 이유
저자의 자동화 시스템에는 이미지 크기를 검사하는 코드가 존재했다.
예를 들어 다음 조건을 확인했다.
width == 1080
height == 1350
실제로 생성된 이미지의 크기는 1080×1350이었다.
따라서 검사를 통과했다.
하지만 이 검사는 중요한 사실을 확인하지 않았다.
이미지의 크기가 올바르다는 사실과 실제 페이지의 모든 콘텐츠가 이미지에 포함됐다는 사실은 다르다.
저자는 기존 검사가 요청한 크기와 결과 이미지의 크기만 비교했다고 설명한다.
즉 같은 기준값에서 나온 두 숫자를 비교하고 있었다.
실제 원본 콘텐츠의 크기는 검사하지 않았다.
Layout 검사의 한계
저자는 실제 DOM의 요소가 서로 겹치거나 화면 밖으로 벗어나는지 확인하는 검사도 사용했다.
하지만 이 검사 역시 통과했다.
이유는 다음과 같다.
실제 HTML 문서의 높이는 1722px이었다.
Footer는 해당 문서 안에 정상적으로 배치돼 있었다.
따라서 문서의 Layout 자체에는 문제가 없었다.
문제는 실제로 캡처한 이미지의 높이가 1350px이라는 점이었다.
즉 문서 내부의 Layout 정확성과 최종 결과물의 완전성이 서로 다른 검증 대상이었다.
Headless Chrome의 Screenshot
저자는 Headless Chromium의 CLI를 사용했다.
대표적인 옵션은 다음과 같다.
--headless=new
--screenshot
--window-size=1080,1350
결과 이미지는 실제로 1080×1350이었다.
하지만 Footer는 포함되지 않았다.
흥미로운 점은 이미지의 하단에 약간의 여백이 남아 있었다는 것이다.
따라서 단순히 이미지를 눈으로 보면 의도한 디자인처럼 보일 수 있었다.
하지만 실제 Footer의 위치는 1590px 이후였다.
이미지에 포함될 수 없는 위치였다.
Chrome DevTools Protocol에서의 문제
저자는 Chrome DevTools Protocol(CDP)도 사용했다.
대표적인 API는 다음과 같다.
Emulation.setDeviceMetricsOverridePage.captureScreenshot
CDP에서는 다음 옵션을 사용할 수 있다.
captureBeyondViewport: true
이 설정은 현재 Viewport보다 아래에 있는 콘텐츠까지 캡처하는 데 사용할 수 있다.
하지만 저자의 자동화 코드에는 다른 문제가 존재했다.
실제 캡처된 이미지가 목표 크기보다 크면 해당 이미지를 다시 1080×1350으로 Crop하고 있었다.
따라서 전체 페이지를 캡처하더라도 마지막 단계에서 Footer가 제거됐다.
저자는 기존 코드가 출력한 다음 메시지를 확인했다.
1080x1722에서 1080x1350으로 잘랐음
이는 실제로 중요한 콘텐츠가 제거됐다는 의미였다.
하지만 프로그램은 해당 작업을 단순한 정보 메시지로 취급했다.
오류로 처리하지 않았다.
실제 수정
저자는 두 가지 검사를 추가했다.
첫 번째는 실제 문서 높이를 확인하는 것이다.
대표적인 DOM 속성은 다음과 같다.
document.documentElement.scrollHeight
두 번째는 Footer가 실제 캡처 영역 안에 존재하는지 확인하는 것이다.
대표적으로 다음 값을 읽을 수 있다.
getBoundingClientRect().bottom
이후 실제 캡처 영역의 높이와 비교한다.
예를 들어 Footer의 하단 위치가 1652px이라고 가정해 보자.
캡처 이미지의 높이가 1350px이라면 해당 Footer를 포함할 수 없다.
따라서 이미지 크기가 정확하더라도 검사를 실패 처리해야 한다.
전체 페이지를 캡처한 결과
저자는 실제 문서 높이인 1722px을 사용해 다시 캡처했다.
결과는 다음과 같았다.
- Footer의 연락처 정보 표시
- 구분선 표시
- 실제 하단 콘텐츠 포함
하지만 여기에는 중요한 디자인상의 차이가 존재한다.
최종 이미지가 반드시 1080×1350이어야 한다면 이미지를 1722px 높이로 확장하는 것이 최종 해결책은 아니다.
이 경우 실제 콘텐츠를 1350px 안에 배치하도록 Layout을 변경해야 한다.
따라서 다음 두 요구사항을 구분해야 한다.
첫 번째는 전체 콘텐츠를 빠짐없이 캡처하는 것이다.
두 번째는 지정된 이미지 크기 안에 모든 콘텐츠가 들어가도록 디자인하는 것이다.
저자의 수정은 첫 번째 문제를 해결한다.
두 번째 문제에는 별도의 Layout 조정이 필요할 수 있다.
Screenshot 검사의 설계 문제
이번 글에서 중요한 부분은 검사의 기준을 어디에서 가져오는지다.
기존 검사는 요청한 크기와 실제 이미지의 크기를 비교했다.
하지만 실제 콘텐츠의 크기는 확인하지 않았다.
저자는 이를 다음과 같은 문제로 설명한다.
검사 대상과 검사 기준이 같은 정보에서 만들어지면 실제 오류를 발견하지 못할 수 있다.
예를 들어 다음 검사를 생각할 수 있다.
- 요청한 이미지 크기와 결과 이미지 크기 비교
- 설정 파일의 행 수와 같은 설정에서 생성한 결과의 행 수 비교
- 같은 Parser를 두 번 실행해 결과 비교
이러한 검사는 서로 다른 구현에서 발생한 오류를 발견하는 데 한계가 있을 수 있다.
따라서 원본 문서의 실제 크기와 결과 이미지의 크기처럼 독립적인 정보를 비교해야 한다.
브라우저 실행 환경
저자는 다음 환경에서 테스트했다.
- Chromium 145.0.7632.0
- Headless 모드
- 2026년 11월
- 하나의 개발 환경
또한 동일한 Debugging Port로 여러 Chromium 프로세스를 실행하면서 연결 오류가 발생한 문제도 발견했다.
이를 해결하기 위해 프로세스 ID를 기준으로 Port를 분리했다.
하지만 특정 브라우저 버전의 Screenshot 동작을 모든 Chromium 버전에 일반화해서는 안 된다.
실제 Headless Chrome의 캡처 동작은 버전에 따라 변경될 수 있다.
적용 범위와 한계
이번 글은 이미지 생성 자동화의 실제 오류를 분석했다.
하지만 여러 브라우저 버전에서 동일한 문제를 반복 측정한 Benchmark는 아니다.
또한 모든 이미지 생성 도구가 같은 방식으로 Crop한다는 의미도 아니다.
이번 글은 웹페이지를 이미지나 PDF 같은 결과물로 변환하는 자동화에서 문서의 Layout이 올바르다는 사실과 최종 파일에 필요한 콘텐츠가 모두 포함됐다는 사실을 독립적으로 검증해야 한다는 점을 보여준다.
Open research, stronger privacy: Making Firefox users harder to fingerprint
- 저자: Tom Ritter, Frederik Braun, Christoph Kerschbaumer
- 매체: Mozilla Security Blog
- 게시일: 2026-11-10
- 기술: Browser Fingerprinting, JavaScript API, 개인정보 보호, OHTTP, Firefox
- 원문: https://blog.mozilla.org/security/2026/11/10/open-research-stronger-privacy-making-firefox-users-harder-to-fingerprint/
Mozilla가 약 2,500만 명의 Firefox 사용자로부터 수집한 데이터를 이용해 실제 Browser Fingerprinting의 특성을 분석하고 이를 완화하기 위한 연구 결과를 소개한 글이다.
이번 자료는 단순한 개인정보 보호 설정 안내가 아니다.
실제 Fingerprinting Script가 어떤 브라우저 정보를 이용해 사용자를 구분하는지 조사했다.
그리고 브라우저가 일부 정보를 제한하거나 변경하면 사용자의 식별 가능성이 어떻게 달라지는지 분석했다.
다만 중요한 시점상의 차이가 존재한다.
이번 글은 11월 10일에 게시됐다.
하지만 연구에서 설명하는 주요 보호 기능은 Firefox 160에서 처음 도입된 것이 아니다.
Mozilla에 따르면 관련 기능 가운데 가장 최근에 배포된 것은 Firefox 145에 포함돼 있었다.
따라서 이번 글은 새로운 Firefox 160 기능의 출시가 아니라 기존 보호 기능을 도출한 연구와 실제 효과를 설명하는 자료다.
Browser Fingerprinting
일반적인 웹사이트의 사용자 식별에는 Cookie가 사용될 수 있다.
하지만 Cookie가 없어도 사용자를 구분할 수 있는 방법이 존재한다.
대표적인 기술이 Browser Fingerprinting이다.
브라우저는 웹사이트에 여러 정보를 제공한다.
예를 들어 다음과 같다.
- 화면 크기
- 사용 가능한 Font
- 운영체제
- 브라우저 버전
- CPU 관련 정보
- 그래픽 장치
- Canvas 렌더링 결과
- Web Audio 처리 결과
이러한 정보 하나만으로 사용자를 식별하기는 어려울 수 있다.
하지만 여러 값을 조합하면 특정 사용자의 브라우저를 구분할 가능성이 높아진다.
예를 들어 같은 브라우저를 사용하는 사람이 많더라도 실제 화면의 크기와 설치된 Font, 그래픽 장치 등이 다를 수 있기 때문이다.
실제 연구 규모
Mozilla는 약 2,500만 명의 Firefox 사용자에 관한 측정 정보를 분석했다.
이를 통해 실제 Fingerprinting Script에서 사용하는 브라우저 정보의 구분 능력을 확인했다.
대표적인 비교 대상은 다음 서비스의 Fingerprinting 방식이었다.
- Fingerprint Pro
- Signifyd
- Akamai
Mozilla는 이러한 서비스에서 수집하는 종류의 브라우저 측정값을 모의로 구성해 사용자 식별 가능성을 분석했다.
다만 실제 모든 Fingerprinting 업체의 전체 내부 시스템을 그대로 재현했다는 의미는 아니다.
연구에서 정의한 데이터와 분석 모델을 기준으로 평가했다.
OHTTP를 이용한 데이터 수집
이번 연구에서는 대규모 사용자 데이터를 분석해야 했다.
하지만 Browser Fingerprinting을 연구하는 과정에서 실제 사용자의 식별 정보를 과도하게 수집한다면 개인정보 보호 목적과 충돌할 수 있다.
Mozilla는 이를 줄이기 위해 OHTTP를 사용했다.
OHTTP는 Oblivious HTTP를 의미한다.
이 구조에서는 요청의 전달과 실제 데이터의 해석을 분리할 수 있다.
대표적인 구조는 다음과 같다.
- 사용자가 암호화된 요청을 전달한다.
- Relay는 사용자의 IP 주소를 확인한다.
- Relay는 실제 요청 내용을 확인하지 못한다.
- Mozilla는 요청 내용을 처리한다.
- Mozilla는 해당 사용자의 IP 주소를 직접 확인하지 못한다.
이러한 구조는 네트워크상의 식별 정보와 실제 측정 데이터를 분리하는 데 도움이 된다.
Mozilla는 개별 데이터에 대한 접근과 보관 기간도 제한했다고 설명한다.
현재는 개별 기록을 삭제하고 집계 결과만 유지한다고 밝혔다.
화면 크기의 불필요한 세부 정보 제한
Mozilla가 분석한 정보 가운데 하나는 화면의 크기다.
예를 들어 다음 두 사용자가 있다고 가정해 보자.
두 사람은 같은 해상도의 모니터를 사용한다.
하지만 한 사람은 운영체제의 작업 표시줄을 화면 아래쪽에 배치했다.
다른 사람은 작업 표시줄을 화면 왼쪽에 배치했다.
이 경우 실제 웹페이지에서 읽을 수 있는 화면 영역의 크기가 달라질 수 있다.
이러한 차이는 사용자의 브라우저를 구분하는 추가 정보가 될 수 있다.
Mozilla는 브라우저가 불필요하게 이러한 세부 정보를 노출하지 않도록 일부 Screen API의 반환값을 제한했다.
따라서 작업 표시줄이나 Dock의 크기와 위치가 Fingerprinting에 사용되는 상황을 줄인다.
하지만 모든 화면 크기 정보가 완전히 제거되는 것은 아니다.
실제 웹 애플리케이션의 Layout과 기능을 위해 필요한 정보는 유지해야 하기 때문이다.
CPU 관련 정보의 제한
다음 대상은 CPU의 Core 수다.
예를 들어 사용자의 기기가 6개 또는 12개의 논리 프로세서를 가지고 있다고 가정해 보자.
이러한 값은 다른 브라우저 정보와 결합했을 때 사용자를 구분하는 데 활용될 수 있다.
Mozilla는 실제 프로세서 수를 그대로 노출하는 대신 일부 환경에서 다음 두 값 가운데 하나를 제공하도록 했다.
- 4
- 8
이러한 방식은 실제 하드웨어의 차이를 외부 웹사이트에 덜 노출하려는 목적이다.
하지만 CPU Core 수의 정보를 제한한다는 사실이 실제 JavaScript 실행에 사용할 수 있는 CPU의 개수를 반드시 변경한다는 의미는 아니다.
브라우저가 외부 코드에 제공하는 정보와 실제 실행 환경의 자원은 구분해야 한다.
Canvas와 Web Audio
Browser Fingerprinting에서는 그래픽 렌더링 결과도 사용될 수 있다.
예를 들어 같은 Canvas 코드를 여러 브라우저에서 실행한다고 가정해 보자.
사용자의 그래픽 장치와 운영체제, Font Rendering 방식에 따라 결과에 미세한 차이가 발생할 수 있다.
이러한 차이를 Hash로 변환하면 사용자를 구분하는 정보로 활용할 수 있다.
Web Audio에서도 비슷한 문제가 존재한다.
같은 오디오 처리를 수행하더라도 실제 실행 환경의 계산 차이가 나타날 수 있기 때문이다.
Mozilla는 이러한 차이를 줄이기 위해 일부 렌더링과 계산 동작을 더 일관되게 만들었다고 설명한다.
또한 일부 Fingerprinting Signal에는 Randomization도 사용한다.
하지만 Randomization의 효과는 모든 경우에 동일하지 않다.
특정 공격자가 여러 측정 결과를 수집해 실제 값을 추정할 가능성도 고려해야 한다.
실제 연구 결과
Mozilla는 보호 기능 적용 이후 다음 변화가 나타났다고 설명한다.
- 고유한 Fingerprint를 가진 사용자 수 감소
- 같은 Fingerprint를 공유하는 사용자 집단의 크기 증가
- 일부 주요 Fingerprinting 방식의 정확성 감소
이러한 결과는 브라우저가 제공하는 정보를 더 일관되게 제한하면 실제 사용자 식별의 정확성이 낮아질 수 있다는 점을 보여준다.
하지만 이번 블로그 글에는 모든 측정 조건에서 적용할 수 있는 하나의 정확도 감소 비율이 제시되지 않았다.
따라서 Fingerprinting의 정확성이 특정 비율만큼 감소했다고 임의로 계산해서는 안 된다.
또한 Mozilla는 이번 연구의 결과가 Browser Fingerprinting을 완전히 불가능하게 만든다는 의미는 아니라고 설명한다.
추적 기술은 이후 변경될 수 있기 때문이다.
기본 보호와 Strict Mode
모든 Fingerprinting 보호 기능이 동일한 설정에서 활성화되는 것도 아니다.
Mozilla는 일부 보호 기능을 모든 브라우징 모드에서 기본 제공한다.
대표적인 예는 작업 표시줄이나 Dock 관련 정보 제한이다.
반면 다른 보호 기능은 다음 환경에서 먼저 제공될 수 있다.
- Private Browsing
- Strict Enhanced Tracking Protection
따라서 Firefox를 사용한다는 사실만으로 모든 연구상의 보호 기능이 항상 같은 수준으로 활성화된다고 판단해서는 안 된다.
실제 브라우저 버전과 개인정보 보호 설정에 따라 지원 범위가 달라질 수 있다.
웹 개발에서 고려할 부분
이번 연구는 개인정보 보호뿐 아니라 웹 애플리케이션의 설계와도 연결된다.
예를 들어 개발자가 navigator.hardwareConcurrency를 이용해 실제 기기의 CPU Core 수를 알아내려고 한다고 가정해 보자.
브라우저는 개인정보 보호를 위해 실제 하드웨어의 정확한 정보를 제공하지 않을 수 있다.
따라서 해당 값을 실제 CPU Core 수의 정확한 측정값으로 취급해서는 안 된다.
또한 화면 크기와 Canvas 렌더링 결과도 브라우저의 정책에 따라 영향을 받을 수 있다.
실제 웹 애플리케이션에서는 이러한 값에 과도하게 의존하지 않는 설계가 필요할 수 있다.
연구의 적용 범위와 한계
이번 글은 Mozilla의 자체 연구 결과를 소개한다.
연구 논문은 공개돼 있으며 CCS 2026에 채택됐다고 설명한다.
하지만 블로그에서 요약한 결과가 모든 브라우저와 모든 Fingerprinting 기술에 동일하게 적용되는 것은 아니다.
또한 사용자의 브라우저를 추적할 수 있는 방법은 Fingerprinting 외에도 존재한다.
예를 들어 다음 방법을 생각할 수 있다.
- 로그인 계정
- Cookie
- 네트워크 기반 식별 정보
- 서비스 자체의 사용자 식별자
따라서 Fingerprinting의 정확성을 낮추는 것만으로 모든 온라인 추적이 사라지는 것은 아니다.
이번 글은 브라우저에서 제공하는 작은 기술 정보들이 결합될 때 사용자를 구분할 수 있다는 사실과, 이러한 정보를 제한하면서 실제 웹사이트의 호환성을 유지하는 것이 브라우저 개인정보 보호 설계의 핵심 과제라는 점을 대규모 연구로 설명한 자료다.