전 세계적으로 오염된 JavaScript 코드 추적
이전 기사에서 JavaScript 코드를 통해 전역 범위에 추가된 변수의 이름을 발견할 수 있는 기술을 배웠습니다.일반적으로 글로벌 변수 이름만 알고 있으면 1) 변수가 글로벌 범위에 존재할 수 있는지 여부와 그렇지 않으면 2) 글로벌 범위의 JavaScript 코드 행에 추가할 수 있는지 여부를 결정합니다.
그럼에도 불구하고 전역 변수를 만드는 자바스크립트 코드를 추적하는 것은 그리 간단하지 않다. 예를 들어 전역 변수의 이름이 매우 통용될 때 (예:
item
, x
, 전역 변수를 만드는 코드가 자바스크립트 프로그램의 라이버 트리에 깊이 들어갈 때.다음은 코드 내부에서 발생하는 전체 위치를 디버깅하는 데 도움을 줄 자바스크립트 유틸리티를 만드는 방법입니다.
Here’s a real-world example where this utility has helped me track-down a global variable leak coming from third-party JavaScript code.
전 세계 오염의 예
예를 들어, 이전 기사에서 공유한 HTML 문서에 대해 다시 한 번 살펴보겠습니다.
<html>
<body>
<h1>Hello world!</h1>
<script src="https://unpkg.com/[email protected]/dist/jquery.js"></script>
<script>
function doSomethingTwice() {
for (i = 0; i <= 2; i++) {
const myString = `hello-world-${i}`;
// Let's imagine we're going to do something with myString here...
}
}
doSomethingTwice();
</script>
</body>
</html>
페이지의 두 스크립트 (jquery.js
와 내연 스크립트 $
는 네 개의 서로 다른 전역 변수를 추가했습니다. jQuery
와 jquery.js
, 그리고 doSomethingTwice
와 i
내연 스크립트입니다.jQuery가 매우 유행하기 때문에 $
와 jQuery
전역 이름은 라이브러리를 만드는 것과 쉽게 연결됩니다. (전역 유출이 아니라는 것을 알아야 합니다.)그러나 다른 두 전 세계 선수의 상황은 다르다.
doSomethingTwice
는 루트 범위에서 정의되었기 때문에 전역 범위에 추가되었습니다. (더 깨끗한 방법은closure/iLife에 봉인하는 것입니다.)코드 라이브러리에서 검색과 교체를 통해 이 전역을 만드는 코드를 찾는 것은 어렵지 않을 것이다. doSomethingTwice
는 매우 독특한 이름이기 때문이다.그러나 전역 이름이 더 통용되거나 (예: run
코드가 희화화되거나 축소되거나 의존항에서 왔다면 어떻게 해야 합니까?그 이름만으로 성명을 추적하는 것은 더욱 어려워질 것이다.i
가 전역 범위에 추가되었습니다. 왜냐하면 우리가 그것을 성명할 때 var
/let
/const
가 없고 strict mode에 없기 때문입니다.이 작은 예에서, 어느 줄의 코드가 그것을 성명했는지 매우 분명하다.하지만 행운을 빕니다. 더 큰 프로그램에서 검색하고 바꾸십시오.😅. 디버그 전역 누설: 호출 창고 검사
다음은 우리가 이런 얄미운 글로벌 변수를 추적하는 데 도움을 줄 수 있는 고차원 개술이다.
set
대상에 있는 이 변수의 window
명령은 변수를 설정할 때 사용자 정의 코드를 터치합니다.이 코드의 목표는 전역 변수를 설정하는 내용을 가리키는 것이다.window
(또는 globalThis
대상에 주목하자.이 아이디어는
window.i = 1
와 같은 값이 발생할 때마다 우리는 코드를 실행해서 이 값이 발생하는 상하문을 알려주기를 원한다는 것이다.유용성을 위해서, 이 상하문은 그것을 실행하는 코드에 대한 정보를 제공해야 한다. (예를 들어, 발생하는 코드 줄이나 파일을 알려주는 것)다음은 이러한 정보를 얻는 몇 가지 방법입니다.
debugger;
문구의 정지 코드를 사용하여 위아래 문장을 검사합니다. 이것은 스크립트 원본에 단점을 추가하는 것과 똑같습니다. 디버깅 필드와 패키지를 닫는 데 도움이 됩니다.console.trace()
인쇄 스택 추적을 사용합니다.이것은 실행 과정에서 창고 추적 코드를 검사하는 데 도움이 된다.onGlobalDeclaration
함수를 사용하여 이 두 가지 해결 방안을 실현할 것이다.function onGlobalDeclaration(globalName) {
// Print the stack trace to the console.
console.trace();
// Halt the code execution (only if the DevTools are running).
debugger;
}
// TODO: Code that attaches the onGlobalDeclaration listener.
디버그 전역 누설: 에이전트
window
속성기왕 우리가 창고에 관한 상하문 정보를 얻을 수 있는 이상 전역 변수를 설정할 때, 우리는 어떻게 invoke
onGlobalDeclaration
를 부가합니까?과거에 나는 몇 가지 다른 선택을 시도했지만, 나에게 더 좋은 방법은 전역 변수가 다른 코드 라이브러리에 설정되기 전에 그 자체를 에이전트로 실례화하는 것이다.기본적으로
window.i = 1
문장이 실행되기 전에 우리는 그것을 호출할 때 우리도 호출할 수 있도록 window.i
setter 함수를 실례화하고 다시 쓰기를 희망한다onGlobalDeclaration
.function addGlobalToInspect(globalName) {
function onGlobalDeclaration(globalName) {
// Print the stack trace to the console.
console.trace();
// Halt the code execution (only if the DevTools are running).
debugger;
}
// Proxy the global variable that we're interested in.
Object.defineProperty(window, globalName, {
set: function (value) {
// Invoke onGlobalDeclaration and set the value in a proxy attribute.
onGlobalDeclaration(globalName);
window[` __globals-debugger-proxy-for-${globalName}__ `] = value;
},
get: function () {
// When the global is requested, return the proxy attribute value.
return window[` __globals-debugger-proxy-for-${globalName}__ `];
},
configurable: true,
});
}
// Inspect the strack whenever an "i" variable is added to the global scope.
addGlobalToInspect("i");
Note on ES6 proxies : ES6 introduced the
Proxy
object to cover similar use-cases. If you’re not familiar with it, theProxy
object allows you to create an object that can be used in place of the original object, but which may redefine fundamental Object operations like getting, setting, and defining properties.
Unfortunately, theProxy
object doesn’t work well for our use case because of how thewindow
object is implemented at the browser level (with proxies, we’d need to override it with its own proxy instance, which we can’t do), so we need to fallback to the monkey-patching approach.
좋아요!현재 우리의 코드는 글로벌 성명을 차단할 준비가 되어 있다.다음 단계는 전역 성명문 앞에서 실행하는 것을 확보하는 것이다.
addGlobalToInspect
디버그 글로벌 누출:통합 글로벌 검사기
우리는 디버깅 절차를 완성하기 위해 여전히 두 가지 일을 해야 한다.
우선, 우리는 검사할 전역 변수를 설정하기 전에 실행해야 한다.
addGlobalToInspect
어떻게, 언제 이렇게 할지 결정하지만, 제 조언은 글로벌 inspector 코드를 자신의 코드에 넣는 것입니다.js 파일 (예: globals-debugger.js
은 다른 모든 스크립트를 불러오기 전에 불러올 수 있도록 합니다.<html>
<body>
<h1>Hello world!</h1>
<!---
Make sure to load globals-debugger.js first.
It might be wise to load it conditionally depending
on the environment (e.g., do not load it in production).
—-->
<script src="./globals-debugger.js"></script>
<script src="https://unpkg.com/[email protected]/dist/jquery.js">.
</script>
<script>
function doSomethingTwice() {
for (i = 0; i <= 2; i++) {
const myString = `hello-world-${i}`;
// Let's imagine we're going to do something with myString here...
}
}
doSomethingTwice();
</script>
</body>
</html>
그리고 전역 변수를 선택해서 동적 검사를 하는 것이 좋습니다. 지금처럼 코드에서 그것들을 하드코딩하는 것이 아니라. (우리가 addGlobalToInspect("i")
에서 한 것처럼)스크립트가 빨리 실행되기 때문에, 전역 이름을 매개 변수로 전달하는 가장 간단한 방법은 그것들을 조회 매개 변수로 URL에 추가하는 것이라고 생각합니다.
예를 들어, URL의
?globalsToInspect=i,jQuery
를 페이지로 로드할 때 자동으로 체크i
및 jQuery
글로벌 변수를 시작하도록 스크립트를 변경할 수 있습니다.// Grab the global to inspect from the URL's "globalsToInspect" query parameter.
const parsedUrl = new URL(window.location.href);
(parsedUrl.searchParams.get("globalsToInspect") || "")
.split(",")
.filter(Boolean)
.forEach((globalToInspect) => addGlobalToInspect(globalToInspect));
전체 솔루션:
globals-debugger.js
글로벌 디버거를 최종적으로 시도하기 전에 다음은 완전한 코드(주석과 추가 보안 검사가 있음)입니다.
globals-debugger.js
사용 예
마지막으로, 여기는 우리가 방금 구축한 것을 사용하여 i
전 세계가 창조한 예를 추적하는 것이다
Note: This is just a simplified use-case to show you the
globals-debugger
use-flow. In a more realistic scenario you would probably use it to track down globals added in bigger codebases or from third-party libraries deep down the dependencies tree.
변수?globalsToInspect=i
를 설정할 때 i
조회 매개 변수를 사용하여 위의 HTML 페이지를 열면 코드 실행을 즉시 정지합니다 (현재 패키지에 있는 globalName
변수가 오른쪽 패널에 있는 것을 주의하십시오 i
:
debugger;
문장이 우리 코드에 있기 때문에 현재 함수(Shift+F11)를 종료하고 설정i
변수의 코드 줄에 들어가야 합니다:
마지막이지만 가장 중요하지 않은 것은 DevTools 컨트롤러를 검사하면 기록된 창고 추적을 볼 수 있습니다. 이것은 스크립트가 실행될 때 창고를 검사하는 데 도움이 됩니다.또한 에이전트를 사용하더라도 글로벌 변수가 제대로 작동하는지 확인할 수 있습니다.
Reference
이 문제에 관하여(전 세계적으로 오염된 JavaScript 코드 추적), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/mmazzarolo/track-down-the-javascript-code-responsible-for-polluting-the-global-scope-35pm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)