요소 내에서 <script>를 실행하지 않도록 브라우저에 요청할 수 있습니까?


84

HTML 문서의 특정 부분에서 JavaScript를 실행하지 않도록 브라우저에 지시 할 수 있습니까?

처럼:

<div script="false"> ...

추가 보안 기능으로 유용 할 수 있습니다. 내가 원하는 모든 스크립트는 문서의 특정 부분에로드됩니다. 문서의 다른 부분에는 스크립트가 없어야하며 스크립트가있는 경우 실행해서는 안됩니다.


1
내가 아는 것은 아닙니다. 나는 100 % 말할 수 없기 때문 댓글이 아닌 답변입니다
freefaller

4
@ chiastic-security DOM이로드 된 후에 만 ​​DOM을 탐색 할 수 있습니다. 어느 시점에서 해당 블록의 모든 JS가 실행되었을 것입니다.
카울

8
내가 생각할 수있는 가장 가까운 것은 콘텐츠 보안 정책으로, 스크립트를 출처 (아마도 원하는대로)로 제한 할 수 있습니다. 예를 들어 script-src:"self"도메인의 스크립트 만 페이지에서 실행되도록 지정 하면됩니다. 관심이 있으시면 Mike West의 CSP 관련 기사를 읽어보십시오 .
Christoph

1
@ chiastic-security 헤더가 이미 전송 된 후 헤더에 지정된 제한을 완화하려면 어떻게 계획합니까? 어쨌든 CSP는 기본적으로 인라인 스크립트를 비활성화하고 원격 스크립트는 허용 목록에 포함되지 않는 한로드되지 않기 때문에 다른 스크립트와 결합해야하는 이유는 무엇입니까? CSP는 아마도 OP의 최선의 선택 일 것입니다. 누군가 CSP 답변을 남기기를 바랍니다.
Dagg Nabbit

6
누군가가 당신의 HTML에 임의의 블록을 주입하는 것에 대해 염려한다면, 당신이 제안한 솔루션은 </div>그들이이 DOM 요소를 닫기 위해를 주입 한 다음 <div>스크립트가 실행되지 않는 것의 형제가 될 새로운 것을 시작하는 것을 어떻게 막을 것인가?
Damien_The_Unbeliever

답변:


92

예, 할 수 있습니다. :-) 대답은 CSP ( 콘텐츠 보안 정책 )입니다.

대부분의 최신 브라우저 는 신뢰할 수있는 외부 파일에서 JavaScript 코드를로드하고 모든 내부 JavaScript 코드를 허용하지 않도록 브라우저에 지시하는 이 플래그를 지원 합니다. 유일한 단점은 전체 페이지에서 인라인 자바 스크립트를 사용할 수 없다는 것입니다 (단일 <div>). 다른 보안 정책을 사용하여 외부 파일의 div를 동적으로 포함하여 해결 방법이있을 수 있지만 확실하지 않습니다.

그러나 외부 자바 스크립트 파일에서 모든 자바 스크립트를로드하도록 사이트를 변경할 수 있다면이 헤더와 함께 인라인 자바 스크립트를 모두 비활성화 할 수 있습니다!

다음은 예제가 포함 된 멋진 튜토리얼입니다. HTML5Rocks Tutorial

이 HTTP-Header 플래그를 보내도록 서버를 구성 할 수 있다면 세상이 더 나은 곳이 될 것입니다!


2
+1 정말 멋지네요. 존재하는 줄 몰랐어요! (참고로, 귀하의 위키 링크는 독일어 버전으로 직접 연결됩니다.) 다음은 브라우저 지원에 대한 요약입니다. caniuse.com/#feat=contentsecuritypolicy
BrianH

4
이렇게하더라도 페이지에 이스케이프되지 않은 사용자 입력을 허용하는 것은 여전히 ​​좋지 않습니다. 기본적으로 사용자가 원하는대로 페이지를 변경할 수 있습니다. 모든 CSP (콘텐츠 보안 정책) 설정이 최대로 설정되어 있어도 (인라인 스크립트, 스타일 등을 허용하지 않음) 사용자는 GET 요청에 대해 이미지 srcs를 사용하거나 사용자를 속여서 사이트 간 요청 위조 (CSRF) 공격을 수행 할 수 있습니다. POST 요청을 위해 양식 제출 버튼을 클릭합니다.
Ajedi32

@ Ajedi32 물론 항상 사용자 입력을 삭제해야합니다. 그러나 CSP는 이미지 또는 CSS와 같은 GET 요청에 대한 정책을 설정할 수도 있으며이를 차단할뿐만 아니라 서버에 알립니다.
Falco

