www/nginx: CSP and other headers, allow running webserver sockets safely

This commit is contained in:
Fabian Franz BSc 2018-08-13 20:39:10 +02:00 committed by GitHub
parent 4c63e92dcd
commit b3d0d01bc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1067 additions and 7 deletions

View file

@ -1,8 +1,7 @@
PLUGIN_NAME= nginx
PLUGIN_VERSION= 0.4
PLUGIN_VERSION= 1.1
PLUGIN_COMMENT= Nginx HTTP server and reverse proxy
PLUGIN_DEPENDS= nginx
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
PLUGIN_DEVEL= yes
.include "../../Mk/plugins.mk"

View file

@ -278,4 +278,31 @@ class SettingsController extends ApiMutableModelControllerBase
{
return $this->setBase('httprewrite', 'http_rewrite', $uuid);
}
// http security headers
public function searchsecurity_headerAction()
{
return $this->searchBase('security_header', array('description'));
}
public function getsecurity_headerAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('security_header', 'security_header', $uuid);
}
public function addsecurity_headerAction()
{
return $this->addBase('security_header', 'security_header');
}
public function delsecurity_headerAction($uuid)
{
return $this->delBase('security_header', $uuid);
}
public function setsecurity_headerAction($uuid)
{
return $this->setBase('security_header', 'security_header', $uuid);
}
}

View file

@ -49,6 +49,7 @@ class IndexController extends \OPNsense\Base\IndexController
$this->view->httprewrite = $this->getForm("httprewrite");
$this->view->naxsi_rule = $this->getForm("naxsi_rule");
$this->view->naxsi_custom_policy = $this->getForm("naxsi_custom_policy");
$this->view->security_headers = $this->getForm("security_headers");
$this->view->pick('OPNsense/Nginx/index');
}
}

View file

@ -89,4 +89,9 @@
<type>checkbox</type>
<help>Allow the daemon to use the sendfile function.</help>
</field>
<field>
<id>httpserver.security_header</id>
<label>Security Header</label>
<type>dropdown</type>
</field>
</form>

View file

