DOM에 임의의 JSON을 포함하는 모범 사례?


110

다음과 같이 DOM에 임의의 JSON을 포함하는 것에 대해 생각하고 있습니다.

<script type="application/json" id="stuff">
    {
        "unicorns": "awesome",
        "abc": [1, 2, 3]
    }
</script>

이는 나중에 JavaScript 템플릿 엔진에서 사용하기 위해 임의의 HTML 템플릿을 DOM에 저장하는 방식과 유사합니다. 이 경우 나중에 JSON을 검색하고 다음과 같이 구문 분석 할 수 있습니다.

var stuff = JSON.parse(document.getElementById('stuff').innerHTML);

이것은 작동 하지만 가장 좋은 방법입니까? 이것이 모범 사례 또는 표준을 위반합니까?

참고 : DOM에 JSON을 저장하는 대안을 찾고있는 것이 아닙니다. 내가 겪고있는 특정 문제에 대한 최상의 솔루션이라고 이미 결정했습니다. 나는 그것을 할 가장 좋은 방법을 찾고 있습니다.


1
왜 당신은 그것을 var자바 스크립트 로 가지지 않습니까?
Krizz

@Krizz, 나중에 캡슐화 된 자바 스크립트의 복잡한 체인에 의해 처리되는 정적 문서의 일부 여야합니다. DOM에 저장하는 것이 제가하고 싶은 일입니다.
Ben Lee

@Krizz 비슷한 문제가 제기되었습니다. AJAX 요청을하지 않고 사용자별로 다른 사이트에 데이터를 저장하고 싶었습니다. 그래서 컨테이너에 PHP를 내장하여 자바 스크립트로 데이터를 얻기 위해 위와 비슷한 작업을 수행했습니다.
Patrick Lorio 2012

2
당신의 원래 방법이 실제로 최고라고 생각합니다. HTML5에서 100 % 유효하고 표현력이 뛰어나며 CSS로 제거하거나 숨길 "가짜"요소를 만들지 않습니다. 문자 인코딩이 필요하지 않습니다. 단점은 무엇입니까?
Jamie Treworgy 2012

22
</script><script>alert()</script><script>JSON 객체 내부 에 값이있는 문자열 이 있으면 놀라움을 금치 못할 것입니다. 데이터를 먼저 삭제하지 않으면 안전하지 않습니다.
silviot 2014

답변:


77

원래 방법이 최고라고 생각합니다. HTML5 사양은 이러한 용도를 다룹니다.

"데이터 블록 (스크립트와 반대)을 포함하는 데 사용되는 경우 데이터는 인라인으로 포함되어야하며 데이터 형식은 type 속성을 사용하여 제공되어야하며 src 속성은 지정되지 않아야하며 스크립트 요소의 내용은 사용 된 형식에 대해 정의 된 요구 사항을 준수하십시오. "

여기에서 읽으십시오 : http://dev.w3.org/html5/spec/Overview.html#the-script-element

당신은 정확히 그렇게했습니다. 사랑하지 않는 것은 무엇입니까? 속성 데이터에 필요한 문자 인코딩이 없습니다. 원하는 경우 포맷 할 수 있습니다. 표현력이 풍부하고 용도가 명확합니다. 해킹처럼 느껴지지 않습니다 (예 : "운송 업체"요소를 숨기기 위해 CSS를 사용하는 것과 같이). 완벽하게 유효합니다.


3
감사합니다. 사양의 인용문이 저를 확신 시켰습니다.
Ben Lee

17
JSON 객체를 먼저 확인하고 삭제하는 경우에만 완벽하게 유효합니다. 사용자가 생성 한 데이터를 포함 할 수는 없습니다. 질문에 대한 내 의견을 참조하십시오.
silviot 2014

1
추가 궁금증 : 그것을 넣어 좋은 장소는 무엇입니까? 머리 또는 몸, 상단 또는 하단?
challet

1
불행하게도, 나타납니다 CSP는 정책 / 모두 중지됩니다 수 script태그를.
Larry K

2
</ script>를 포함하여 HTML 삽입을 허용하는 JSON 삽입을 효과적으로 방지하는 방법은 무엇입니까? 견고하고 쉬운 것이 있습니까, 아니면 데이터 속성을 사용하는 것이 더 낫습니까?
jonasfj

23

일반적인 방향으로 HTML5 데이터 속성을 대신 사용해 보겠습니다 . 유효한 JSON을 입력하는 것을 막을 수는 없습니다. 예 :

<div id="mydiv" data-unicorns='{"unicorns":"awesome", "abc":[1,2,3]}' class="hidden"></div>

