Limit CSP log file size (#4098)

This commit is contained in:
Fabian Franz BSc 2024-07-19 10:02:22 +02:00 committed by GitHub
parent 8514b05cac
commit b97e975a57
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 31 additions and 2 deletions

View file

@ -15,6 +15,7 @@ Plugin Changelog
* Add the option to not log TLS handshakes
* Remove obsolete http2_push_preload directive
* Migrate from the deprecated 'listen … http2' directive to the 'http2' directive
* Limit CSP log file size (migration notice: if you want to keep CSP violations logged, you will need to enable logging in the security policy)
1.33

View file

@ -73,6 +73,12 @@
<type>checkbox</type>
<help>If checked, the Content Security Policy (CSP) header is enabled. A detailed configuration is still required via the other tabs of this sheet.</help>
</field>
<field>
<id>security_header.csp_log_violations</id>
<label>Log violations</label>
<type>checkbox</type>
<help>If checked, the plugin collects CSP violation reports and stores one JSON document per line under /var/log/nginx/csp_violations.log. You can use that file to check for XSS attempts or broken web pages where the CSP denied access to a resource.</help>
</field>
<field>
<id>security_header.csp_report_only</id>
<label>Report Only</label>

View file

@ -1369,6 +1369,10 @@
<enable_csp type="BooleanField">
<Required>Y</Required>
</enable_csp>
<csp_log_violations type="BooleanField">
<Required>Y</Required>
<default>0</default>
</csp_log_violations>
<csp_report_only type="BooleanField">
<Required>Y</Required>
<default>0</default>

View file

@ -27,6 +27,8 @@
*/
$log_file = '/var/log/nginx/csp_violations.log';
$max_file_size = 1024 * 1024 * 30; // 30 MiB
$max_single_record_size = 1024 * 20; // 20 KiB
// make sure we don't have any formatting issues here
if (stristr($_SERVER['CONTENT_TYPE'], 'csp-report') === false) {
@ -41,6 +43,18 @@ if ($json_data = json_decode(file_get_contents('php://input'), true)) {
$json_data['server_time'] = time();
$json_data['server_uuid'] = $_SERVER['SERVER-UUID'];
$json_data = json_encode($json_data);
if (strlen($json_data) > $max_single_record_size) {
echo "The payload is too large";
http_response_code(413);
exit(0);
}
if (file_exists($log_file)) {
if ((filesize($log_file) + strlen($json_data)) > $max_file_size) {
// silently drop the data
http_response_code(200);
exit(0);
}
}
file_put_contents($log_file, $json_data . PHP_EOL, FILE_APPEND | LOCK_EX);
} else {
http_response_code(400);

View file

@ -294,7 +294,9 @@ server {
{% set ip_acl = server.ip_acl %}
{% include "OPNsense/Nginx/ipacl.conf" %}
{% endif %}
{% if server.security_header is defined and server.security_header != '' %}
{% set security_rule = helpers.getUUID(server.security_header) %}
{% if security_rule is defined and security_rule.csp_log_violations is defined and security_rule.csp_log_violations == '1' %}
location = /opnsense-report-csp-violation {
include fastcgi_params;
fastcgi_param QUERY_STRING $query_string;
@ -306,6 +308,8 @@ server {
fastcgi_intercept_errors on;
fastcgi_pass unix:/var/run/php-webgui.socket;
}
{% endif %}
{% endif %}
location /opnsense-auth-request {
internal;
fastcgi_pass unix:/var/run/php-webgui.socket;

View file

@ -61,5 +61,5 @@
{% do our_headers.append('Content-Security-Policy-Report-Only') %}
add_header Content-Security-Policy{% if security_rule.csp_report_only is defined and security_rule.csp_report_only == '1' %}-Report-Only{% endif %} "{%
for key, value in hash_csp.items() %}{{ key }} {{ value|join(' ') }}; {% endfor %}{#
#} report-uri /opnsense-report-csp-violation" always;
#}{% if security_rule.csp_log_violations is defined and security_rule.csp_log_violations == '1' %} report-uri /opnsense-report-csp-violation{% endif %}" always;
{% endif %}