1
@Falco 나는 문서를 읽었고 내 이해는 해당 요청을 도메인의 특정 하위 페이지 집합이 아닌 지정된 도메인으로 만 제한 할 수 있다는 것입니다. 아마도 설정 한 도메인은 사이트와 동일한 도메인 일 것이므로 CSRF 공격에 여전히 열려 있음을 의미합니다.
Ajedi32

3
@Falco 예, 기본적으로 StackExchange가 새로운 Stack Snippets 기능으로 한 일입니다 : blog.stackoverflow.com/2014/09/… 입력을 적절하게 삭제하면 별도의 도메인이 필요하지 않습니다.
Ajedi32

13

이벤트를 <script>사용하여에서 로드 한 자바 스크립트를 차단할 수 있습니다 beforescriptexecute.

<script>
  // Run this as early as possible, it isn't retroactive
  window.addEventListener('beforescriptexecute', function(e) {
    var el = e.target;
    while(el = el.parentElement)
      if(el.hasAttribute('data-no-js'))
        return e.preventDefault(); // Block script
  }, true);
</script>

<script>console.log('Allowed. Console is expected to show this');</script>
<div data-no-js>
  <script>console.log('Blocked. Console is expected to NOT show this');</script>
</div>

참고 beforescriptexecuteHTML 5.0에 정의되어 있지만, HTML 5.1에서 제거되었습니다. Firefox는이를 구현 한 유일한 주요 브라우저입니다.

페이지에 신뢰할 수없는 HTML 묶음을 삽입하는 경우 해당 요소 내부의 차단 스크립트는 더 많은 보안을 제공하지 않습니다. 신뢰할 수없는 HTML이 샌드 박스 요소를 닫을 수 있으므로 스크립트가 외부에 배치되어 실행되기 때문입니다.

그리고 이것은 같은 것을 차단하지 않습니다 <img onerror="javascript:alert('foo')" src="//" />.


바이올린이 예상대로 작동하지 않는 것 같습니다. "차단 된"부분을 볼 수 없어야 하죠?
Salman A

@SalmanA 정확합니다. 아마도 브라우저가 beforescriptexecute이벤트를 지원하지 않을 것 입니다. Firefox에서 작동합니다.
Oriol 2014 년

아마도 제공된 코드를 사용하여 Chrome에서 작동하지 않기 때문일 수 있습니다.하지만 방금 코드를 코드 조각으로 변환 한 것으로 보입니다. :-)
Mark Hurd

beforescriptexecute지원되지 않으며 대부분의 주요 브라우저에서 지원되지 않는 것 같습니다. developer.mozilla.org/en-US/docs/Web/Events/beforescriptexecute
Matt Pennington 2011

8

흥미로운 질문은 가능하지 않다고 생각합니다. 하지만 그렇다고해도 해킹처럼 들립니다.

해당 div의 콘텐츠를 신뢰할 수없는 경우 HTTP 응답으로 전송되고 브라우저에서 렌더링되기 전에 서버 측에서 데이터를 이스케이프해야합니다.

<script>태그 를 제거 하고 다른 html 태그 만 허용하려면 콘텐츠에서 제거하고 나머지는 그대로 두십시오.

XSS 예방을 살펴보십시오.

https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet


7

JavaScript는 "인라인"으로 실행됩니다. 즉, DOM에 나타나는 순서대로 실행됩니다 (그렇지 않은 경우 처음 사용할 때 다른 스크립트에 정의 된 일부 변수가 표시되는지 확인할 수 없습니다. ).

그래서 이론적으로 의미 당신은 페이지의 시작 부분에서 스크립트 (즉, 첫째 가질 수있는 <script>DOM을 통해 요소) 외모와 제거 모든 <script>당신의 내부 요소와 이벤트 핸들러 <div>.

그러나 현실은 더 복잡합니다. DOM과 스크립트 로딩은 비동기 적으로 발생합니다. 즉, 브라우저는 스크립트가 그 앞에 있는 DOM 부분 (예 : 지금까지의 헤더)을 볼 수 있음을 보증합니다 . 그 이상에 대한 보장은 없습니다 (과 관련됨 document.write()). 따라서 다음 스크립트 태그가 표시되거나 표시되지 않을 수 있습니다.

onload문서 의 이벤트에 래치 하여 전체 DOM을 확보 할 수 있지만 그 당시에는 악성 코드가 이미 실행되었을 수 있습니다. 다른 스크립트가 DOM을 조작하여 거기에 스크립트를 추가하면 상황이 악화됩니다. 따라서 DOM의 모든 변경 사항도 확인해야합니다.

따라서 @cowls 솔루션 (서버에서 필터링)은 모든 상황에서 작동하도록 만들 수있는 유일한 솔루션입니다.


1

브라우저에 JavaScript 코드를 표시하려는 경우 :