jQuery를 사용하는 경우 검색은 다음과 같이 쉽습니다.

var stuff = JSON.parse($('#mydiv').attr('data-unicorns'));

1
말이된다. 키 이름에 작은 따옴표가 있으면 JSON.parse작동하지 않습니다 (적어도 기본 Google Chrome JSON.parse는 작동하지 않습니다). JSON 사양에는 큰 따옴표가 필요합니다. 하지만 ...&lt;unicorns&gt;:....
Ben Lee

4
하지만 한 가지 질문 : HTML 5의 속성 길이에 제한이 있습니까?
Ben Lee

예, 작동합니다. HTML이 작은 따옴표를 사용하고 JSON 데이터가 큰 따옴표를 사용하도록 전환 할 수도 있습니다.
Horatio Alderaan 2012

1
좋아, 내 질문에 대한 답을 찾았습니다. stackoverflow.com/questions/1496096/…- 이것은 내 목적에 충분합니다.
Ben Lee

2
이것은 단일 문자열에 대해서는 작동하지 않습니다. 예를 들어 "I am valid JSON"태그에 큰 따옴표를 사용하거나 문자열에 작은 따옴표가있는 작은 따옴표를 사용합니다. 예를 data-unicorns='"My JSON's string"'들어 작은 따옴표는 JSON으로 인코딩으로 이스케이프되지 않기 때문입니다.
Robbie Averill

13

스크립트 태그에 json을 포함하는이 방법에는 잠재적 인 보안 문제가 있습니다. json 데이터가 사용자 입력에서 비롯된 것이라고 가정하면 실제로 스크립트 태그에서 벗어나 DOM에 직접 삽입 할 수있는 데이터 멤버를 만들 수 있습니다. 여기를 보아라:

http://jsfiddle.net/YmhZv/1/

여기 주사입니다

<script type="application/json" id="stuff">
{
    "unicorns": "awesome",
    "abc": [1, 2, 3],
    "badentry": "blah </script><div id='baddiv'>I should not exist.</div><script type="application/json" id='stuff'> ",
}
</script>

이스케이프 / 인코딩 방법은 없습니다.


7
이것은 사실이지만 실제로는 방법의 보안 결함이 아닙니다. 사용자 입력에서 비롯된 것을 페이지에 넣는 경우에는이를 피하는 데 부지런해야합니다. 이 방법은 사용자 입력에 대한 일반적인 예방 조치를 취하는 한 여전히 유효합니다.
Ben Lee

JSON은 HTML의 일부가 아니며 HTML 파서는 계속 진행됩니다. JSON이 텍스트 단락 또는 div 요소의 일부가 될 때와 동일합니다. 프로그램의 콘텐츠를 HTML로 이스케이프합니다. 또한 슬래시를 이스케이프 할 수도 있습니다. JSON은이를 필요로하지 않지만 불필요한 슬래시를 허용합니다. 삽입하기에 안전한 목적으로 그녀를 사용할 수 있습니다. PHP의 json_encode는 기본적으로이 작업을 수행합니다.
Timo Tijhof

7

OWASP의 XSS 방지 치트 시트의 규칙 # 3.1 을 참조하십시오 .

이 JSON을 HTML에 포함하고 싶다고 가정 해 보겠습니다.

{
    "html": "<script>alert(\"XSS!\");</script>"
}

