wake-up-neo.com

Definieren Sie den CSP-HTTP-Header in der Electron App

Nach der API-Dokumentation verstehe ich nicht, wie ein Content-Security-Policy-HTTP-Header für den Renderer meiner Electron-Anwendung definiert wird. Ich bekomme immer eine Warnung in den DevTools.

Ich habe es versucht:

1) Kopieren/fügen Sie den Code blind in das API-Dokument ein:

app.on('ready', () => {
    const {session} = require('electron')
    session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
        callback({responseHeaders: `default-src 'self'`})
    })

    win = new BrowserWindow(...)
    win.loadUrl(...)
}

(Ich verstehe übrigens nicht, warum "Content-Security-Policy:" in der Zeichenfolge fehlt. Durch das Hinzufügen wird jedoch nichts geändert.)

2) Ändern der Sitzung des Renderers mit demselben Code:

win = new BrowserWindow(...)
win.loadUrl(...)

const ses = win.webContents.session;
ses.webRequest.onHeadersReceived((details, callback) => {
  callback({responseHeaders: `default-src 'self'`})
})

3) Fügen Sie dem Renderer einen zusätzlichen Header hinzu:

win = new BrowserWindow(...)
win.loadURL(`file://${__dirname}/renderer.html`,{
    extraHeaders: `Content-Security-Policy: default-src 'self'`
});

...

Das einzige, was funktioniert, ist die Verwendung eines Meta-Tags in der Renderer-HTML-Datei:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'>
19
Anozer

Nicht sicher, warum die Dokumentation diesen fehlerhaften Code enthält. Es hat mich total verwirrt, aber ich habe durch Versuch und Irrtum eine funktionierende Lösung gefunden:

session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
    callback({ responseHeaders: Object.assign({
        "Content-Security-Policy": [ "default-src 'self'" ]
    }, details.responseHeaders)});
});

Das Argument headers muss also ein Objekt mit der gleichen Struktur wie die in details.responseHeaders erhaltenen ursprünglichen Header sein. Die ursprünglichen Header müssen ebenfalls in dem übergebenen Objekt enthalten sein, da dieses Objekt die ursprünglichen Antwort-Header vollständig zu ersetzen scheint.

Die Option extraHeaders ist nicht für Antwortheader vorgesehen. Es ist für Anforderungsheader, die an den Server gesendet werden.

7
kayahr

Ihre Frage enthält nicht genügend Details, um festzustellen, ob beim erstmaligen Laden oder bei nachfolgenden Webanforderungen Probleme aufgetreten sind. Mein Problem bestand jedoch beim erstmaligen Laden der Datei. Mit einer Electron-App, die React verwendet, erhielt ich Warnungen bezüglich der Verwendung von Inline-Skripten, selbst mit Kayahrs Code. Dies liegt daran, dass die onHeadersReceived-Methode nur Anforderungen abfängt, die nach dem ersten Laden der Anwendung eingehen. Es werden keine Warnungen beim erstmaligen Laden der Anwendung gestoppt.

Während der Erstellung meiner Anwendung musste ich Templating verwenden, um dem Inline-Skript und -Stil sowie dem CSP-Header in der HTML-Datei, die die Anwendung anfänglich lädt, ein Nonce hinzuzufügen.

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-<%= scriptNonce %>'; style-src 'nonce-<%= styleNonce %>';">
    <link rel="stylesheet" type="text/css" href="./index.css" nonce=<%= styleNonce %>>
    <title>Basic Electron App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="application/javascript" nonce=<%= scriptNonce %>>
      require('./index.js');
    </script>
  </body>
</html>

index.css

body {
  margin: 0px;
}

.hello {
  font-family: "Century Gothic";
  width: 800px;
  margin: 70px auto;
  text-align: center;
}

fügen Sie in gulfile.js Folgendes zu dem hinzu, was Sie bereits haben, und stellen Sie sicher, dass diese Aufgabe in Ihrer Pipeline enthalten ist. Sie können auch einfach Ihre aktuelle HTML-Aufgabe mit dem folgenden Code aktualisieren.

const template = require('gulp-template');
const uuidv4 = require('uuid/v4');

gulp.task('copy-html', () => {
  // Create nonces during the build and pass them to the template for use with inline scripts and styles
  const nonceData = {
    scriptNonce: new Buffer(uuidv4()).toString('base64'),
    styleNonce: new Buffer(uuidv4()).toString('base64')
  };
  return gulp.src('src/*.html')
  .pipe(template(nonceData))
  .pipe(gulp.dest('dist/'));
});