JavaScript 및 HTML을 사용하면 HTML 엔터티 를 사용 하여 JavaScript 코드를 표시하고이 코드가 실행되는 것을 방지해야합니다. 여기에서 HTML 엔티티 목록을 찾을 수 있습니다.

서버 측 스크립팅 언어 (PHP, ASP.NET 등)를 사용하는 경우 문자열을 이스케이프하고 특수 문자를 HTML 엔티티로 변환하는 함수가있을 것입니다. PHP에서는 "htmlspecialchars ()"또는 "htmlentities ()"를 사용합니다. 후자는 모든 HTML 문자를 다룹니다.

JavaScript 코드를 멋지게 표시하려는 경우 코드 하이 라이터 중 하나를 사용해보십시오.


1

나는 이론이 있습니다.

  • 문서의 특정 부분을 noscript태그 안에 감습니다.
  • DOM 함수를 사용하여 script태그 내부의 모든 태그 를 삭제 noscript한 다음 해당 내용을 풉니 다.

개념 증명 예 :

window.onload = function() {
    var noscripts = /* _live_ list */ document.getElementsByTagName("noscript"),
        memorydiv = document.createElement("div"),
        scripts = /* _live_ list */ memorydiv.getElementsByTagName("script"),
        i,
        j;
    for (i = noscripts.length - 1; i >= 0; --i) {
        memorydiv.innerHTML = noscripts[i].textContent || noscripts[i].innerText;
        for (j = scripts.length - 1; j >= 0; --j) {
            memorydiv.removeChild(scripts[j]);
        }
        while (memorydiv.firstChild) {
            noscripts[i].parentNode.insertBefore(memorydiv.firstChild, noscripts[i]);
        }
        noscripts[i].parentNode.removeChild(noscripts[i]);
    }
};
body { font: medium/1.5 monospace; }
p, h1 { margin: 0; }
<h1>Sample Content</h1>
<p>1. This paragraph is embedded in HTML</p>
<script>document.write('<p style="color: red;">2. This paragraph is generated by JavaScript</p>');</script>
<p>3. This paragraph is embedded in HTML</p>
<h1>Sample Content in No-JavaScript Zone</h1>
<noscript>
    <p>1. This paragraph is embedded in HTML</p>
    <script>document.write('<p style="color: red;">2. This paragraph is generated by JavaScript</p>');</script>
    <p>3. This paragraph is embedded in HTML</p>
</noscript>
<noscript>
    <p>1. This paragraph is embedded in HTML</p>
    <script>document.write('<p style="color: red;">2. This paragraph is generated by JavaScript</p>');</script>
    <p>3. This paragraph is embedded in HTML</p>
</noscript>


div의 내용이 신뢰할 수없는 경우 질문이 주어집니다. 그들은 단지 가까이 할 수 <noscript>태그하고 그들이 무엇을 좋아 주사한다.
카울

예, 적절한 해결책은 서버 측에서 문제를 해결하는 것입니다. 자바 스크립트를 통해 내가하는 일은 서버 측에서하는 것이 더 낫습니다.
Salman A

0

나중에 스크립트 태그를 다시 활성화하려면 브라우저 환경을 중단하여 실행되는 모든 스크립트에서 오류가 상당히 일찍 발생하도록하는 것이 제 해결책이었습니다. 그러나 완전히 신뢰할 수는 없으므로 보안 기능으로 사용할 수 없습니다.

전역 속성에 액세스하려고하면 Chrome에서 예외가 발생합니다.

setTimeout("Math.random()")
// => VM116:25 Uncaught Error: JavaScript Execution Inhibited  

에서 덮어 쓸 수있는 모든 속성을 덮어 window쓰지만 다른 기능을 중단하도록 확장 할 수도 있습니다.

window.allowJSExecution = inhibitJavaScriptExecution();
function inhibitJavaScriptExecution(){

    var windowProperties = {};
    var Object = window.Object
    var console = window.console
    var Error = window.Error

    function getPropertyDescriptor(object, propertyName){
        var descriptor = Object.getOwnPropertyDescriptor(object, propertyName);
        if (!descriptor) {
            return getPropertyDescriptor(Object.getPrototypeOf(object), propertyName);
        }
        return descriptor;
    }

    for (var propName in window){
        try {
            windowProperties[propName] = getPropertyDescriptor(window, propName)
            Object.defineProperty(window, propName, {
                get: function(){
                    throw Error("JavaScript Execution Inhibited")
                },
                set: function(){
                    throw Error("JavaScript Execution Inhibited")
                },
                configurable: true
            })
        } catch (err) {}
    }

    return function allowJSExecution(){
        for (var propName in window){
            if (!(propName in windowProperties)) {
                delete windowProperties[propName]
            }
        }

        for (var propName in windowProperties){
            try {
                Object.defineProperty(window, propName, windowProperties[propName])
            } catch (err) {}
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.