<div>HTML 에서 숨김 을 만듭니다 . 다음으로, 안전하지 않은 엔티티 (예 : &, <,>, ", ', 및 /)를 인코딩하여 JSON을 이스케이프하고 요소 안에 넣습니다.

<div id="init_data" style="display:none">
        {&#34;html&#34;:&#34;&lt;script&gt;alert(\&#34;XSS!\&#34;);&lt;/script&gt;&#34;}
</div>

이제 textContentJavaScript를 사용하여 요소를 읽고 파싱하여 액세스 할 수 있습니다 .

var text = document.querySelector('#init_data').textContent;
var json = JSON.parse(text);
console.log(json); // {html: "<script>alert("XSS!");</script>"}

나는 이것이 가장 좋고 안전한 대답이라고 믿습니다. 많은 일반적인 JSON 문자가 이스케이프되고 객체의 내부 따옴표와 같은 특정 문자가 이중 이스케이프 {name: 'Dwayne "The Rock" Johnson'}됩니다. 그러나 프레임 워크 / 템플릿 라이브러리에는 HTML 인코딩을 수행하는 안전한 방법이 이미 포함되어 있기 때문에이 방법을 사용하는 것이 가장 좋습니다. 대안은 HTML 안전하고 JS 문자열 안에 넣어도 안전한 base64를 사용하는 것입니다. btoa () / atob ()를 사용하여 JS에서 쉽게 인코딩 / 디코딩 할 수 있으며 서버 측에서 수행하는 것도 쉬울 것입니다.
sstur

더 안전한 방법은 의미 상 올바른 <data>요소 를 사용 하고 value속성에 JSON 데이터를 포함하는 것입니다. 그런 다음 &quot큰 따옴표를 사용하여 데이터를 묶거나 작은 따옴표를 사용 하는 경우에만 따옴표를 이스케이프하면됩니다 &#39;(아마도 더 좋습니다).
Rúnar Berg

5

함수 콜백 (일종의 JSONP )을 사용하여 JSON을 인라인 스크립트에 넣는 것이 좋습니다 .

<script>
someCallback({
    "unicorns": "awesome",
    "abc": [1, 2, 3]
});
</script>

실행중인 스크립트가 문서 다음에로드되면 추가 식별자 인수를 사용하여 어딘가에 저장할 수 있습니다. someCallback("stuff", { ... });


@BenLee는 콜백 함수를 정의해야하는 유일한 단점을 제외하고는 매우 잘 작동합니다. 다른 제안 된 솔루션은 특수 HTML 문자 (예 : &) 및 따옴표 (JSON에 포함 된 경우)를 중단합니다.
복사

당신이 데이터를 찾기 위해 DOM 쿼리를 필요가없는 때문에 더 나은이 Feel로
Jaseem

@copy이 솔루션은 여전히 ​​이스케이프가 필요합니다 (다른 종류). MadCoder의 답변을 참조하십시오. 완전성을 위해 여기에 두십시오.
pvgoran

2

내 권장 사항은 JSON 데이터를 외부 .json파일 에 보관 한 다음 Ajax를 통해 해당 파일을 검색하는 것입니다. 웹 페이지 (인라인)에 CSS 및 JavaScript 코드를 넣지 않는데 왜 JSON으로 하시겠습니까?


12
일반적으로 다른 페이지에서 공유되기 때문에 웹 페이지에 CSS 및 Javascript를 삽입하지 않습니다. 문제의 데이터가이 컨텍스트에 대해 명시 적으로 서버에 의해 생성 된 경우이를 포함하는 것이 캐시 할 수없는 다른 요청을 시작하는 것보다 훨씬 효율적입니다.
Jamie Treworgy 2012

잘못 설계된 레거시 시스템을 업데이트하고 전체 시스템을 재 설계하는 대신 한 부분 만 수정하면되기 때문입니다. DOM에 JSON을 저장하는 것이이 부분을 수정하는 가장 좋은 방법입니다. 또한 @jamietre가 말한 것에 동의합니다.
Ben Lee

@jamietre OP는이 JSON 문자열이 나중에 만 필요하다고 명시했습니다 . 문제는 항상 필요한지 아니면 일부 경우에만 필요한지입니다. 일부 경우에만 필요한 경우 외부 파일에 저장하고 조건부로만로드하는 것이 좋습니다.
Šime Vidas 2012

2
나는 저울을 한 방향 또는 다른 방향으로 기울일 수있는 많은 "만약"이 있다는 데 동의합니다. 그러나 일반적으로 페이지가 렌더링 될 때 필요한 것을 안다면 일반적으로 말하면-가능하더라도-즉시 전송하는 것이 좋습니다. 예를 들어, 접 히기 시작하는 정보 상자가있는 경우 일반적으로 내용을 인라인으로 포함하여 즉시 확장하고 싶습니다. 새 요청의 오버 헤드는 기존 요청에 대한 약간의 추가 데이터 오버 헤드에 비해 훨씬 많으며 응답 성이 뛰어난 사용자 경험을 생성합니다. 브레이크 포인트가 있다고 확신합니다.
Jamie Treworgy 2012

2

HTML5에는 기계가 읽을 수있는 데이터를 유지하기위한 <data>요소 가 포함되어 있습니다. 더 안전한 방법 으로 해당 요소 <script type="application/json">value속성 내에 JSON 데이터를 포함 할 수 있습니다 .

const jsonData = document.querySelector('.json-data');
const data = JSON.parse(jsonData.value);

console.log(data)
<data class="json-data" value='
  {
    "unicorns": "awesome",
    "abc": [1, 2, 3],
    "careful": "to escape &#39; quotes"
  }
'></data>

이 경우 값을 큰 따옴표로 묶으려면 모든 작은 따옴표를 &#39;또는 로 바꿔야 &quot;합니다. 그렇지 않으면 다른 답변과 같은 위험 XSS 공격이 제안했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.