Dies ist ein sehr einfaches Beispiel. Ich habe ein vollständigeres Beispiel unter https://github.com/NFabrizio/data-entry-electron-app wenn jemand interessiert ist, obwohl es immer noch eine Warnung gibt, wenn die Anwendung ausgeführt wird, weil eine der Pakete, die ich verwende, verwenden pulls in react-beautiful-dnd, das Inline-Stile hinzufügt, aber derzeit keine Nonces akzeptiert.

0
NFab

Wenn Sie CSP sowohl im dev-Modus (mit vom http://-Protokoll geladenen Ressourcen) als auch im prod-Modus (file://-Protokoll) verwenden möchten, können Sie Folgendes tun:

Entfernen Sie zunächst das Content-Security-Policy-Meta aus src/index.html - wir müssen es nur für den Prod-Modus einfügen, da 

  • onHeadersReceived funktioniert nicht für das file://-Protokoll als Electron docs confirm und auch weil 
  • wenn wir es im src/index.html für den Dev-Modus beibehalten, wird die onHeadersReceived zumindest für einen Teil der Ressourcen überschrieben. Für den Dev-Modus benötigen wir andere Einstellungen.

Dann können wir es mit gulp-inject für den Prod-Modus injizieren:

// in project dir
npm install --save-dev gulp-inject gulp
// src/index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <base href="">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- inject:prod-headers -->
  <!-- src/prod-headers.html content will be injected here -->
  <!-- endinject -->
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
</body>
</html>

// src/prod-headers.html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'>
// gulpfile.js
var gulp = require('gulp');
var inject = require('gulp-inject');

gulp.task('insert-prod-headers', function () {
  return gulp.src('./dist/index.html')
    .pipe(inject(gulp.src('./src/prod-headers.html'), {
      starttag: '<!-- inject:prod-headers -->',
      transform: function (filePath, file) {
        // return file contents as string
        return file.contents.toString('utf8')
      }
    }))
    .pipe(gulp.dest('./dist'));
});

Stellen Sie dann sicher, dass npx gulp insert-prod-headers nach z. ng build generiert dist/index.html.

Und für den Dev-Modus verwenden wir onHeadersReceived ähnlich wie Electron docs example :

const args = process.argv.slice(1);
const devMode = args.some((val) => val === '--serve');
app.on('ready', () => {
    if (devMode) {
      const {session} = require('electron')
      session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
        callback({responseHeaders: `default-src http: ws:`})
      })
    }

    win = new BrowserWindow(...)
    win.loadUrl(...)
}

Diese Lösung wurde an Electron 4.0.3 getestet.

0
Artem Vasiliev

Wie in den Electron-Dokumenten erwähnt, müssen Sie beim Laden Ihres _renderer.html_ über _file://_ Schema (IIRC machen Sie das im obigen Beispiel).

Wenn Sie die Inhaltssicherheitsrichtlinie unter bestimmten Bedingungen für die Prod- und Dev-Umgebung anpassen möchten, können Sie diese Zeichenfolge in Ihrem Erstellungsschritt dynamisch im HTML-Code generieren. Ich schlage vor, eine Template-Engine wie _mustache.js_ (im Beispiel verwendet) zu verwenden.

Beispiel (Dateiressourcen)

In meinem Fall wollte ich Hot Module Replacement (HMR) über Websockets und _file://_ -Ressourcen im Dev-Modus aktivieren, wodurch die CSP-Regeln gelockert werden mussten (jedoch nur in dev!).

index.mustache:

_<html>
  <head>
    <meta
      http-equiv="Content-Security-Policy"
      content="{{{cspContent}}}"
    />
  </head>
...
_

cspContent.json für dev:

_{
  "cspContent": "default-src 'self'; connect-src 'self' ws:"
}
_

build-Schritt in dev (für Prod können Standardwerte verwendet werden):

_npx mustache cspContent.json index.mustache > index.html
_

URL-Ressourcen

Für die Verwendung mit URL-Ressourcen können Sie sich an dieses Beispiel halten :

_const { session } = require('electron')

session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
  callback({
    responseHeaders: {
      ...details.responseHeaders,
      'Content-Security-Policy': ['default-src \'none\'']
    }
  })
})
_

Stellen Sie sicher, dass Ihre benutzerdefinierten CSP-Antwortheader mit den Standardheader zusammengeführt werden - das tun Sie in Ihrem oben eingefügten Beispiel nicht. Hier können Sie auch bedingt nach der Umgebung suchen.

Ich hoffe es hilft.

0
ford04