@ -0,0 +1,547 @@
<form>
<field>
<id>security_header.description</id>
<label>Description</label>
<type>text</type>
<help>This is only for your reference.</help>
</field>
<field>
<id>security_header.referrer</id>
<label>Referrer</label>
<style>selectpicker</style>
<type>dropdown</type>
<help><![CDATA[
<ul>
<li>Same Origin: The header will be sent if you stay on the same server using the same protocol (no data leak)</li>
<li>No Referrer When Downgrade: Prevents sending a referrer when switching from HTTPS to HTTP</li>
<li>Origin, Strict-Origin: Always send the header but no path or query information. Strict Origin additionally suppressed the header on downgrades.</li>
<li>(Strict) Origin When Cross Origin: Full Referrer on the same origin, and like (Strict) Origin when cross domain.</li>
<li>Unsafe URL: Sends the full URL to all pages</li>
</ul> ]]></help>
</field>
<field>
<id>security_header.xssprotection</id>
<label>XSS Protection</label>
<style>selectpicker</style>
<type>dropdown</type>
<help><![CDATA[
<ul>
<li>Block: The browser should block the response</li>
<li>Off: Allow Anything</li>
<li>On: The Browser decides how to handle it.</li>
</ul> ]]></help>
</field>
<field>
<id>security_header.content_type_options</id>
<label>Don't Sniff Content Type</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.strict_transport_security_time</id>
<label>Strict Transport Security: Time</label>
<type>text</type>
<help>A time in seconds in which the transport security (TLS) should be enforced.</help>
</field>
<field>
<id>security_header.strict_transport_security_include_subdomains</id>
<label>Strict Transport Security: Include Subdomains</label>
<type>checkbox</type>
<help>If checked, also subdomains are affected.</help>
</field>
<field>
<id>security_header.hpkp_keys</id>
<label>HTTP Public Key Pinning: Fingerprints</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<help><![CDATA[ Enter a comma separated list of public key fingerprints here.
You can find some documentetion about this feature in the
<a href="https://developer.mozilla.org/de/docs/Web/Security/Public_Key_Pinning">Mozilla Wiki</a>.
It is not recommended to use this feature with short lived certificates.]]></help>
</field>
<field>
<id>security_header.hpkp_report_only</id>
<label>HTTP Public Key Pinning: Report Only</label>
<type>checkbox</type>
<help>If you only want to test it, you can check this box (policy will be deployed but not enforced).</help>
</field>
<field>
<id>security_header.hpkp_time</id>
<label>HTTP Public Key Pinning: Max Age</label>
<type>text</type>
</field>
<field>
<id>security_header.hpkp_include_subdomains</id>
<label>HTTP Public Key Pinning: Include Subdomains</label>
<type>checkbox</type>
<help>If checked, also subdomains are affected.</help>
</field>
<field>
<id>security_header.enable_csp</id>
<label>Content Security Policy: Enable</label>
<type>checkbox</type>
<help>If checked, the CSP is enabled.</help>
</field>
<field>
<type>header</type>
<label>Content Security Policy: Default Source</label>
</field>
<field>
<id>security_header.csp_default_src_enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>If checked, this part of the CSP is enabled.</help>
</field>
<field>
<id>security_header.csp_default_src_data_urls</id>
<label>Enable Data URLs</label>
<help>Data URLs are used to embed files into HTML (for example images written directly into the src attribute).</help>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_default_src_http_urls</id>
<label>Enable HTTP(S) URLs</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help>Allow loading files over HTTP(S) allows downloading of content over other domains or CDNs.
You can use wildcards here like https://*.exmaple.com.</help>
</field>
<field>
<id>security_header.csp_default_src_inline</id>
<label>Enable Inline Scripting</label>
<type>checkbox</type>
<help>Checking this directive allows to use scripts or styles directly embedded in in the HTML content.
Examples are the script and the style tags.</help>
</field>
<field>
<id>security_header.csp_default_src_eval</id>
<label>Enable Eval</label>
<type>checkbox</type>
<help>Checking this box allows functions like eval or createFunction in JS, or style attributes for CSS.</help>
</field>
<field>
<id>security_header.csp_default_src_self</id>
<label>Enable Same Origin (recommended)</label>
<type>checkbox</type>
<help>Allows everything from the same site (path can differ, but host, protocol and port need to be the same).</help>
</field>
<field>
<id>security_header.csp_default_src_blob</id>
<label>Enable Blobs</label>
<type>checkbox</type>
<help>Allows to use blobs as a data source. This usually is content, which is somehow generated in JavaScript.</help>
</field>
<field>
<id>security_header.csp_default_src_mediastream</id>
<label>Enable Media Streams</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_default_src_filesystem</id>
<label>Enable File System URLs</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_default_src_none</id>
<label>Forbid Explicitly</label>
<type>checkbox</type>
<help>If this checkbox is checked, all other settings for this directive are ignored and everything will be forbidden.</help>
</field>
<field>
<type>header</type>
<label>Content Security Policy: Script Source</label>
</field>
<field>
<id>security_header.csp_script_src_enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>If checked, this part of the CSP is enabled.</help>
</field>
<field>
<id>security_header.csp_script_src_data_urls</id>
<label>Enable Data URLs</label>
<help>Data URLs are used to embed files into HTML (for example images written directly into the src attribute).</help>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_script_src_http_urls</id>
<label>Enable HTTP(S) URLs</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help>Allow loading files over HTTP(S) allows downloading of content over other domains or CDNs.
You can use wildcards here like https://*.exmaple.com.</help>
</field>
<field>
<id>security_header.csp_script_src_inline</id>
<label>Enable Inline Scripting</label>
<type>checkbox</type>
<help>Checking this directive allows to use scripts or styles directly embedded in in the HTML content.
Examples are the script and the style tags.</help>
</field>
<field>
<id>security_header.csp_script_src_eval</id>
<label>Enable Eval</label>
<type>checkbox</type>
<help>Checking this box allows functions like eval or createFunction in JS, or style attributes for CSS.</help>
</field>
<field>
<id>security_header.csp_script_src_self</id>
<label>Enable Same Origin (recommended)</label>
<type>checkbox</type>
<help>Allows everything from the same site (path can differ, but host, protocol and port need to be the same).</help>
</field>
<field>
<id>security_header.csp_script_src_blob</id>
<label>Enable Blobs</label>
<type>checkbox</type>
<help>Allows to use blobs as a data source. This usually is content, which is somehow generated in JavaScript.</help>
</field>
<field>
<id>security_header.csp_script_src_mediastream</id>
<label>Enable Media Streams</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_script_src_filesystem</id>
<label>Enable File System URLs</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_script_src_none</id>
<label>Forbid Explicitly</label>
<type>checkbox</type>
<help>If this checkbox is checked, all other settings for this directive are ignored and everything will be forbidden.</help>
</field>
<field>
<type>header</type>
<label>Content Security Policy: Image Source</label>
</field>
<field>
<id>security_header.csp_img_src_enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>If checked, this part of the CSP is enabled.</help>
</field>
<field>
<id>security_header.csp_img_src_data_urls</id>
<label>Enable Data URLs</label>
<help>Data URLs are used to embed files into HTML (for example images written directly into the src attribute).</help>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_img_src_http_urls</id>
<label>Enable HTTP(S) URLs</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help>Allow loading files over HTTP(S) allows downloading of content over other domains or CDNs.
You can use wildcards here like https://*.exmaple.com.</help>
</field>
<field>
<id>security_header.csp_img_src_inline</id>
<label>Enable Inline Scripting</label>
<type>checkbox</type>
<help>Checking this directive allows to use scripts or styles directly embedded in in the HTML content.
Examples are the script and the style tags.</help>
</field>
<field>
<id>security_header.csp_img_src_eval</id>
<label>Enable Eval</label>
<type>checkbox</type>
<help>Checking this box allows functions like eval or createFunction in JS, or style attributes for CSS.</help>
</field>
<field>
<id>security_header.csp_img_src_self</id>
<label>Enable Same Origin (recommended)</label>
<type>checkbox</type>
<help>Allows everything from the same site (path can differ, but host, protocol and port need to be the same).</help>
</field>
<field>
<id>security_header.csp_img_src_blob</id>
<label>Enable Blobs</label>
<type>checkbox</type>
<help>Allows to use blobs as a data source. This usually is content, which is somehow generated in JavaScript.</help>
</field>
<field>
<id>security_header.csp_img_src_mediastream</id>
<label>Enable Media Streams</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_img_src_filesystem</id>
<label>Enable File System URLs</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_img_src_none</id>
<label>Forbid Explicitly</label>
<type>checkbox</type>
<help>If this checkbox is checked, all other settings for this directive are ignored and everything will be forbidden.</help>
</field>
<field>
<type>header</type>
<label>Content Security Policy: Stylesheet Source</label>
</field>
<field>
<id>security_header.csp_style_src_enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>If checked, this part of the CSP is enabled.</help>
</field>
<field>
<id>security_header.csp_style_src_data_urls</id>
<label>Enable Data URLs</label>
<help>Data URLs are used to embed files into HTML (for example images written directly into the src attribute).</help>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_style_src_http_urls</id>
<label>Enable HTTP(S) URLs</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help>Allow loading files over HTTP(S) allows downloading of content over other domains or CDNs.
You can use wildcards here like https://*.exmaple.com.</help>
</field>
<field>
<id>security_header.csp_style_src_inline</id>
<label>Enable Inline Scripting</label>
<type>checkbox</type>
<help>Checking this directive allows to use scripts or styles directly embedded in in the HTML content.
Examples are the script and the style tags.</help>
</field>
<field>
<id>security_header.csp_style_src_eval</id>
<label>Enable Eval</label>
<type>checkbox</type>
<help>Checking this box allows functions like eval or createFunction in JS, or style attributes for CSS.</help>
</field>
<field>
<id>security_header.csp_style_src_self</id>
<label>Enable Same Origin (recommended)</label>
<type>checkbox</type>
<help>Allows everything from the same site (path can differ, but host, protocol and port need to be the same).</help>
</field>
<field>
<id>security_header.csp_style_src_blob</id>
<label>Enable Blobs</label>
<type>checkbox</type>
<help>Allows to use blobs as a data source. This usually is content, which is somehow generated in JavaScript.</help>
</field>
<field>
<id>security_header.csp_style_src_mediastream</id>
<label>Enable Media Streams</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_style_src_filesystem</id>
<label>Enable File System URLs</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_style_src_none</id>
<label>Forbid Explicitly</label>
<type>checkbox</type>
<help>If this checkbox is checked, all other settings for this directive are ignored and everything will be forbidden.</help>
</field>
<field>
<type>header</type>
<label>Content Security Policy: Media Source</label>
</field>
<field>
<id>security_header.csp_media_src_enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>If checked, this part of the CSP is enabled.</help>
</field>
<field>
<id>security_header.csp_media_src_data_urls</id>
<label>Enable Data URLs</label>
<help>Data URLs are used to embed files into HTML (for example images written directly into the src attribute).</help>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_media_src_http_urls</id>
<label>Enable HTTP(S) URLs</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help>Allow loading files over HTTP(S) allows downloading of content over other domains or CDNs.
You can use wildcards here like https://*.exmaple.com.</help>
</field>
<field>
<id>security_header.csp_media_src_inline</id>
<label>Enable Inline Scripting</label>
<type>checkbox</type>
<help>Checking this directive allows to use scripts or styles directly embedded in in the HTML content.
Examples are the script and the style tags.</help>
</field>
<field>
<id>security_header.csp_media_src_eval</id>
<label>Enable Eval</label>
<type>checkbox</type>
<help>Checking this box allows functions like eval or createFunction in JS, or style attributes for CSS.</help>
</field>
<field>
<id>security_header.csp_media_src_self</id>
<label>Enable Same Origin (recommended)</label>
<type>checkbox</type>
<help>Allows everything from the same site (path can differ, but host, protocol and port need to be the same).</help>
</field>
<field>
<id>security_header.csp_media_src_blob</id>
<label>Enable Blobs</label>
<type>checkbox</type>
<help>Allows to use blobs as a data source. This usually is content, which is somehow generated in JavaScript.</help>
</field>
<field>
<id>security_header.csp_media_src_mediastream</id>
<label>Enable Media Streams</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_media_src_filesystem</id>
<label>Enable File System URLs</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_media_src_none</id>
<label>Forbid Explicitly</label>
<type>checkbox</type>
<help>If this checkbox is checked, all other settings for this directive are ignored and everything will be forbidden.</help>
</field>
<field>
<type>header</type>
<label>Content Security Policy: Font Source</label>
</field>
<field>
<id>security_header.csp_font_src_enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>If checked, this part of the CSP is enabled.</help>
</field>
<field>
<id>security_header.csp_font_src_data_urls</id>
<label>Enable Data URLs</label>
<help>Data URLs are used to embed files into HTML (for example images written directly into the src attribute).</help>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_font_src_http_urls</id>
<label>Enable HTTP(S) URLs</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help>Allow loading files over HTTP(S) allows downloading of content over other domains or CDNs.
You can use wildcards here like https://*.exmaple.com.</help>
</field>
<field>
<id>security_header.csp_font_src_inline</id>
<label>Enable Inline Scripting</label>
<type>checkbox</type>
<help>Checking this directive allows to use scripts or styles directly embedded in in the HTML content.
Examples are the script and the style tags.</help>
</field>
<field>
<id>security_header.csp_font_src_eval</id>
<label>Enable Eval</label>
<type>checkbox</type>
<help>Checking this box allows functions like eval or createFunction in JS, or style attributes for CSS.</help>
</field>
<field>
<id>security_header.csp_font_src_self</id>
<label>Enable Same Origin (recommended)</label>
<type>checkbox</type>
<help>Allows everything from the same site (path can differ, but host, protocol and port need to be the same).</help>
</field>
<field>
<id>security_header.csp_font_src_blob</id>
<label>Enable Blobs</label>
<type>checkbox</type>
<help>Allows to use blobs as a data source. This usually is content, which is somehow generated in JavaScript.</help>
</field>
<field>
<id>security_header.csp_font_src_mediastream</id>
<label>Enable Media Streams</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_font_src_filesystem</id>
<label>Enable File System URLs</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_font_src_none</id>
<label>Forbid Explicitly</label>
<type>checkbox</type>
<help>If this checkbox is checked, all other settings for this directive are ignored and everything will be forbidden.</help>
</field>
<field>
<type>header</type>
<label>Content Security Policy: Form Action</label>
</field>
<field>
<id>security_header.csp_form_action_enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>If checked, this part of the CSP is enabled.</help>
</field>
<field>
<id>security_header.csp_form_action_data_urls</id>
<label>Enable Data URLs</label>
<help>Data URLs are used to embed files into HTML (for example images written directly into the src attribute).</help>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_form_action_http_urls</id>
<label>Enable HTTP(S) URLs</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help>Allow loading files over HTTP(S) allows downloading of content over other domains or CDNs.
You can use wildcards here like https://*.exmaple.com.</help>
</field>
<field>
<id>security_header.csp_form_action_inline</id>
<label>Enable Inline Scripting</label>
<type>checkbox</type>
<help>Checking this directive allows to use scripts or styles directly embedded in in the HTML content.
Examples are the script and the style tags.</help>
</field>
<field>
<id>security_header.csp_form_action_eval</id>
<label>Enable Eval</label>
<type>checkbox</type>
<help>Checking this box allows functions like eval or createFunction in JS, or style attributes for CSS.</help>
</field>
<field>
<id>security_header.csp_form_action_self</id>
<label>Enable Same Origin (recommended)</label>
<type>checkbox</type>
<help>Allows everything from the same site (path can differ, but host, protocol and port need to be the same).</help>
</field>
<field>
<id>security_header.csp_form_action_blob</id>
<label>Enable Blobs</label>
<type>checkbox</type>
<help>Allows to use blobs as a data source. This usually is content, which is somehow generated in JavaScript.</help>
</field>
<field>
<id>security_header.csp_form_action_mediastream</id>
<label>Enable Media Streams</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_form_action_filesystem</id>
<label>Enable File System URLs</label>
<type>checkbox</type>
</field>
<field>
<id>security_header.csp_form_action_none</id>
<label>Forbid Explicitly</label>
<type>checkbox</type>
<help>If this checkbox is checked, all other settings for this directive are ignored and everything will be forbidden.</help>
</field>
</form>

