security(H1): add Content Security Policy
Add CSP in two layers: 1. Meta tag in index.html (works for all builds) 2. HTTP header via Electron session API (defense-in-depth) Policy: script-src 'self' blocks XSS from loading external scripts or executing inline scripts. style-src allows 'unsafe-inline' for Vue's style injection. connect-src allows ws/wss/http/https for configurable relay and API endpoints. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1e3de32c51
commit
1ac50b6add
2 changed files with 27 additions and 1 deletions
|
|
@ -6,7 +6,7 @@
|
||||||
* HAL hardware drivers run here (Node.js environment).
|
* HAL hardware drivers run here (Node.js environment).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
import { app, BrowserWindow, ipcMain, session } from 'electron'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
@ -280,6 +280,18 @@ ipcMain.handle('hal:cleanup', async () => {
|
||||||
|
|
||||||
// App lifecycle
|
// App lifecycle
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
|
// Enforce Content Security Policy via HTTP headers (defense-in-depth alongside meta tag)
|
||||||
|
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
||||||
|
callback({
|
||||||
|
responseHeaders: {
|
||||||
|
...details.responseHeaders,
|
||||||
|
'Content-Security-Policy': [
|
||||||
|
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: http: https:; img-src 'self' data: blob:; font-src 'self'; frame-src 'none'; object-src 'none'",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
initDatabase()
|
initDatabase()
|
||||||
|
|
||||||
// Seed cassettes from env/preset if DB table is empty.
|
// Seed cassettes from env/preset if DB table is empty.
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,20 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
||||||
|
<!--
|
||||||
|
Content Security Policy:
|
||||||
|
- script-src 'self': only our own bundled scripts, no inline/eval (XSS protection)
|
||||||
|
- style-src 'self' 'unsafe-inline': Vue injects styles inline
|
||||||
|
- connect-src: WebSocket for Nostr relay, HTTPS for Lightning.Pub and exchange rate APIs
|
||||||
|
- img-src 'self' data: blob:: QR codes use data URIs
|
||||||
|
- default-src 'self': deny everything not explicitly allowed
|
||||||
|
- frame-src 'none': no iframes
|
||||||
|
- object-src 'none': no plugins
|
||||||
|
-->
|
||||||
|
<meta
|
||||||
|
http-equiv="Content-Security-Policy"
|
||||||
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: http: https:; img-src 'self' data: blob:; font-src 'self'; frame-src 'none'; object-src 'none'"
|
||||||
|
/>
|
||||||
<title>Lamassu ATM</title>
|
<title>Lamassu ATM</title>
|
||||||
<style>
|
<style>
|
||||||
/* Prevent text selection and context menu on kiosk */
|
/* Prevent text selection and context menu on kiosk */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue