mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
www/nginx: import naxsi core rules into configuration (#891)
* www/nginx: add draft of code to download naxsi rules * www/nginx: run bmake style-fix * www/nginx: naxsi rule download * www/nginx: rename file * www/nginx: add configd task * www/nginx: add initial GUI code for rule download * www/nginx: add view part * www/nginx: fix inverted regex flag * Problem with multiple Upstream servers (#893) Small change to make it work.
This commit is contained in:
@@ -29,12 +29,23 @@
|
||||
namespace OPNsense\Nginx\Api;
|
||||
|
||||
use OPNsense\Base\ApiMutableModelControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
|
||||
class SettingsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
static protected $internalModelClass = '\OPNsense\Nginx\Nginx';
|
||||
static protected $internalModelName = 'nginx';
|
||||
|
||||
// download rules
|
||||
public function downloadrulesAction()
|
||||
{
|
||||
if (!$this->request->isPost()) {
|
||||
return array('error' => 'Must be called via POST');
|
||||
}
|
||||
$backend = new Backend();
|
||||
return array('result' => trim($backend->configdRun('nginx naxsidownloadrules')));
|
||||
}
|
||||
|
||||
// User List
|
||||
|
||||
public function searchuserlistAction()
|
||||
|
||||
@@ -57,6 +57,9 @@ class IndexController extends \OPNsense\Base\IndexController
|
||||
$this->view->limit_request_connection = $this->getForm("limit_request_connection");
|
||||
$this->view->limit_zone = $this->getForm("limit_zone");
|
||||
$this->view->cache_path = $this->getForm("cache_path");
|
||||
$nginx = new Nginx();
|
||||
$this->view->show_naxsi_download_button =
|
||||
count($nginx->custom_policy->__items) == 0 && count($nginx->naxsi_rule->__items) == 0;
|
||||
$this->view->pick('OPNsense/Nginx/index');
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ $( document ).ready(function() {
|
||||
});
|
||||
|
||||
// update history on tab state and implement navigation
|
||||
if(window.location.hash != "") {
|
||||
if(window.location.hash !== "") {
|
||||
$('a[href="' + window.location.hash + '"]').click()
|
||||
}
|
||||
$('.nav-tabs a').on('shown.bs.tab', function (e) {
|
||||
@@ -56,8 +56,8 @@ $( document ).ready(function() {
|
||||
// form save event handlers for all defined forms
|
||||
$('[id*="save_"]').each(function(){
|
||||
$(this).click(function() {
|
||||
var frm_id = $(this).closest("form").attr("id");
|
||||
var frm_title = $(this).closest("form").attr("data-title");
|
||||
let frm_id = $(this).closest("form").attr("id");
|
||||
let frm_title = $(this).closest("form").attr("data-title");
|
||||
// save data for General TAB
|
||||
saveFormToEndpoint(url="/api/nginx/settings/set", formid=frm_id, callback_ok=function(){
|
||||
// on correct save, perform reconfigure. set progress animation when reloading
|
||||
@@ -67,7 +67,7 @@ $( document ).ready(function() {
|
||||
// when done, disable progress animation.
|
||||
$("#"+frm_id+"_progress").removeClass("fa fa-spinner fa-pulse");
|
||||
|
||||
if (data != undefined && (status != "success" || data['status'] != 'ok')) {
|
||||
if (data !== undefined && (status !== "success" || data['status'] !== 'ok')) {
|
||||
// fix error handling
|
||||
BootstrapDialog.show({
|
||||
type:BootstrapDialog.TYPE_WARNING,
|
||||
@@ -105,6 +105,33 @@ $( document ).ready(function() {
|
||||
}
|
||||
);
|
||||
});
|
||||
let naxsi_rule_download_button = $('#naxsiruledownloadbtn');
|
||||
naxsi_rule_download_button.click(function () {
|
||||
BootstrapDialog.show({
|
||||
type: BootstrapDialog.TYPE_INFO,
|
||||
title: "{{ lang._('Download NAXSI Rules') }}",
|
||||
message: "{{ lang._('You are about to download the core rules from the Repository of NAXSI. You have to accept its %slicense%s to download the rules.')|format("<a href='https://github.com/nbs-system/naxsi/blob/master/LICENSE' target='_blank'>", "</a>") }}",
|
||||
buttons: [{
|
||||
label: "{{ lang._('Accept And Download') }}",
|
||||
cssClass: 'btn-primary',
|
||||
icon: 'fa fa-download',
|
||||
action: function(dlg){
|
||||
dlg.close();
|
||||
ajaxCall(url="/api/nginx/settings/downloadrules", sendData={}, callback=function(data,status) {
|
||||
$('#naxsiruledownloadalert').hide();
|
||||
// reload view after installing rules
|
||||
$('#grid-naxsirule').bootgrid('reload');
|
||||
$('#grid-custompolicy').bootgrid('reload');
|
||||
});
|
||||
}
|
||||
}, {
|
||||
label: '{{ lang._('Reject') }}',
|
||||
action: function(dlg){
|
||||
dlg.close();
|
||||
}
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -122,7 +149,7 @@ $( document ).ready(function() {
|
||||
</a>
|
||||
<a data-toggle="tab" onclick="$('#subtab_item_nginx-http-location').click();"
|
||||
class="visible-lg-inline-block visible-md-inline-block visible-xs-inline-block visible-sm-inline-block"
|
||||
style="border-right:0px;"><b>{{ lang._('HTTP(S)')}}</b></a>
|
||||
style="border-right:0;"><b>{{ lang._('HTTP(S)')}}</b></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<a data-toggle="tab" id="subtab_item_nginx-http-location" href="#subtab_nginx-http-location">{{ lang._('Location')}}</a>
|
||||
@@ -350,6 +377,16 @@ $( document ).ready(function() {
|
||||
</table>
|
||||
</div>
|
||||
<div id="subtab_nginx-http-custompolicy" class="tab-pane fade">
|
||||
{% if (show_naxsi_download_button) %}
|
||||
<div class="alert alert-info" id="naxsiruledownloadalert" role="alert" style="vertical-align: middle;display: table;width: 100%;">
|
||||
<div style="display: table-cell;vertical-align: middle;">{{ lang._('It looks like you are not having any rules installed. You may want to download the NAXSI core rules.') }}</div>
|
||||
<div class="pull-right" style="vertical-align: middle;display: table-cell;">
|
||||
<button id="naxsiruledownloadbtn" class="btn btn-primary">
|
||||
<i class="fa fa-download" aria-hidden="true"></i> {{ lang._('Download') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<table id="grid-custompolicy" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="custompolicydlg">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2018 Fabian Franz
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
require_once('config.inc');
|
||||
use OPNsense\Core\Config;
|
||||
use OPNsense\Nginx\Nginx;
|
||||
|
||||
function download_rules()
|
||||
{
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => 'https://raw.githubusercontent.com/nbs-system/naxsi/master/naxsi_config/naxsi_core.rules',
|
||||
CURLOPT_CUSTOMREQUEST => 'GET',
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_VERBOSE => 0,
|
||||
CURLOPT_MAXREDIRS => 1,
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
"User-Agent: OPNsense Firewall"
|
||||
)
|
||||
));
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
$info = curl_getinfo($curl);
|
||||
curl_close($curl);
|
||||
if ($info['http_code'] != 200 || $err) {
|
||||
syslog(LOG_ERR, 'Cannot download NAXSI core rules');
|
||||
syslog(LOG_ERR, json_encode($info));
|
||||
exit(1);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
function prepare_values($row)
|
||||
{
|
||||
$row['match_zone'] = explode('|', $row['match_zone']);
|
||||
return $row;
|
||||
}
|
||||
|
||||
function parse_rules($data)
|
||||
{
|
||||
$parsed = [];
|
||||
$tmp = null;
|
||||
$description = array('rule', 'match_type', 'match', 'message', 'match_zone', 'variable', 'value', 'id');
|
||||
|
||||
foreach ($data as $line) {
|
||||
$line = trim($line);
|
||||
$matches = [];
|
||||
if (preg_match('/## (.*) ##/', $line, $matches)) {
|
||||
if (isset($tmp) && empty($parsed[$tmp])) {
|
||||
unset($parsed[$tmp]);
|
||||
}
|
||||
$tmp = trim($matches[1]);
|
||||
$parsed[$tmp] = [];
|
||||
} elseif (preg_match('/\S+ "(str|rx):([^\"]+)" "msg:([^\\"]*)" "mz:([^\"]*)" "s:([^\"]*):(\d+)" id:(\d+);/', $line, $matches)) {
|
||||
$parsed[$tmp][] = prepare_values(array_combine($description, $matches));
|
||||
}
|
||||
}
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
function save_to_model($data)
|
||||
{
|
||||
$model = new Nginx();
|
||||
foreach ($data as $group => $rules) {
|
||||
// create a new policy
|
||||
$policy = $model->custom_policy->Add();
|
||||
$policy->name = $group;
|
||||
$policy->value = '8';
|
||||
$policy->operator = '>=';
|
||||
$policy->action = 'BLOCK';
|
||||
// create new values for policy
|
||||
$rule_list = [];
|
||||
foreach ($rules as $rule) {
|
||||
$rule_mdl = $model->naxsi_rule->Add();
|
||||
$rule_mdl->description = $rule['message'];
|
||||
$rule_mdl->message = $rule['message'];
|
||||
$rule_mdl->ruletype = 'main';
|
||||
$rule_mdl->match_type = 'id';
|
||||
$rule_mdl->identifier = $rule['id'];
|
||||
$rule_mdl->match_value = $rule['match'];
|
||||
$rule_mdl->regex = $rule['match_type'] == 'str' ? '0' : '1';
|
||||
// default to 0
|
||||
$rule_mdl->args = '0';
|
||||
$rule_mdl->headers = '0';
|
||||
$rule_mdl->name = '0';
|
||||
$rule_mdl->raw_body = '0';
|
||||
$rule_mdl->file_extension = '0';
|
||||
$rule_mdl->negate = '0';
|
||||
foreach ($rule['match_zone'] as $match_zone) {
|
||||
if (stripos($match_zone, ':') === false) {
|
||||
switch ($match_zone) {
|
||||
case 'ARGS':
|
||||
$rule_mdl->args = '1';
|
||||
break;
|
||||
case 'HEADERS':
|
||||
$rule_mdl->headers = '1';
|
||||
break;
|
||||
case 'NAME':
|
||||
$rule_mdl->name = '1';
|
||||
break;
|
||||
case 'RAW_BODY':
|
||||
$rule_mdl->raw_body = '1';
|
||||
break;
|
||||
case 'FILE_EXT':
|
||||
$rule_mdl->file_extension = '1';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$kv = explode(':', $match_zone);
|
||||
switch ($kv[0]) {
|
||||
case '$BODY_VAR':
|
||||
$rule_mdl->dollar_body_var = $kv[1];
|
||||
break;
|
||||
case '$ARGS_VAR':
|
||||
$rule_mdl->dollar_args_var = $kv[1];
|
||||
break;
|
||||
case '$HEADERS_VAR':
|
||||
$rule_mdl->dollar_headers_var = $kv[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
$rule_list[] = $rule_mdl->getAttributes()["uuid"];
|
||||
}
|
||||
$policy->naxsi_rules = implode(',', $rule_list);
|
||||
}
|
||||
|
||||
$val_result = $model->performValidation(false);
|
||||
if (count($val_result) !== 0) {
|
||||
print_r($val_result);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$model->serializeToConfig();
|
||||
Config::getInstance()->save();
|
||||
}
|
||||
|
||||
|
||||
#$data = parse_rules(file('./naxsi_core.rules'));
|
||||
$data = parse_rules(explode("\n", download_rules()));
|
||||
save_to_model($data);
|
||||
@@ -50,3 +50,8 @@ parameters:
|
||||
type:script_output
|
||||
message:Ban bots and other attackers (nginx plugin)
|
||||
description:Automatically ban attacking hosts (nginx plugin)
|
||||
|
||||
[naxsidownloadrules]
|
||||
command:/usr/local/opnsense/scripts/nginx/naxsi_rule_download.php
|
||||
parameters:
|
||||
type:script
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for upstream_uuid, upstream in upstreamlist.items() %}
|
||||
{% for upstream_serveruuid in upstream.serverentries.split(',') %}
|
||||
upstream upstream{{ upstream_uuid.replace('-','') }} {
|
||||
{% for upstream_serveruuid in upstream.serverentries.split(',') %}
|
||||
{% set upstream_server = helpers.getUUID(upstream_serveruuid) %}
|
||||
server {% if ':' in upstream_server.server %}[{% endif %}{{ upstream_server.server }}{% if ':' in upstream_server.server %}]{% endif
|
||||
%}{% if upstream_server.port is defined %}:{{ upstream_server.port }}{% endif
|
||||
|
||||
Reference in New Issue
Block a user