ฉันหวังว่าคำตอบนี้จะได้รับความสนใจเนื่องจากคำตอบส่วนใหญ่ที่นี่ทำให้เกิดช่องโหว่ด้านความปลอดภัยขนาดใหญ่ในแอปอิเล็กตรอนของคุณ อันที่จริงคำตอบนี้คือสิ่งที่คุณควรทำเพื่อใช้require()
ในแอปอิเล็กตรอนของคุณ (มีเพียงอิเล็กตรอน API ใหม่ที่ทำให้สะอาดขึ้นเล็กน้อยใน v7)
ฉันเขียนคำอธิบายโดยละเอียด / วิธีแก้ปัญหาใน github โดยใช้อิเลคตรอนที่เป็นปัจจุบันที่สุดว่าคุณสามารถทำrequire()
อะไรได้บ้าง แต่ฉันจะอธิบายสั้น ๆ ที่นี่ว่าทำไมคุณควรทำตามวิธีการโดยใช้สคริปต์พรีโหลดบริบทแบริดจ์และ ipc
ปัญหา
แอพ Electron นั้นยอดเยี่ยมเพราะเราใช้งาน node ได้ แต่พลังนี้เป็นดาบสองคม หากเราไม่ระมัดระวังเราจะให้ใครบางคนเข้าถึงโหนดผ่านแอพของเราและด้วยโหนดนักแสดงที่ไม่ดีสามารถทำให้เครื่องของคุณเสียหายหรือลบไฟล์ระบบปฏิบัติการของคุณได้ (ฉันคิดว่า)
ตามที่ @raddevus นำเสนอในความคิดเห็นสิ่งนี้จำเป็นเมื่อโหลดเนื้อหาระยะไกล หากแอปอิเล็กตรอนของคุณมีทั้งแบบออฟไลน์ / ท้องถิ่นnodeIntegration:true
แล้วคุณอาจจะไม่เป็นไรเพียงแค่เปิด อย่างไรก็ตามฉันยังคงเลือกที่nodeIntegration:false
จะรักษาการป้องกันผู้ใช้ที่ไม่ได้ตั้งใจ / เป็นอันตรายที่ใช้แอปของคุณและป้องกันมัลแวร์ที่อาจติดตั้งในเครื่องของคุณจากการโต้ตอบกับแอปอิเล็กตรอนของคุณและใช้nodeIntegration:true
เวกเตอร์การโจมตี (หายากอย่างไม่น่าเชื่อ แต่อาจเกิดขึ้นได้)!
ปัญหามีลักษณะอย่างไร
ปัญหานี้ปรากฏขึ้นเมื่อคุณ (ข้อใดข้อหนึ่งด้านล่าง):
- ได้
nodeIntegration:true
เปิดใช้งาน
- ใช้
remote
โมดูล
ปัญหาทั้งหมดนี้ทำให้สามารถเข้าถึงโหนดจากกระบวนการแสดงผลของคุณได้อย่างต่อเนื่อง หากกระบวนการแสดงภาพของคุณถูกแย่งชิงคุณสามารถพิจารณาว่าทั้งหมดสูญหาย
ทางออกของเราคืออะไร
วิธีแก้ปัญหาคืออย่าให้ตัวแสดงการเข้าถึงโหนดโดยตรง (กล่าวคือrequire()
) แต่เพื่อให้กระบวนการหลักของอิเล็กตรอนของเราสามารถเข้าถึงได้require
และเมื่อใดก็ตามที่กระบวนการเรนเดอร์ของเราจำเป็นต้องใช้require
ให้ยื่นคำร้องขอไปยังกระบวนการหลัก
วิธีนี้ทำงานใน Electron เวอร์ชันล่าสุด (7+) อยู่ที่ด้าน renderer ที่เราตั้งค่าการเชื่อมipcRendererและที่ด้านหลักเราตั้งค่าการเชื่อมipcMain ในการผูก ipcMain require()
เราตั้งค่าวิธีการฟังที่ใช้โมดูลเรา นี่เป็นเรื่องปกติและดีเพราะกระบวนการหลักของเราสามารถทำได้require
ทุกอย่าง
เราใช้contextBridgeเพื่อส่งการเชื่อมโยง ipcRenderer ไปยังรหัสแอปของเรา (เพื่อใช้งาน) ดังนั้นเมื่อแอปของเราจำเป็นต้องใช้require
โมดูล d เป็นหลักแอปจะส่งข้อความผ่าน IPC (การสื่อสารระหว่างกระบวนการ) และกระบวนการหลักจะทำงาน รหัสบางส่วนจากนั้นเราจะส่งข้อความกลับไปพร้อมกับผลลัพธ์ของเรา
คร่าวๆนี่คือสิ่งที่คุณต้องการทำ
main.js
const {
app,
BrowserWindow,
ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");
let win;
async function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, "preload.js")
}
});
win.loadFile(path.join(__dirname, "dist/index.html"));
}
app.on("ready", createWindow);
ipcMain.on("toMain", (event, args) => {
fs.readFile("path/to/file", (error, data) => {
win.webContents.send("fromMain", responseObj);
});
});
preload.js
const {
contextBridge,
ipcRenderer
} = require("electron");
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);
index.html
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8"/>
<title>Title</title>
</head>
<body>
<script>
window.api.receive("fromMain", (data) => {
console.log(`Received ${data} from main process`);
});
window.api.send("toMain", "some data");
</script>
</body>
</html>
ข้อจำกัดความรับผิดชอบ
ฉันเป็นผู้secure-electron-template
สร้างเทมเพลตที่ปลอดภัยในการสร้างแอปอิเล็กตรอน ฉันสนใจหัวข้อนี้และได้ดำเนินการเรื่องนี้มาสองสามสัปดาห์แล้ว (ณ เวลานี้)