View file

@ -1,5 +1,6 @@
<model>
<mount>//OPNsense/Nginx</mount>
<version>1.1.0</version>
<description>nginx web server, reverse proxy and waf</description>
<items>
<general>
@ -459,6 +460,18 @@
<default>1</default>
<Required>Y</Required>
</sendfile>
<security_header type="ModelRelationField">
<Model>
<template>
<source>OPNsense.Nginx.Nginx</source>
<items>security_header</items>
<display>description</display>
</template>
</Model>
<ValidationMessage>Selected security rule not found</ValidationMessage>
<Required>N</Required>
<multiple>N</multiple>
</security_header>
</http_server>
<http_rewrite type="ArrayField">
@ -484,5 +497,336 @@
</flag>
</http_rewrite>
<security_header type="ArrayField">
<description type="TextField">
<Required>Y</Required>
</description>
<referrer type="OptionField">
<multiple>N</multiple>
<OptionValues>
<no-referrer>No Referrer</no-referrer>
<no-referrer-when-downgrade>No Referrer When Downgrading</no-referrer-when-downgrade>
<same-origin>Same Origin (recommended)</same-origin>
<origin>Origin</origin>
<strict-origin>Strict Origin</strict-origin>
<strict-origin-when-cross-origin>Strict Origin When Cross Origin</strict-origin-when-cross-origin>
<origin-when-cross-origin>Origin When Cross Origin</origin-when-cross-origin>
<unsafe-url>Unsafe URL</unsafe-url>
</OptionValues>
<Required>N</Required>
</referrer>
<xssprotection type="OptionField">
<multiple>N</multiple>
<OptionValues>
<val1 value="1; mode=block">Block</val1>
<val2 value="0">Off</val2>
<val3 value="1">On</val3>
</OptionValues>
<Required>N</Required>
</xssprotection>
<content_type_options type="BooleanField">
<Required>Y</Required>
</content_type_options>
<strict_transport_security_time type="IntegerField">
<Required>N</Required>
</strict_transport_security_time>
<strict_transport_security_include_subdomains type="BooleanField">
<Required>Y</Required>
<default>1</default>
</strict_transport_security_include_subdomains>
<hpkp_keys type="CSVListField">
<Required>N</Required>
<mask>/[a-z0-9\+\/=]+(,[a-z0-9\+\/=]+)*/i</mask>
</hpkp_keys>
<hpkp_report_only type="BooleanField">
<Required>Y</Required>
</hpkp_report_only>
<hpkp_time type="IntegerField">
<Required>N</Required>
</hpkp_time>
<hpkp_include_subdomains type="BooleanField">
<Required>Y</Required>
</hpkp_include_subdomains>
<enable_csp type="BooleanField">
<Required>Y</Required>
</enable_csp>
<csp_report_only type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_report_only>
<csp_default_src_enabled type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_enabled>
<csp_default_src_data_urls type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_data_urls>
<csp_default_src_http_urls type="CSVListField">
<Required>N</Required>
</csp_default_src_http_urls>
<csp_default_src_inline type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_inline>
<csp_default_src_eval type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_eval>
<csp_default_src_self type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_self>
<csp_default_src_blob type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_blob>
<csp_default_src_mediastream type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_mediastream>
<csp_default_src_filesystem type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_filesystem>
<csp_default_src_none type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_default_src_none>
<csp_script_src_enabled type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_enabled>
<csp_script_src_data_urls type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_data_urls>
<csp_script_src_http_urls type="CSVListField">
<Required>N</Required>
</csp_script_src_http_urls>
<csp_script_src_inline type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_inline>
<csp_script_src_eval type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_eval>
<csp_script_src_self type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_self>
<csp_script_src_blob type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_blob>
<csp_script_src_mediastream type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_mediastream>
<csp_script_src_filesystem type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_filesystem>
<csp_script_src_none type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_script_src_none>
<csp_img_src_enabled type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_enabled>
<csp_img_src_data_urls type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_data_urls>
<csp_img_src_http_urls type="CSVListField">
<Required>N</Required>
</csp_img_src_http_urls>
<csp_img_src_inline type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_inline>
<csp_img_src_eval type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_eval>
<csp_img_src_self type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_self>
<csp_img_src_blob type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_blob>
<csp_img_src_mediastream type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_mediastream>
<csp_img_src_filesystem type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_filesystem>
<csp_img_src_none type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_img_src_none>
<csp_style_src_enabled type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_enabled>
<csp_style_src_data_urls type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_data_urls>
<csp_style_src_http_urls type="CSVListField">
<Required>N</Required>
</csp_style_src_http_urls>
<csp_style_src_inline type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_inline>
<csp_style_src_eval type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_eval>
<csp_style_src_self type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_self>
<csp_style_src_blob type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_blob>
<csp_style_src_mediastream type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_mediastream>
<csp_style_src_filesystem type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_filesystem>
<csp_style_src_none type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_style_src_none>
<csp_media_src_enabled type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_enabled>
<csp_media_src_data_urls type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_data_urls>
<csp_media_src_http_urls type="CSVListField">
<Required>N</Required>
</csp_media_src_http_urls>
<csp_media_src_inline type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_inline>
<csp_media_src_eval type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_eval>
<csp_media_src_self type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_self>
<csp_media_src_blob type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_blob>
<csp_media_src_mediastream type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_mediastream>
<csp_media_src_filesystem type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_filesystem>
<csp_media_src_none type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_media_src_none>
<csp_font_src_enabled type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_enabled>
<csp_font_src_data_urls type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_data_urls>
<csp_font_src_http_urls type="CSVListField">
<Required>N</Required>
</csp_font_src_http_urls>
<csp_font_src_inline type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_inline>
<csp_font_src_eval type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_eval>
<csp_font_src_self type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_self>
<csp_font_src_blob type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_blob>
<csp_font_src_mediastream type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_mediastream>
<csp_font_src_filesystem type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_filesystem>
<csp_font_src_none type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_font_src_none>
<csp_form_action_enabled type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_enabled>
<csp_form_action_data_urls type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_data_urls>
<csp_form_action_http_urls type="CSVListField">
<Required>N</Required>
</csp_form_action_http_urls>
<csp_form_action_inline type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_inline>
<csp_form_action_eval type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_eval>
<csp_form_action_self type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_self>
<csp_form_action_blob type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_blob>
<csp_form_action_mediastream type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_mediastream>
<csp_form_action_filesystem type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_filesystem>
<csp_form_action_none type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_form_action_none>
</security_header>
</items>
</model>

View file

@ -96,6 +96,7 @@ $( document ).ready(function() {
'httpserver',
'httprewrite',
'custompolicy',
'security_header',
'naxsirule'].forEach(function(element) {
$("#grid-" + element).UIBootgrid(
{ 'search':'/api/nginx/settings/search' + element,
@ -149,6 +150,9 @@ $( document ).ready(function() {
<li>
<a data-toggle="tab" id="subtab_item_nginx-http-naxsirule" href="#subtab_nginx-http-naxsirule">{{ lang._('Naxsi WAF Rule')}}</a>
</li>
<li>
<a data-toggle="tab" id="subtab_item_nginx-http-security_header" href="#subtab_nginx-http-security_header">{{ lang._('Security Headers')}}</a>
</li>
</ul>
</li>
</ul>
@ -367,6 +371,27 @@ $( document ).ready(function() {
</tfoot>
</table>
</div>
<div id="subtab_nginx-http-security_header" class="tab-pane fade">
<table id="grid-security_header" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="security_headersdlg">
<thead>
<tr>
<th data-column-id="description" data-type="string" data-sortable="true" data-visible="true">{{ lang._('Description') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button type="button" class="btn btn-xs reload_btn btn-primary"><span class="fa fa-refresh reloadAct_progress"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
@ -380,3 +405,4 @@ $( document ).ready(function() {
{{ partial("layout_partials/base_dialog",['fields': httprewrite,'id':'httprewritedlg', 'label':lang._('Edit URL Rewrite')]) }}
{{ partial("layout_partials/base_dialog",['fields': naxsi_custom_policy,'id':'custompolicydlg', 'label':lang._('Edit WAF Policy')]) }}
{{ partial("layout_partials/base_dialog",['fields': naxsi_rule,'id':'naxsiruledlg', 'label':lang._('Edit Naxsi Rule')]) }}
{{ partial("layout_partials/base_dialog",['fields': security_headers,'id':'security_headersdlg', 'label':lang._('Edit Security Headers')]) }}

View file

@ -0,0 +1,23 @@
<?php
$log_file = '/var/log/nginx/csp_violations.log';
// make sure we don't have any formatting issues here
if (stristr($_SERVER['CONTENT_TYPE'], 'json') === false) {
http_response_code(400);
echo "This endpoint expects JSON data. Please send data using a json mime time (for example application/json)";
exit(0);
}
if ($json_data = json_decode(file_get_contents('php://input'), true)) {
http_response_code(204);
// inject some data for a log viewer to get a relation with the server entry
$json_data['server_time'] = time();
$json_data['server_uuid'] = $_SERVER['SERVER-UUID'];
$json_data = json_encode($json_data);
file_put_contents($log_file, $json_data . PHP_EOL, FILE_APPEND | LOCK_EX);
} else {
http_response_code(400);
echo "Your request data cannot be decoded. Please send compliant JSON data.";
exit(0);
}

View file

@ -87,6 +87,12 @@ server {
#include tls.conf;
error_page 404 /opnsense_error_404.html;
error_page 500 501 502 503 504 /opnsense_server_error.html;
{% if server.security_header is defined and server.security_header != '' %}
{% set security_rule = helpers.getUUID(server.security_header) %}
{% if security_rule is defined %}
{% include "OPNsense/Nginx/security_rule.conf" ignore missing with context %}
{% endif %}
{% endif %}
# location to ban the host permanently
set $naxsi_extensive_log {% if server.naxsi_extensive_log is defined and server.naxsi_extensive_log == '1' %}1{% else %}0{% endif %};
location @permanentban {
@ -123,6 +129,24 @@ server {
{
return 418;
}
location = /opnsense-report-csp-violation {
include fastcgi_params;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param SCRIPT_FILENAME /usr/local/opnsense/scripts/nginx/csp_report.php;
fastcgi_param TLS-Cipher $ssl_cipher;
fastcgi_param TLS-Protocol $ssl_protocol;
fastcgi_param TLS-SNI-Host $ssl_server_name;
{% if helpers._template_in_data['__uuid__'] is defined %}
{% for uuid in helpers._template_in_data['__uuid__'] %}
{% if helpers._template_in_data['__uuid__'][uuid] == server %}
fastcgi_param SERVER-UUID "{{ uuid }}";
{% endif %}
{% endfor %}
{% endif %}
fastcgi_intercept_errors on;
fastcgi_pass unix:/var/run/php-webgui.socket;
}
location /opnsense-auth-request {
internal;
fastcgi_pass unix:/var/run/php-webgui.socket;

View file

@ -5,8 +5,7 @@ load_module /usr/local/libexec/nginx/ngx_mail_module.so;
load_module /usr/local/libexec/nginx/ngx_http_brotli_filter_module.so;
load_module /usr/local/libexec/nginx/ngx_http_brotli_static_module.so;
# TODO enable root when running the web interface
#user root wheel;
user www staff;
worker_processes 1;
error_log /var/log/nginx/error.log;

View file

@ -4,7 +4,7 @@ user = root
group = wheel
listen = /var/run/php-webgui.socket
listen.owner = root
listen.group = wheel
listen.group = staff
listen.mode = 0660
pm = dynamic
pm.max_children = 5

View file

@ -3,8 +3,8 @@
user = www
group = www
listen = /var/run/php-www.socket
listen.owner = www
listen.group = www
listen.owner = root
listen.group = staff
listen.mode = 0660
pm = dynamic
pm.max_children = 5

View file

@ -0,0 +1,65 @@
{% if security_rule.referrer is defined %}
add_header Referrer-Policy "{{ security_rule.referrer }}" always;
{% endif %}
{% if security_rule.xssprotection is defined %}
add_header X-XSS-Protection "{{ security_rule.xssprotection }}" always;
{% endif %}
{% if security_rule.content_type_options is defined and security_rule.content_type_options == '1' %}
add_header X-Content-Type-Options "nosniff" always;
{% endif %}
{% if security_rule.strict_transport_security_time is defined %}
add_header Strict-Transport-Security "{{ security_rule.strict_transport_security_time }}{%
if security_rule.strict_transport_security_include_subdomains is defined and
security_rule.strict_transport_security_include_subdomains == '1' %}; includeSubDomains{% endif %}" always;
{% endif %}
{% if security_rule.hpkp_keys is defined and security_rule.hpkp_time is defined %}
add_header Public-Key-Pins{% if security_rule.hpkp_report_only is defined and security_rule.hpkp_report_only == '1'
%}-Report-Only{% endif %} "{% for key in security_rule.hpkp_keys.split(',')
%}pin-sha256={{ key }}; {% endfor %}max-age={{ security_rule.hpkp_time }}{%
if security_rule.hpkp_include_subdomains is defined and
security_rule.hpkp_include_subdomains == '1' %}; includeSubDomains{% endif %}" always;
{% endif %}
{% if security_rule.enable_csp is defined and security_rule.enable_csp == '1' %}
{% set hash_csp = {} %}
{% for csp_category in ['default-src', 'script-src', 'img-src', 'style-src', 'media-src', 'font-src', 'form-action'] %}
{% set prefix = 'csp_' + csp_category.replace('-', '_') + '_' %}
{% if security_rule[prefix + 'enabled'] == '1' %}
{% set current_list = [] %}
{% if security_rule[prefix + 'none'] is defined and security_rule[prefix + 'none'] == '1' %}
{% do current_list.append("'none'") %}
{% else %}
{% if security_rule[prefix + 'data_urls'] is defined and security_rule[prefix + 'data_urls'] == '1' %}
{% do current_list.append('data:') %}
{% endif %}
{% if security_rule[prefix + 'inline'] is defined and security_rule[prefix + 'inline'] == '1' %}
{% do current_list.append("'unsafe-inline'") %}
{% endif %}
{% if security_rule[prefix + 'eval'] is defined and security_rule[prefix + 'eval'] == '1' %}
{% do current_list.append("'unsafe-eval'") %}
{% endif %}
{% if security_rule[prefix + 'self'] is defined and security_rule[prefix + 'self'] == '1' %}
{% do current_list.append("'self'") %}
{% endif %}
{% if security_rule[prefix + 'blob'] is defined and security_rule[prefix + 'blob'] == '1' %}
{% do current_list.append("blob:") %}
{% endif %}
{% if security_rule[prefix + 'mediastream'] is defined and security_rule[prefix + 'mediastream'] == '1' %}
{% do current_list.append("mediastream:") %}
{% endif %}
{% if security_rule[prefix + 'filesystem'] is defined and security_rule[prefix + 'filesystem'] == '1' %}
{% do current_list.append("filesystem:") %}
{% endif %}
{% if security_rule[prefix + 'http_urls'] is defined and security_rule[prefix + 'http_urls'] != '' %}
{% do current_list.append(security_rule[prefix + 'http_urls'].replace(',', ' ')) %}
{% endif %}
{% endif %}
{% if current_list|length > 0 %}
{# only append non-empty #}
{% do hash_csp.update({csp_category: current_list}) %}
{% endif %}
{% endif %}
{% endfor %}
add_header Content-Security-Policy{% if security_rule.csp_report_only %}-Report-Only{% endif %} "{%
for key, value in hash_csp.items() %}{{ key }} {{ value|join(' ') }}; {% endfor %}{#
#} report-uri /opnsense-report-csp-violation" always;
{% endif %}