//PC 및 모바일 접속 확인 실시
if(navigator.platform){
}
navigator.platform 이 값이 궁금하다.
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform
https://kkh0977.tistory.com/873
window.onload : 웹브라우저 로딩 완료 상태를 확인
navigator.platform : 브라우저가 실행되는 플랫폼 정보를 반환
navigator.userAgent : 웹 브라우저 전반에 대한 정보를 제공하는 객체
<script>
/* html 최초 로드 및 이벤트 상시 대기 실시 */
window.onload = function() {
console.log("");
console.log("[window onload] : [start]");
console.log("");
//PC 및 모바일 접속 확인 실시
checkPcAndMobile();
};
/* 브라우저 및 모바일 접속 체크 실시 */
function checkPcAndMobile(){
console.log("");
console.log("[checkPcAndMobile] : [start]");
console.log("");
//운영체제 종류 선언
var filterOs = "win16|win32|win64|mac|macintel";
//PC 및 모바일 접속 확인 실시
if(navigator.platform){
if(0 > filterOs.indexOf(navigator.platform.toLowerCase())){
console.log("");
console.log("[checkPcAndMobile] : [platform] : [Mobile]");
console.log("");
//모바일 기기 종류 확인 함수 호출
checkMobileDevice();
}
else {
console.log("");
console.log("[checkPcAndMobile] : [platform] : [PC]");
console.log("");
alert("PC");
}
}
else {
console.log("");
console.log("[checkPcAndMobile] : [platform] : [none]");
console.log("");
alert("none");
}
};
/* 모바일 기기 체크 실시 */
function checkMobileDevice(){
console.log("");
console.log("[checkMobileDevice] : [start]");
console.log("");
//모바일 기종 종류 선언
var mobileArray = new Array();
mobileArray.push("iPhone");
mobileArray.push("iPod");
mobileArray.push("BlackBerry");
mobileArray.push("Android");
mobileArray.push("Windows CE");
mobileArray.push("LG");
mobileArray.push("MOT");
mobileArray.push("SAMSUNG");
mobileArray.push("SonyEricsson");
mobileArray.push("webOS");
mobileArray.push("IEMobile");
mobileArray.push("Opera Mini");
//반복문 수행 실시
for(var mobile in mobileArray){
if(navigator.userAgent.match(mobileArray[mobile]) != null){
console.log("");
console.log("[checkMobileDevice] : " + mobileArray[mobile]);
console.log("");
alert(mobileArray[mobile]);
break;
}
}
};
</script>
https://d2.naver.com/helloworld/6532276
User-Agent Client Hints의 도입, UA 프리징을 대비하라
2020.10.12|21961
이 글에서는 클라이언트 입장에서 User-Agent Client Hints를 다룹니다.
지금까지 웹 서비스는 User-Agent HTTP 헤더에 포함된 User-Agent string에서 브라우저, OS, 사용자의 기기 정보 등 사용자 에이전트 정보를 얻을 수 있었습니다. User-Agent string을 이용하는 이유는 주로 다음과 같습니다.
- 특정 버전의 버그
- OS의 동작 차이
- 버전에 따른 동작 차이
- 사용자 에이전트에 따라 보여줄 콘텐츠 협상
우리는 위와 같은 다양한 이유로 User-Agent string을 사용해 왔지만 User-Agent string에는 많은 엔트로피(정보량)가 담겨 있어 개인정보 침해 문제가 있을 수 있습니다.
그래서 Chrome은 개인정보 보호를 위한 샌드박스 프로젝트 중 Client Hints 도입을 시도했습니다. Client Hints를 쉽게 말하자면 클라이언트 및 에이전트의 정보라고 할 수 있으며 가져올 정보를 명시합니다. 그렇기 때문에 사용자는 서버 및 클라이언트가 어떤 정보를 요구하는지 알 수 있습니다. 지금까지의 Client Hints 관련 Chrome 릴리즈 사항은 다음과 같습니다.
- Chrome 46 - HTTP Client Hints 실험적 도입
- Chrome 77 - Freeze-User-Agent 플래그 추가
- Chrome 82, 83 (2020.05) - User-Agent Client Hints 실험적 도입
- Chrome 84 (2020.07) - User-Agent Client Hints 인터페이스 변경
이 글에서는 이에 따라 앞으로 어떤 변화가 있을지, 이 변화에 어떻게 대응해야 할지 알아보겠습니다.
UA 프리징
Chrome 83부터 User-Agent Client Hints가 실험적으로 도입되었고 가장 큰 이슈는 바로 User-Agent string 프리징(이하 UA 프리징)이다. UA 프리징으로 달라지는 점은 다음과 같다.
- 다음 속성값이 고정된다.
- navigator.userAgent
- navigator.appVersion
- navigator.platform (Android Chrome에서는 Linux armv8l으로 고정)
- navigator.productSub
- navigator.vendor
- Chrome에서 안드로이드를 제외한 모든 운영체제는 윈도우 10으로 변한다.
- 동기 방식으로 OS 이름, OS 버전, 모델명을 알 수 없다.
- navigator.userAgent 대신 navigator.userAgentData을 사용해야 한다.
- 브라우저 버전은 메이저 버전만 나타난다.
- OS 이름, 버전, 모델명, 브라우저의 풀버전은 비동기 방식으로 알 수 있다.
UA 프리징은 다음 플래그를 활성화하면 테스트할 수 있다.
- chrome://flags/#enable-experimental-web-platform-features
- chrome://flags/#freeze-user-agent
UA 프리징 테스트 결과 navigator.userAgent를 사용하여 얻은 User-Agent string 값은 다음과 같다.
- Galaxy Z Flip, Android 10, Chrome 85.0.4183.81
- 전: Mozila/5.0 (Linux; Android 10; SM-F700N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.81 Mobile Safari/537.36
- 후: Mozila/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.0.0 Mobile Safari/537.36
- Mac OS X 10.15.4, Chrome Canary 87.0.4243.0
- 전: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4243.0 Safari/537.36
- 후: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.0.0 Safari/537.36
UA 프리징 결과 기기명, OS의 정보, 브라우저의 버전이 불분명해진 것을 확인할 수 있다. 앞으로 User-Agent string을 고정된 값으로 제공하기 위해 값은 점점 더 간소해질 수 있다.
UA 프리징 대응 방안
User-Agent Data
UA 프리징의 대응 방안으로 User-Agent string을 세분화해 Object 형식으로 나타낸 User-Agent Data를 사용할 수 있다. 인터페이스는 다음과 같다.
dictionary NavigatorUABrandVersion {
DOMString brand;
DOMString version;
};
dictionary UADataValues {
DOMString platform;
DOMString platformVersion;
DOMString architecture;
DOMString model;
DOMString uaFullVersion;
};
[Exposed=(Window,Worker)]
interface NavigatorUAData {
readonly attribute FrozenArray<NavigatorUABrandVersion> brands;
readonly attribute boolean mobile;
Promise<UADataValues> getHighEntropyValues(sequence<DOMString> hints);
};
interface mixin NavigatorUA {
[SecureContext] readonly attribute NavigatorUAData userAgentData;
};
Navigator includes NavigatorUA;
WorkerNavigator includes NavigatorUA;
navigator.userAgentData에 접근하면 brands(84 이전 버전에서는 uaList)과 mobile 속성이 있으며 getHighEntropyValues 메서드를 사용할 수 있다.
그림 Chrome Canary 87.0.4243.0의 navigator.userAgentData
그림 Edge 85.0.564.44의 navigator.userAgentData
- brands는 사용자 에이전트의 상업명과 버전의 이름이 담긴 리스트이다. 87 버전을 기준으로 Chromium을 사용하는 브라우저에서는 브라우저 브랜드, Chromium 브랜드, GREASE 브랜드 3개의 값이 임의의 순서로 있다.
- mobile은 사용자 에이전트의 기기가 모바일인지를 나타내는 값이다.
- getHighEntropyValues 메서드는 높은 엔트로피에 해당하는 값을 가져온다. brands(브라우저 이름과 메이저 버전)와 mobile은 낮은 엔트로피로 분류되기 때문에 동기 방식으로 값을 가져올 수 있지만 그 외 정보는 높은 엔트로피로 분류되어 getHighEntropyValues 메서드로 가져와야 한다. 또한 User-Agent string처럼 모든 정보를 가져오는 게 아니라 자신에게 필요한 정보만 가져올 수 있다.
navigator.userAgentData.getHighEntropyValues([
"architecture",
"model",
"platform",
"platformVersion",
"uaFullVersion",
]).then(info => {
console.log(info);
});
그림 Mac OS X 10.15.4, Chrome Canary 87.0.4243.0의 navigator.userAgentData.getHighEntropyValues 호출 결과
아직은 Editor's draft 상태이며 Chrome 85에서는 권한 요청 프롬프트가 나타나지 않는다. 하지만 사용자 권한이 필요한 메서드이기 때문에 추후에는 권한 요청 프롬프트가 나타날 수 있고 사용자들은 이 사이트에서 어떤 정보를 수집하는지 알 수 있게 된다.
navigator.userAgentData.getHighEntropyValues를 통해 비동기 방식으로 정보를 가져오면 기존 User-Agent string으로 얻은 정보와 동일한 정보를 얻을 수 있다. 하지만 모든 코드를 비동기 방식으로 바꾸기 어려울뿐더러 다음 코드와 같이 상수로 사용하는 사람도 있을 것이다.
const userAgent = navigator.userAgent;
// check Mac
export const isMac = userAgent.indexOf("Mac") > -1;
// check iOS
export const isIOS = (isMac || userAgent.indexOf("iPhone") > -1 || userAgent.indexOf("iPad") > -1) && !!navigator.maxTouchPoints && navigator.maxTouchPoints > 0;
// check Chrome
export const isChrome = userAgent.indexOf("Chrome") > -1;
네이버 서비스가 사용하고 있는 agent 모듈 @egjs/agent도 navigator.userAgent를 통해 브라우저 및 OS 정보를 가져오고 있다. 그렇기 때문에 UA 프리징에 대한 대비가 필요했다. @egjs/agent에서는 navigator.userAgentData를 이용해 어떻게 문제에 대응했는지 알아보겠다.
동기 방식의 대응 방안
먼저 동기 방식으로 해결할 수 있다면 기존 코드와 크게 달라지지 않기 때문에 최선의 해결책일 것이다. 그럼에도 불구하고 동기 방식으로 해결할 수 없는 문제라면 비동기 방식으로 전환을 고려해야 한다.
동기 방식으로 확인할 수 있는 정보는 다음과 같다.
- navigator.userAgentData.brands: 브라우저의 이름과 메이저 버전, Chromium 정보
- navigator.userAgentData.mobile: 모바일 여부
- navigator.platform: Android Chrome(Linux armv8l) 여부
- User-Agent Client Hints를 지원하지 않는 브라우저의 OS, OS 버전(Chrome 84의 지원 범위: Android 5.0 이상, Mac OS X 10.10 이상, 윈도우 7 이상)
다음은 동기 방식으로 사용자 에이전트 정보를 확인하는 예시 코드이다.
import getAgent from "@egjs/agent";
const agent = getAgent();
// Android 확인
export const IS_ANDROID = agent.os.name === "android";
// 브라우저 IE11 확인
export const IS_IE11 = agent.browser.name === "ie" && agent.browser.majorVersion === 11;
// User-Agent Client Hints를 지원하지 않는 Android 4 확인
export const IS_ANDROID4 = IS_ANDROID && agent.os.majorVersion === 4;
// User-Agent Client Hints를 지원하지 않는 iOS 10 확인
export const IS_IOS10 = agent.os.name === "ios" && agent.os.majorVersion === 10;
Safari 추측
Safari(Safari 14, AppleWebkit 605 기준)는 아직 User-Agent Client Hints를 지원하지 않기 때문에 brand 리스트에 무슨 값이 있을지 알 수 없다. 또한 iOS 정책상 문제로 다른 브라우저 엔진을 사용하고 있는 기존의 브라우저(Chrome, Whale, Edge, Firefox)는 iOS 버전에서는 Safari를 사용한다. 그럼 Safari에서 User-Agent Client Hints가 도입된다면 brand 리스트에는 어떤 값이 있을까? iOS Chrome을 기준으로 다음과 같이 추측할 수 있다.
- [Safari, Chrome]
- [Safari, CriOS]
- [AppleWebkit, Chrome]
- [AppleWebkit, CriOS]
Safari 기반의 브라우저는 Safari 또는 AppleWebkit brand 정보가 있을 거라 추측하고 있다. 또한 Safari 기반 브라우저의 OS는 Mac 또는 iOS만 해당하기 때문에 다음과 같이 OS를 추측할 수 있다.
- Safari 기반이고 mobile이면 iOS이다.
- Safari 기반이고 mobile이 아니면 Mac이다.
즉, 다음과 같이 사용자 에이전트 정보를 확인할 수 있을 것이다.
import getAgent from "@egjs/agent";
const agent = getAgent();
// iOS 추측 가능
export const IS_IOS = agent.os.name === "ios";
// MAC Safari 추측 가능
export const IS_MAC_SAFARI = agent.os.name === "mac" && agent.browser.name === "safari";
비동기 방식으로 전환
동기 방식으로 확인할 수 없는 정보는 비동기 방식으로 에이전트 값을 얻은 후에 코드가 실행되어야 한다. 동기 방식으로 확인할 수 없는 정보는 다음과 같다.
- Android, iOS, Mac Safari를 제외한 OS 정보
- 특정 OS 버전
- 브라우저의 풀버전
import getAgent from "@egjs/agent";
const agent = getAgent();
// Windows를 확인할 수 없다.
export const IS_WINDOWS = agent.os.name === "window";
// Safari를 제외한 mac OS를 확인할 수 없다.
export const IS_MAC = agent.os.name === "mac";
다음은 navigator.userAgentData.getHighEntropyValues 메서드로 정확한 agent 값을 얻을 수 있도록 만든 getAccurateAgent 비동기 함수이다.
import { getAccurateAgent } from "@egjs/agent";
async function start() {
const agent = await getAccurateAgent();
const isWindows = agent.os.name === "window";
const isMac = agent.os.name === "mac";
}
마치며
매일 3천만 명 이상이 네이버 서비스를 이용하고 있으며 모든 서비스에서 @egjs/agent 또는 navigator.userAgent를 사용하고 있기 때문에 네이버는 User-Agent Client Hints 도입에 주목하고 있다. 갑자기 User-Agent Client Hints가 도입된다면 서비스뿐만 아니라 agent 모듈을 사용하고 있는 Component들도 큰 타격을 입을 것이므로 네이버 FE Platform 팀은 User-Agent Client Hints를 리서치하고 @egjs/agent를 통해 지원하기로 했다.
User-Agent Client Hints는 아직 Editor's Draft 상태(2020.09.18)이며 언제든지 인터페이스 및 동작이 바뀔 수 있기 때문에 계속 주시하고 있고 Chromium뿐만 아니라 Webkit 코드도 확인하면서 빠르게 대응하고자 한다. 여러분도 함께 준비하는 데 이 글이 도움이 되길 바란다.
'차근차근 > JAVA Script' 카테고리의 다른 글
pagecontext.request.contextpath (0) | 2021.12.15 |
---|---|
클립보드 복사 execCommand (0) | 2021.12.15 |
자바스크립트 위치..? (0) | 2021.12.07 |
[Vue.js] v-cloak (0) | 2021.12.06 |
[Vue.js] Vue.js란 (5) - Vue 컴포넌트 (0) | 2021.12.06 |