หมายความว่าอย่างไรเมื่อพวกเขากล่าวว่า React ได้รับการป้องกัน XSS?


119

ฉันอ่านสิ่งนี้ในบทช่วยสอนการตอบสนอง สิ่งนี้หมายความว่า?

React มีความปลอดภัย เราไม่ได้สร้างสตริง HTML ดังนั้นการป้องกัน XSS จึงเป็นค่าเริ่มต้น

การโจมตี XSS ทำงานอย่างไรหาก React ปลอดภัย ความปลอดภัยนี้บรรลุได้อย่างไร?

คำตอบ:


194

ReactJS ค่อนข้างปลอดภัยจากการออกแบบตั้งแต่นั้นมา

  1. ตัวแปรสตริงในมุมมองจะถูกหลีกเลี่ยงโดยอัตโนมัติ
  2. ด้วย JSX คุณจะส่งผ่านฟังก์ชันเป็นตัวจัดการเหตุการณ์แทนที่จะเป็นสตริงที่อาจมีโค้ดที่เป็นอันตราย

ดังนั้นการโจมตีทั่วไปเช่นนี้จะไม่ได้ผล

const username = "<img onerror='alert(\"Hacked!\")' src='invalid-image' />";

class UserProfilePage extends React.Component {
  render() {
    return (
      <h1> Hello {username}!</h1>
    );
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

แต่ว่า ...

❗❗❗คำเตือน❗❗❗

ยังมีเวกเตอร์โจมตี XSS บางตัวที่คุณต้องจัดการด้วยตัวเองใน React!

1. XSS ผ่าน dangerouslySetInnerHTML

เมื่อคุณใช้dangerouslySetInnerHTMLคุณต้องตรวจสอบให้แน่ใจว่าเนื้อหาไม่มีจาวาสคริปต์ React ไม่สามารถทำอะไรให้คุณได้ที่นี่

const aboutUserText = "<img onerror='alert(\"Hacked!\");' src='invalid-image' />";

class AboutUserComponent extends React.Component {
  render() {
    return (
      <div dangerouslySetInnerHTML={{"__html": aboutUserText}} />
    );
  }
}

ReactDOM.render(<AboutUserComponent />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

2. XSS ผ่านแอตทริบิวต์ a.href

ตัวอย่างที่ 1: การใช้ javascript: code

คลิกที่ "Run code snippet" -> "My Website" เพื่อดูผลลัพธ์

const userWebsite = "javascript:alert('Hacked!');";

class UserProfilePage extends React.Component {
  render() {
    return (
      <a href={userWebsite}>My Website</a>
    )
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

ตัวอย่างที่ 2: การใช้ข้อมูลที่เข้ารหัส base64:

คลิกที่ "Run code snippet" -> "My Website" เพื่อดูผลลัพธ์

const userWebsite = "data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGFja2VkISIpOzwvc2NyaXB0Pg==";

class UserProfilePage extends React.Component {
  render() {
    const url = userWebsite.replace(/^(javascript\:)/, "");
    return (
      <a href={url}>My Website</a>
    )
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

3. XSS ผ่านอุปกรณ์ประกอบฉากที่ควบคุมโดยผู้โจมตี

const customPropsControledByAttacker = {
  dangerouslySetInnerHTML: {
    "__html": "<img onerror='alert(\"Hacked!\");' src='invalid-image' />"
  }
};

class Divider extends React.Component {
  render() {
    return (
      <div {...customPropsControledByAttacker} />
    );
  }
}

ReactDOM.render(<Divider />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

นี่คือแหล่งข้อมูลเพิ่มเติม


14
คำตอบนี้น่าทึ่งมาก! พร้อมตัวอย่างโค้ดและอ้างอิงท้าย ... ! ขอบคุณ!
Ioanna

ตัวอย่างใด ๆ ข้างต้นได้รับการดูแลโดย React ตั้งแต่เขียนคำตอบนี้หรือไม่? ฉันถามว่าเนื่องจากฉันอ่านในสไลด์ต่อไปนี้: slideshare.net/kseniadmitrieva/…สไลด์ # 20 อุปกรณ์ประกอบฉากที่ผู้ใช้ควบคุมซึ่งแก้ไขใน React 0.14 ในวันที่ 15 พฤศจิกายน
omer

@omer ไม่และตอบสนองตัดสินใจที่จะไม่ดูแลเวกเตอร์การโจมตีนี้ในระดับปฏิกิริยา นี่คือความคิดเห็นดีๆบางส่วนอธิบายว่าทำไมพวกเขาถึงไม่จัดการใน React level github.com/facebook/react/issues/3473 ( github.com/facebook/react/issues/3473#issuecomment-91349525 , github.com/facebook/react / issue / 3473 # issue-90594748 )
CyberPanda Consulting

1
@ เกี่ยวกับปัญหาที่คุณอ้างถึงคือข้อบกพร่องด้านความปลอดภัยและได้รับการแก้ไขแล้ว แต่จุดที่ 3 ที่ฉันระบุไว้ไม่เกี่ยวข้องกับประเด็นนั้นคุณยังสามารถตรวจสอบว่าจุดที่ 3 ทำงานได้โดยเรียกใช้รหัสของฉันภายใต้เวอร์ชันการตอบสนองใด ๆ
CyberPanda Consulting

63

React จะหลีกเลี่ยงตัวแปรให้คุณโดยอัตโนมัติ ... มันป้องกันการฉีด XSS ผ่านสตริง HTML ด้วย Javascript ที่เป็นอันตราย .. โดยปกติแล้วอินพุตจะถูกฆ่าเชื้อพร้อมกับสิ่งนี้

ตัวอย่างเช่นสมมติว่าคุณมีสตริงนี้

var htmlString = '<img src="javascript:alert('XSS!')" />';

หากคุณพยายามแสดงสตริงนี้ในการตอบสนอง

render() {
    return (
        <div>{htmlString}</div>
    );
}

คุณจะเห็นสตริงทั้งหมดในหน้าเว็บรวมทั้ง<span>แท็กองค์ประกอบ คุณจะเห็นในเบราว์เซอร์<img src="javascript:alert('XSS!')" />

หากคุณดู html ต้นทางคุณจะเห็น

<span>"<img src="javascript:alert('XSS!')" />"</span>

รายละเอียดเพิ่มเติมเกี่ยวกับการโจมตี XSS คืออะไร

การตอบสนองโดยทั่วไปทำให้คุณไม่สามารถแทรกมาร์กอัปได้เว้นแต่คุณจะสร้างองค์ประกอบด้วยตัวเองในฟังก์ชั่นการเรนเดอร์ ... ที่กล่าวกันว่ามีฟังก์ชันที่อนุญาตให้แสดงผลดังกล่าวเรียกว่าdangerouslySetInnerHTML... นี่คือรายละเอียดเพิ่มเติม


แก้ไข:

มีบางสิ่งที่ควรทราบมีหลายวิธีในการหลีกเลี่ยงสิ่งที่ React หลบหนี อีกวิธีหนึ่งคือเมื่อผู้ใช้กำหนดอุปกรณ์ประกอบฉากให้กับส่วนประกอบของคุณ อย่าขยายข้อมูลใด ๆ จากการป้อนข้อมูลของผู้ใช้เป็นอุปกรณ์ประกอบฉาก!


14
หนีทุกอย่าง? จริงๆ? การตอบสนองจะไม่ปลอดภัยโดยค่าเริ่มต้นมีหลายสิ่งที่คุณต้องทำด้วยตนเองและโจมตีเวกเตอร์ที่คุณต้องเข้าใจ React ทั้งหมดคือ Escape html เป็น string เมื่อคุณพยายามแทรกด้วย {html} แต่มีอีกหลายล้านวิธีในการอนุญาต XSS ซึ่ง React ไม่ได้ป้องกัน <a href="{...}" />, <img src = {... } />, <iframe src = "{... } /> และอุปกรณ์ประกอบฉากอื่น ๆ อีกมากมายที่อนุญาตให้ฉีดจาวาสคริปต์ที่เรียกใช้งานได้ จากนั้นก็มีการแทรกสคริปต์ CSS ผ่าน style = {... } คำตอบด้านล่างโดย @Marty Aghajanyan สรุปความเสี่ยงที่อาจเกิดขึ้นได้
andree

@andree ขอบคุณสำหรับการชี้การพิมพ์ผิดของฉัน มันเป็นโพสต์เก่า 3 ปี เห็นได้ชัดว่ามีหลายวิธีในการหลีกเลี่ยงสิ่งที่ React หลบหนีและนักพัฒนาแต่ละคนควรเบื่อหน่ายกับสิ่งนั้น
John Ruddell

ขอบคุณสำหรับการแก้ไขคำตอบของคุณ @John Ruddell ไม่มีความผิด แต่คำตอบของคุณทำให้ React ดูปลอดภัยกว่าที่เป็นจริงและเนื่องจากคำตอบของคุณเป็นคำตอบแรกที่เกิดขึ้นในหัวข้อนี้ฉันแค่อยากจะชี้ให้เห็น น่าเสียดายที่นี่เป็นเรื่องธรรมดาที่ฉันเห็นในการรักษาความปลอดภัยส่วนหน้าโดยรวม (ไม่ใช่แค่ตอบสนอง) - สิ่งต่างๆดูปลอดภัยหรือรักษาได้ง่ายบนพื้นผิว แต่เมื่อคุณขุดเข้าไปปรากฎว่ามีช่องโหว่ คำถามเพื่อความปลอดภัยขั้นพื้นฐานควรมีคำตอบที่หาได้ง่ายซึ่งสรุปไว้ที่ไหนสักแห่งน่าเสียดายที่ช่วงนี้ไม่ใช่ประสบการณ์ของฉัน
andree

เมื่อเวลาผ่านไปเอกสารจะออกมาเมื่อมีการทดสอบความปลอดภัย คำตอบที่ครั้งหนึ่งเราเคยช่วยไม่ได้มีประโยชน์ ส่วนที่ยากคือการทำให้คำตอบทั้งหมดเป็นข้อมูลล่าสุดด้วยเทคโนโลยีที่เปลี่ยนแปลง
John Ruddell
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.