Pavel Loginov 2022-01-02 18:51:13 +03:00
parent 5f27f86df0
commit 831fbf4df9
17 changed files with 1122 additions and 321 deletions

View File

@ -859,7 +859,7 @@ def update_db_v_5_3_2_2(**kwargs):
def update_ver():
query = Version.update(version='5.3.5.0')
query = Version.update(version='5.3.6.0')
try:
query.execute()
except:

View File

@ -743,10 +743,15 @@ def install_haproxy(server_ip, **kwargs):
def waf_install(server_ip):
import sql
script = "waf.sh"
tmp_config_path = sql.get_setting('tmp_config_path')
proxy = sql.get_setting('proxy')
haproxy_dir = sql.get_setting('haproxy_dir')
ver = check_haproxy_version(server_ip)
service = ' WAF'
ssh_enable, ssh_user_name, ssh_user_password, ssh_key_name = return_ssh_keys_path(server_ip)
ssh_port = '22'
if ssh_enable == 0:
ssh_key_name = ''
os.system("cp scripts/%s ." % script)
@ -755,22 +760,20 @@ def waf_install(server_ip):
else:
proxy_serv = ''
commands = ["sudo chmod +x " + tmp_config_path+script + " && " + tmp_config_path+script + " PROXY=" + proxy_serv +
" HAPROXY_PATH=" + haproxy_dir + " VERSION=" + ver]
commands = ["chmod +x " + script + " && ./" + script + " PROXY=" + proxy_serv + " HAPROXY_PATH=" + haproxy_dir +
" VERSION='" + ver + "' SSH_PORT=" + ssh_port + " HOST=" + server_ip +
" USER=" + ssh_user_name + " PASS='" + ssh_user_password + "' KEY=" + ssh_key_name]
error = str(upload(server_ip, tmp_config_path, script))
output, error = subprocess_execute(commands[0])
if error:
print('error: '+error)
logging('localhost', error, haproxywi=1)
if show_installation_output(error, output, service):
ssh_command(server_ip, commands, print_out="1")
sql.insert_waf_metrics_enable(server_ip, "0")
sql.insert_waf_rules(server_ip)
os.system("rm -f %s" % script)
ssh_command(server_ip, commands, print_out="1")
sql.insert_waf_metrics_enable(server_ip, "0")
sql.insert_waf_rules(server_ip)
def install_nginx(server_ip, **kwargs):
import sql

View File

@ -632,42 +632,61 @@ if act == "overview":
ioloop.close()
if act == "overviewwaf":
import asyncio
import http.cookies
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/ajax'), autoescape=True,
extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'])
template = env.get_template('overivewWaf.html')
async def async_get_overviewWaf(serv1, serv2):
haproxy_path = sql.get_setting('haproxy_dir')
commands0 = ["ps ax |grep waf/bin/modsecurity |grep -v grep |wc -l"]
commands1 = ["cat %s/waf/modsecurity.conf |grep SecRuleEngine |grep -v '#' |awk '{print $2}'" % haproxy_path]
servers = sql.select_servers(server=serv)
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_id = cookie.get('uuid')
server_status = (serv1, serv2,
funct.ssh_command(serv2, commands0),
funct.ssh_command(serv2, commands1).strip(),
sql.select_waf_metrics_enable_server(serv2))
return server_status
haproxy_path = ''
returned_servers = []
waf = ''
metrics_en = 0
waf_process = ''
waf_mode = ''
for server in servers:
haproxy = sql.select_haproxy(server[2])
if haproxy == 1:
haproxy_path = sql.get_setting('haproxy_dir')
waf = sql.select_waf_servers(server[2])
metrics_en = sql.select_waf_metrics_enable_server(server[2])
try:
waf_len = len(waf)
except:
waf_len = 0
async def get_runner_overviewWaf():
env = Environment(loader=FileSystemLoader('templates/ajax'), autoescape=True,
extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'])
template = env.get_template('overivewWaf.html')
if waf_len >= 1:
command = ["ps ax |grep waf/bin/modsecurity |grep -v grep |wc -l"]
commands1 = [
"cat %s/waf/modsecurity.conf |grep SecRuleEngine |grep -v '#' |awk '{print $2}'" % haproxy_path]
waf_process = funct.ssh_command(server[2], command)
waf_mode = funct.ssh_command(server[2], commands1).strip()
servers = []
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_id = cookie.get('uuid')
futures = [async_get_overviewWaf(server[1], server[2]) for server in sql.select_servers(server=serv)]
for i, future in enumerate(asyncio.as_completed(futures)):
result = await future
servers.append(result)
servers_sorted = sorted(servers, key=funct.get_key)
template = template.render(service_status=servers_sorted, role=sql.get_user_role_by_uuid(user_id.value))
print(template)
server_status = (server[1],
server[2],
waf_process,
waf_mode,
metrics_en,
waf_len)
else:
server_status = (server[1],
server[2],
waf_process,
waf_mode,
metrics_en,
waf_len)
returned_servers.append(server_status)
ioloop = asyncio.get_event_loop()
ioloop.run_until_complete(get_runner_overviewWaf())
ioloop.close()
servers_sorted = sorted(returned_servers, key=funct.get_key)
template = template.render(service_status=servers_sorted, role=sql.get_user_role_by_uuid(user_id.value))
print(template)
if act == "overviewServers":

View File

@ -0,0 +1,11 @@
---
- name: Install WAF
hosts: "{{ variable_host }}"
become: yes
become_method: sudo
gather_facts: yes
roles:
- role: waf
environment:
http_proxy: "{{PROXY}}"
https_proxy: "{{PROXY}}"

View File

@ -0,0 +1,2 @@
---
modsec_ver: "2.9.5"

View File

@ -0,0 +1,12 @@
---
- name: Install git
package:
name: git
state: present
- name: Git clone spoa-modsecurity
command: chdir=/tmp/ git clone https://github.com/haproxy/spoa-modsecurity.git
- name: Set ModSec foleder
set_fact:
mod_sec_dir: /tmp/spoa-modsecurity

View File

@ -0,0 +1,27 @@
---
- name: Download HAProxy tarball
get_url:
url: "http://www.haproxy.org/download/{{ VERSION_MAJ }}/src/haproxy-{{ VERSION }}.tar.gz"
dest: "/tmp/haproxy-{{ VERSION }}.tar.gz"
- name: Create HAProxy directory
file:
path: "/tmp/haproxy-{{ VERSION }}"
state: directory
- name: Untar HAProxy tarball
become: true
become_user: root
unarchive:
src: "/tmp/haproxy-{{ VERSION }}.tar.gz"
dest: "/tmp/haproxy-{{ VERSION }}"
remote_src: true
- name: Copy HAProxy files
synchronize:
src: "/tmp/haproxy-{{ VERSION }}/haproxy-{{ VERSION }}/"
dest: "/tmp/haproxy-{{ VERSION }}"
- name: Set ModSec foleder
set_fact:
mod_sec_dir: "/tmp/haproxy-{{ VERSION }}/contrib/modsecurity"

View File

@ -0,0 +1,389 @@
---
- name: Installing WAF
block:
- name: Set SSH port
set_fact:
ansible_port: "{{SSH_PORT}}"
- name: Check that WAF has been installed
stat:
path: "{{ HAPROXY_PATH }}/waf/modsecurity.conf"
register: stat_result
- name: Fail if has been installed
fail:
msg="info HAProxy WAF has already installed"
when: stat_result.stat.exists
- name: install the el7 RPMS for HAProxy
yum:
name:
- yajl-devel
- http://repo.haproxy-wi.org/libevent-devel-2.0.21-4.el7.x86_64.rpm
state: latest
when:
- ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS'
- ansible_facts['distribution_major_version'] == '7'
environment:
http_proxy: "{{PROXY}}"
https_proxy: "{{PROXY}}"
- name: install the el8 RPMS for HAProxy
yum:
name:
- http://repo.haproxy-wi.org/yajl-devel-2.1.0-10.el8.x86_64.rpm
state: latest
when:
- ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS'
- ansible_facts['distribution_major_version'] == '8'
environment:
http_proxy: "{{PROXY}}"
https_proxy: "{{PROXY}}"
- name: install the common RPMS for HAProxy
yum:
name:
- httpd-devel
- libxml2-devel
- gcc
- curl-devel
- pcre-devel
- wget
- automake
- libevent-devel
- libtool
state: latest
when:
- ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS'
environment:
http_proxy: "{{PROXY}}"
https_proxy: "{{PROXY}}"
- name: Install needed packages
apt:
name:
- libevent-dev
- apache2-dev
- libpcre3-dev
- libxml2-dev
- gcc
- libpcre3-dev
- wget
- libcurl4-nss-dev
- libyajl-dev
- libxml2
- automake
state: present
when: ansible_facts['os_family'] == 'Debian' or ansible_facts['os_family'] == 'Ubuntu'
environment:
http_proxy: "{{PROXY}}"
https_proxy: "{{PROXY}}"
- name: Download Modsec tarball
become: false
get_url:
# url: https://www.modsecurity.org/tarball/2.9.5/modsecurity-2.9.5.tar.gz
url: "https://github.com/SpiderLabs/ModSecurity/releases/download/v{{ modsec_ver }}/modsecurity-{{ modsec_ver }}.tar.gz"
dest: /tmp/modsecurity.tar.gz
owner: "{{ ansible_user }}"
- name: Create HAProxy directory
become: false
file:
path: /tmp/modsecurity
state: directory
- name: Untar Modsec tarball
become: false
unarchive:
src: /tmp/modsecurity.tar.gz
dest: /tmp/modsecurity/
remote_src: true
- name: Copy modsecurity
copy:
src: "/tmp/modsecurity/modsecurity-{{ modsec_ver }}/"
dest: /tmp/modsecurity/
remote_src: yes
- name: Set execute permision to configure
become: true
command: chdir=/tmp/modsecurity/ chmod +x configure
args:
warn: no
- name: Re configure Modsecurity
become: true
command: chdir=/tmp/modsecurity/ autoreconf -f -i
- name: Configure Modsecurity
become: true
command: chdir=/tmp/modsecurity/ ./configure --prefix=/tmp/modsecurity --enable-standalone-module --disable-mlogc --enable-pcre-study --without-lua --enable-pcre-jit
- name: Make Modsecurity
command: chdir=/tmp/modsecurity/ make
- name: Make Install Modsecurity
command: chdir=/tmp/modsecurity/ make -C standalone install
- name: Creates directory
file:
path: /tmp/modsecurity/INSTALL/include
state: directory
- name: Copy Modsec libs
copy:
src: /tmp/modsecurity/standalone/.libs/
dest: /tmp/modsecurity/INSTALL/include/
remote_src: yes
- name: Copy Modsec files
copy:
src: /tmp/modsecurity/standalone/
dest: /tmp/modsecurity/INSTALL/include/
remote_src: yes
- name: Copy Modsec apache files
copy:
src: /tmp/modsecurity/apache2/
dest: /tmp/modsecurity/INSTALL/include/
remote_src: yes
- name: Include task for HAProxy <= 2.3.16
include: haproxy_under_2.4.0.yml
when: VERSION is version('2.3.16', '<=')
- name: Include task for HAProxy >= 2.4.0
include: haproxy_above_2.4.0.yml
when: VERSION is version('2.4.0', '>=')
- name: Make APT Modsecurity module for HAProxy
command: "chdir={{ mod_sec_dir }} make MODSEC_INC=/tmp/modsecurity/INSTALL/include MODSEC_LIB=/tmp/modsecurity/INSTALL/include APACHE2_INC=/usr/include/apache2/ APR_INC=/usr/include/apr-1.0"
when: ansible_facts['os_family'] == 'Debian' or ansible_facts['os_family'] == 'Ubuntu'
- name: Make EL Modsecurity module for HAProxy
command: "chdir={{ mod_sec_dir }} make MODSEC_INC=/tmp/modsecurity/INSTALL/include MODSEC_LIB=/tmp/modsecurity/INSTALL/include APACHE2_INC=/usr/include/httpd/ APR_INC=/usr/include/apr-1"
when: ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS'
- name: Make WAF rules directory
file:
path: "{{ HAPROXY_PATH }}/waf/rules"
state: directory
- name: Make WAF bin directory
file:
path: "{{ HAPROXY_PATH }}/waf/bin"
state: directory
- name: Copy Modsec module to HAProxy dir
copy:
src: "{{ mod_sec_dir }}/modsecurity"
dest: "{{ HAPROXY_PATH }}/waf/bin"
mode: '0744'
remote_src: true
- name: Download modsecurity conf
get_url:
url: https://github.com/SpiderLabs/ModSecurity/raw/v2/master/modsecurity.conf-recommended
dest: "{{ HAPROXY_PATH }}/waf/modsecurity.conf"
- name: Insert Modsec rules
blockinfile:
path: "{{ HAPROXY_PATH }}/waf/modsecurity.conf"
block: |
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_10_ignore_static.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_10_setup.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_11_avs_traffic.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_11_brute_force.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_11_dos_protection.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_13_xml_enabler.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_16_authentication_tracking.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_16_scanner_integration.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_16_username_tracking.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_20_protocol_violations.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_21_protocol_anomalies.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_23_request_limits.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_25_cc_known.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_25_cc_track_pan.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_30_http_policy.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_35_bad_robots.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_40_generic_attacks.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_40_http_parameter_pollution.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_41_sql_injection_attacks.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_41_xss_attacks.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_42_comment_spam.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_42_tight_security.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_45_trojans.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_46_av_scanning.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_46_scanner_integration.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_46_slr_et_xss_attacks.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_46_slr_et_lfi_attacks.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_46_slr_et_sqli_attacks.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_47_common_exceptions.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_49_inbound_blocking.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_50_outbound.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_55_marketing.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_56_pvi_checks.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_59_outbound_blocking.conf
Include {{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_60_correlation.conf
- name: Download unicode.mapping
get_url:
url: https://github.com/SpiderLabs/ModSecurity/raw/v2/master/unicode.mapping
dest: "{{ HAPROXY_PATH }}/waf/unicode.mapping"
- name: Download owasp-modsecurity-crs
get_url:
url: https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/2.2.9.tar.gz
dest: /tmp/owasp.tar.gz
- name: Create owasp directory
file:
path: /tmp/owasp-modsecurity-crs-2.2.9
state: directory
- name: Untar owasp-modsecurity-crs tarball
become: true
become_user: root
unarchive:
src: /tmp/owasp.tar.gz
dest: /tmp/owasp-modsecurity-crs-2.2.9
remote_src: true
- name: Copy owasp files
copy:
src: /tmp/owasp-modsecurity-crs-2.2.9/owasp-modsecurity-crs-2.2.9/
dest: /tmp/owasp-modsecurity-crs-2.2.9
remote_src: yes
- name: Copy Modsec crs conf file
copy:
src: /tmp/owasp-modsecurity-crs-2.2.9/modsecurity_crs_10_setup.conf.example
dest: "{{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_10_setup.conf"
remote_src: true
- name: Copy Modsec crs activated_rules files
copy:
src: /tmp/owasp-modsecurity-crs-2.2.9/activated_rules/
dest: "{{ HAPROXY_PATH }}/waf/rules/"
remote_src: yes
- name: Copy Modsec crs base_rules files
copy:
src: /tmp/owasp-modsecurity-crs-2.2.9/base_rules/
dest: "{{ HAPROXY_PATH }}/waf/rules/"
remote_src: yes
- name: Copy Modsec crs experimental_rules files
copy:
src: /tmp/owasp-modsecurity-crs-2.2.9/experimental_rules/
dest: "{{ HAPROXY_PATH }}/waf/rules/"
remote_src: yes
- name: Copy Modsec crs optional_rules files
copy:
src: /tmp/owasp-modsecurity-crs-2.2.9/optional_rules/
dest: "{{ HAPROXY_PATH }}/waf/rules/"
remote_src: yes
- name: Copy Modsec crs slr_rules files
copy:
src: /tmp/owasp-modsecurity-crs-2.2.9/slr_rules/
dest: "{{ HAPROXY_PATH }}/waf/rules/"
remote_src: yes
- name: Ensure ModSec engine mode on
ansible.builtin.lineinfile:
path: "{{ HAPROXY_PATH }}/waf/modsecurity.conf"
regexp: '^SecRuleEngine DetectionOnly'
line: SecRuleEngine On
- name: Change ModSec audit log
ansible.builtin.lineinfile:
path: "{{ HAPROXY_PATH }}/waf/modsecurity.conf"
regexp: '^SecAuditLogParts ABIJDEFHZ'
line: SecAuditLogParts ABIJDEH
- name: Create modsecurity_crs_10_setup
template:
src: modsecurity_crs_10_setup.conf.j2
dest: "{{ HAPROXY_PATH }}/waf/rules/modsecurity_crs_10_setup.conf"
- name: Create WAF service file
template:
src: waf.service.j2
dest: /etc/systemd/system/waf.service
mode: 0644
- name: Create WAF rsyslog file
template:
src: waf_rsyslog.conf.j2
dest: /etc/rsyslog.d/waf.conf
mode: 0644
- name: Create WAF conf file
template:
src: waf.conf.j2
dest: "{{ HAPROXY_PATH }}/waf.conf"
mode: 0644
- name: Insert Modsec backend
blockinfile:
path: "{{ HAPROXY_PATH }}/haproxy.cfg"
block: |
backend waf
mode tcp
timeout connect 5s
timeout server 3m
server waf 127.0.0.1:12345 check
- name: Daemon-reload for WAF service
systemd:
daemon_reexec: yes
- name: Start and enable WAF service
systemd:
name: waf
state: started
enabled: yes
always:
- name: Remove modsecurity.tar.gz
ansible.builtin.file:
path: /tmp/modsecurity.tar.gz
state: absent
- name: Remove modsecurity-2.9.2
ansible.builtin.file:
path: /tmp/modsecurity-2.9.2
state: absent
- name: Remove HAProxy
ansible.builtin.file:
path: "/tmp/haproxy-{{ VERSION }}"
state: absent
- name: Remove modsecurity
ansible.builtin.file:
path: /tmp/modsecurity
state: absent
- name: Remove modsecurity.conf
ansible.builtin.file:
path: /tmp/modsecurity.conf
state: absent
- name: Remove owasp.tar.gz
ansible.builtin.file:
path: /tmp/owasp.tar.gz
state: absent
- name: Remove owasp-modsecurity-crs-2.2.9
ansible.builtin.file:
path: /tmp/owasp-modsecurity-crs-2.2.9
state: absent
- name: Remove spoa-modsecurity
ansible.builtin.file:
path: /tmp/spoa-modsecurity
state: absent

View File

@ -0,0 +1,435 @@
# ---------------------------------------------------------------
# Core ModSecurity Rule Set ver.2.2.9
# Copyright (C) 2006-2012 Trustwave All rights reserved.
#
# The OWASP ModSecurity Core Rule Set is distributed under
# Apache Software License (ASL) version 2
# Please see the enclosed LICENCE file for full details.
# ---------------------------------------------------------------
#
# -- [[ Recommended Base Configuration ]] -------------------------------------------------
#
# The configuration directives/settings in this file are used to control
# the OWASP ModSecurity CRS. These settings do **NOT** configure the main
# ModSecurity settings such as:
#
# - SecRuleEngine
# - SecRequestBodyAccess
# - SecAuditEngine
# - SecDebugLog
#
# You should use the modsecurity.conf-recommended file that comes with the
# ModSecurity source code archive.
#
# Ref: https://github.com/SpiderLabs/ModSecurity/blob/master/modsecurity.conf-recommended
#
#
# -- [[ Rule Version ]] -------------------------------------------------------------------
#
# Rule version data is added to the "Producer" line of Section H of the Audit log:
#
# - Producer: ModSecurity for Apache/2.7.0-rc1 (http://www.modsecurity.org/); OWASP_CRS/2.2.4.
#
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecComponentSignature
#
SecComponentSignature "OWASP_CRS/2.2.9"
#
# -- [[ Modes of Operation: Self-Contained vs. Collaborative Detection ]] -----------------
#
# Each detection rule uses the "block" action which will inherit the SecDefaultAction
# specified below. Your settings here will determine which mode of operation you use.
#
# -- [[ Self-Contained Mode ]] --
# Rules inherit the "deny" disruptive action. The first rule that matches will block.
#
# -- [[ Collaborative Detection Mode ]] --
# This is a "delayed blocking" mode of operation where each matching rule will inherit
# the "pass" action and will only contribute to anomaly scores. Transactional blocking
# can be applied
#
# -- [[ Alert Logging Control ]] --
# You have three options -
#
# - To log to both the Apache error_log and ModSecurity audit_log file use: "log"
# - To log *only* to the ModSecurity audit_log file use: "nolog,auditlog"
# - To log *only* to the Apache error_log file use: "log,noauditlog"
#
# Ref: http://blog.spiderlabs.com/2010/11/advanced-topic-of-the-week-traditional-vs-anomaly-scoring-detection-modes.html
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecDefaultAction
#
SecDefaultAction "phase:1,deny,log"
SecDefaultAction "phase:2,deny,log"
#
# -- [[ Collaborative Detection Severity Levels ]] ----------------------------------------
#
# These are the default scoring points for each severity level. You may
# adjust these to you liking. These settings will be used in macro expansion
# in the rules to increment the anomaly scores when rules match.
#
# These are the default Severity ratings (with anomaly scores) of the individual rules -
#
# - 2: Critical - Anomaly Score of 5.
# Is the highest severity level possible without correlation. It is
# normally generated by the web attack rules (40 level files).
# - 3: Error - Anomaly Score of 4.
# Is generated mostly from outbound leakage rules (50 level files).
# - 4: Warning - Anomaly Score of 3.
# Is generated by malicious client rules (35 level files).
# - 5: Notice - Anomaly Score of 2.
# Is generated by the Protocol policy and anomaly files.
#
SecAction \
"id:'900001', \
phase:1, \
t:none, \
setvar:tx.critical_anomaly_score=5, \
setvar:tx.error_anomaly_score=4, \
setvar:tx.warning_anomaly_score=3, \
setvar:tx.notice_anomaly_score=2, \
nolog, \
pass"
#
# -- [[ Collaborative Detection Scoring Initialization and Threshold Levels ]] ------------------------------
#
# These variables are used in macro expansion in the 49 inbound blocking and 59
# outbound blocking files.
#
# **MUST HAVE** ModSecurity v2.5.12 or higher to use macro expansion in numeric
# operators. If you have an earlier version, edit the 49/59 files directly to
# set the appropriate anomaly score levels.
#
# You should set the score level (rule 900003) to the proper threshold you
# would prefer. If set to "5" it will work similarly to previous Mod CRS rules
# and will create an event in the error_log file if there are any rules that
# match. If you would like to lessen the number of events generated in the
# error_log file, you should increase the anomaly score threshold to something
# like "20". This would only generate an event in the error_log file if there
# are multiple lower severity rule matches or if any 1 higher severity item matches.
#
SecAction \
"id:'900002', \
phase:1, \
t:none, \
setvar:tx.anomaly_score=0, \
setvar:tx.sql_injection_score=0, \
setvar:tx.xss_score=0, \
setvar:tx.inbound_anomaly_score=0, \
setvar:tx.outbound_anomaly_score=0, \
nolog, \
pass"
SecAction \
"id:'900003', \
phase:1, \
t:none, \
setvar:tx.inbound_anomaly_score_level=5, \
setvar:tx.outbound_anomaly_score_level=4, \
nolog, \
pass"
#
# -- [[ Collaborative Detection Blocking ]] -----------------------------------------------
#
# This is a collaborative detection mode where each rule will increment an overall
# anomaly score for the transaction. The scores are then evaluated in the following files:
#
# Inbound anomaly score - checked in the modsecurity_crs_49_inbound_blocking.conf file
# Outbound anomaly score - checked in the modsecurity_crs_59_outbound_blocking.conf file
#
# If you want to use anomaly scoring mode, then uncomment this line.
#
SecAction \
"id:'900004', \
phase:1, \
t:none, \
setvar:tx.anomaly_score_blocking=on, \
nolog, \
pass"
#
# -- [[ GeoIP Database ]] -----------------------------------------------------------------
#
# There are some rulesets that need to inspect the GEO data of the REMOTE_ADDR data.
#
# You must first download the MaxMind GeoIP Lite City DB -
#
# http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
#
# You then need to define the proper path for the SecGeoLookupDb directive
#
# Ref: http://blog.spiderlabs.com/2010/10/detecting-malice-with-modsecurity-geolocation-data.html
# Ref: http://blog.spiderlabs.com/2010/11/detecting-malice-with-modsecurity-ip-forensics.html
#
#SecGeoLookupDb /opt/modsecurity/lib/GeoLiteCity.dat
#
# -- [[ Regression Testing Mode ]] --------------------------------------------------------
#
# If you are going to run the regression testing mode, you should uncomment the
# following rule. It will enable DetectionOnly mode for the SecRuleEngine and
# will enable Response Header tagging so that the client testing script can see
# which rule IDs have matched.
#
# You must specify the your source IP address where you will be running the tests
# from.
#
#SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \
"id:'900005', \
phase:1, \
t:none, \
ctl:ruleEngine=DetectionOnly, \
setvar:tx.regression_testing=1, \
nolog, \
pass"
#
# -- [[ HTTP Policy Settings ]] ----------------------------------------------------------
#
# Set the following policy settings here and they will be propagated to the 23 rules
# file (modsecurity_common_23_request_limits.conf) by using macro expansion.
# If you run into false positives, you can adjust the settings here.
#
# Only the max number of args is uncommented by default as there are a high rate
# of false positives. Uncomment the items you wish to set.
#
#
# -- Maximum number of arguments in request limited
SecAction \
"id:'900006', \
phase:1, \
t:none, \
setvar:tx.max_num_args=255, \
nolog, \
pass"
#
# -- Limit argument name length
SecAction \
"id:'900007', \
phase:1, \
t:none, \
setvar:tx.arg_name_length=100, \
nolog, \
pass"
#
# -- Limit value name length
SecAction \
"id:'900008', \
phase:1, \
t:none, \
setvar:tx.arg_length=400, \
nolog, \
pass"
#
# -- Limit arguments total length
SecAction \
"id:'900009', \
phase:1, \
t:none, \
setvar:tx.total_arg_length=64000, \
nolog, \
pass"
#
# -- Individual file size is limited
SecAction \
"id:'900010', \
phase:1, \
t:none, \
setvar:tx.max_file_size=1048576, \
nolog, \
pass"
#
# -- Combined file size is limited
SecAction \
"id:'900011', \
phase:1, \
t:none, \
setvar:tx.combined_file_sizes=1048576, \
nolog, \
pass"
#
# Set the following policy settings here and they will be propagated to the 30 rules
# file (modsecurity_crs_30_http_policy.conf) by using macro expansion.
# If you run into false positves, you can adjust the settings here.
#
SecAction \
"id:'900012', \
phase:1, \
t:none, \
setvar:'tx.allowed_methods=GET HEAD POST OPTIONS', \
setvar:'tx.allowed_request_content_type=application/x-www-form-urlencoded|multipart/form-data|text/xml|application/xml|application/x-amf|application/json', \
setvar:'tx.allowed_http_versions=HTTP/0.9 HTTP/1.0 HTTP/1.1', \
setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/', \
setvar:'tx.restricted_headers=/Proxy-Connection/ /Lock-Token/ /Content-Range/ /Translate/ /via/ /if/', \
nolog, \
pass"
#
# -- [[ Content Security Policy (CSP) Settings ]] -----------------------------------------
#
# The purpose of these settings is to send CSP response headers to
# Mozilla FireFox users so that you can enforce how dynamic content
# is used. CSP usage helps to prevent XSS attacks against your users.
#
# Reference Link:
#
# https://developer.mozilla.org/en/Security/CSP
#
# Uncomment this SecAction line if you want use CSP enforcement.
# You need to set the appropriate directives and settings for your site/domain and
# and activate the CSP file in the experimental_rules directory.
#
# Ref: http://blog.spiderlabs.com/2011/04/modsecurity-advanced-topic-of-the-week-integrating-content-security-policy-csp.html
#
SecAction \
"id:'900013', \
phase:1, \
t:none, \
setvar:tx.csp_report_only=1, \
setvar:tx.csp_report_uri=/csp_violation_report, \
setenv:'csp_policy=allow \'self\'; img-src *.yoursite.com; media-src *.yoursite.com; style-src *.yoursite.com; frame-ancestors *.yoursite.com; script-src *.yoursite.com; report-uri %{tx.csp_report_uri}', \
nolog, \
pass"
#
# -- [[ Brute Force Protection ]] ---------------------------------------------------------
#
# If you are using the Brute Force Protection rule set, then uncomment the following
# lines and set the following variables:
# - Protected URLs: resources to protect (e.g. login pages) - set to your login page
# - Burst Time Slice Interval: time interval window to monitor for bursts
# - Request Threshold: request # threshold to trigger a burst
# - Block Period: temporary block timeout
#
SecAction \
"id:'900014', \
phase:1, \
t:none, \
setvar:'tx.brute_force_protected_urls=#/login.jsp# #/partner_login.php#', \
setvar:'tx.brute_force_burst_time_slice=60', \
setvar:'tx.brute_force_counter_threshold=10', \
setvar:'tx.brute_force_block_timeout=300', \
nolog, \
pass"
#
# -- [[ DoS Protection ]] ----------------------------------------------------------------
#
# If you are using the DoS Protection rule set, then uncomment the following
# lines and set the following variables:
# - Burst Time Slice Interval: time interval window to monitor for bursts
# - Request Threshold: request # threshold to trigger a burst
# - Block Period: temporary block timeout
#
SecAction \
"id:'900015', \
phase:1, \
t:none, \
setvar:'tx.dos_burst_time_slice=60', \
setvar:'tx.dos_counter_threshold=100', \
setvar:'tx.dos_block_timeout=600', \
nolog, \
pass"
#
# -- [[ Check UTF enconding ]] -----------------------------------------------------------
#
# We only want to apply this check if UTF-8 encoding is actually used by the site, otherwise
# it will result in false positives.
#
# Uncomment this line if your site uses UTF8 encoding
SecAction \
"id:'900016', \
phase:1, \
t:none, \
setvar:tx.crs_validate_utf8_encoding=1, \
nolog, \
pass"
#
# -- [[ Enable XML Body Parsing ]] -------------------------------------------------------
#
# The rules in this file will trigger the XML parser upon an XML request
#
# Initiate XML Processor in case of xml content-type
#
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
"id:'900017', \
phase:1, \
t:none,t:lowercase, \
nolog, \
pass, \
chain"
SecRule REQBODY_PROCESSOR "!@streq XML" \
"ctl:requestBodyProcessor=XML"
#
# -- [[ Global and IP Collections ]] -----------------------------------------------------
#
# Create both Global and IP collections for rules to use
# There are some CRS rules that assume that these two collections
# have already been initiated.
#
SecRule REQUEST_HEADERS:User-Agent "^(.*)$" \
"id:'900018', \
phase:1, \
t:none,t:sha1,t:hexEncode, \
setvar:tx.ua_hash=%{matched_var}, \
nolog, \
pass"
SecRule REQUEST_HEADERS:x-forwarded-for "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" \
"id:'900019', \
phase:1, \
t:none, \
capture, \
setvar:tx.real_ip=%{tx.1}, \
nolog, \
pass"
SecRule &TX:REAL_IP "!@eq 0" \
"id:'900020', \
phase:1, \
t:none, \
initcol:global=global, \
initcol:ip=%{tx.real_ip}_%{tx.ua_hash}, \
nolog, \
pass"
SecRule &TX:REAL_IP "@eq 0" \
"id:'900021', \
phase:1, \
t:none, \
initcol:global=global, \
initcol:ip=%{remote_addr}_%{tx.ua_hash}, \
setvar:tx.real_ip=%{remote_addr}, \
nolog, \
pass"

View File

@ -0,0 +1,12 @@
[modsecurity]
spoe-agent modsecurity-agent
messages check-request
option var-prefix modsec
timeout hello 100ms
timeout idle 30s
timeout processing 15ms
use-backend waf
spoe-message check-request
args unique-id method path query req.ver req.hdrs_bin req.body_size req.body
event on-frontend-http-request

View File

@ -0,0 +1,15 @@
[Unit]
Description=HAProxy WAF
After=syslog.target network.target
[Service]
ExecStart={{HAPROXY_PATH}}/waf/bin/modsecurity -n 4 -f {{HAPROXY_PATH}}/waf/modsecurity.conf
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=waf
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,2 @@
if $programname startswith "waf" then /var/log/waf.log
& stop

View File

@ -9,218 +9,42 @@ do
PROXY) PROXY=${VALUE} ;;
VERSION) VERSION=${VALUE} ;;
HAPROXY_PATH) HAPROXY_PATH=${VALUE} ;;
HOST) HOST=${VALUE} ;;
USER) USER=${VALUE} ;;
PASS) PASS=${VALUE} ;;
KEY) KEY=${VALUE} ;;
SSH_PORT) SSH_PORT=${VALUE} ;;
*)
esac
done
VERSION=$(echo 2.1.3| awk -F"-" '{print $1}')
VERSION=$(echo "$VERSION"| awk -F"-" '{print $1}')
VERSION_MAJ=$(echo "$VERSION" | awk -F"." '{print $1"."$2}')
function do_clean() {
sudo rm -f /tmp/modsecurity.tar.gz
sudo rm -rf /tmp/modsecurity
sudo rm -rf /tmp/haproxy-*
sudo rm -f /tmp/modsecurity.conf
sudo rm -f /tmp/owasp.tar.gz
sudo rm -rf /tmp/owasp-modsecurity-crs-2.2.9
}
if (( $(awk 'BEGIN {print ("'$VERSION_MAJ'" < "'1.8'")}') )); then
echo 'error: Need HAProxy version 1.8 or later'
exit 1
fi
if [[ $PROXY != "" ]]
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False
export ACTION_WARNINGS=False
export LOCALHOST_WARNING=False
export COMMAND_WARNINGS=False
PWD=$(pwd)
PWD=$PWD/scripts/ansible/
echo "$HOST ansible_port=$SSH_PORT" > $PWD/$HOST
if [[ $KEY == "" ]]; then
ansible-playbook $PWD/roles/waf.yml -e "ansible_user=$USER ansible_ssh_pass='$PASS' variable_host=$HOST PROXY=$PROXY HAPROXY_PATH=$HAPROXY_PATH VERSION=$VERSION VERSION_MAJ=$VERSION_MAJ SSH_PORT=$SSH_PORT" -i $PWD/$HOST
else
ansible-playbook $PWD/roles/waf.yml --key-file $KEY -e "ansible_user=$USER variable_host=$HOST PROXY=$PROXY HAPROXY_PATH=$HAPROXY_PATH VERSION=$VERSION VERSION_MAJ=$VERSION_MAJ SSH_PORT=$SSH_PORT" -i $PWD/$HOST
fi
if [ $? -gt 0 ]
then
export http_proxy="$PROXY"
export https_proxy="$PROXY"
fi
if [ -f "$HAPROXY_PATH"/waf/modsecurity.conf ];then
echo -e 'info: Haproxy WAF has already installed.'
exit 0
fi
if hash apt-get 2>/dev/null; then
sudo apt install libevent-dev apache2-dev libpcre3-dev libxml2-dev gcc pcre-devel wget libxml2 -y
echo "error: Cannot install WAF"
else
if [[ $(cat /etc/*rele* |grep VERSION_ID |awk -F"\"" '{print $2}') -eq 7 ]]; then
sudo yum install -y http://rpmfind.net/linux/centos/7/os/x86_64/Packages/yajl-devel-2.0.4-4.el7.x86_64.rpm >> /dev/null
sudo yum install -y http://mirror.centos.org/centos/7/os/x86_64/Packages/libevent-devel-2.0.21-4.el7.x86_64.rpm >> /dev/null
else
sudo rpm -ivh ftp://ftp.ntua.gr/pub/linux/centos/8.3.2011/PowerTools/x86_64/kickstart/Packages/yajl-devel-2.1.0-10.el8.x86_64.rpm
fi
sudo yum install -y httpd-devel libxml2-devel gcc curl-devel pcre-devel wget libevent-devel -y >> /dev/null
echo "success"
fi
wget -O /tmp/modsecurity.tar.gz https://www.modsecurity.org/tarball/2.9.2/modsecurity-2.9.2.tar.gz >> /dev/null
if [ $? -eq 1 ]; then
echo -e "Can't download WAF application. Check the Internet connection"
do_clean
exit 1
fi
cd /tmp || exit
sudo tar xf modsecurity.tar.gz
sudo mv modsecurity-2.9.2 modsecurity
sudo bash -c 'cd /tmp/modsecurity && \
sudo ./configure --prefix=/tmp/modsecurity --enable-standalone-module --disable-mlogc --enable-pcre-study --without-lua --enable-pcre-jit >> /dev/null && \
sudo make >> /dev/null && \
sudo make -C standalone install >> /dev/null'
if [ $? -eq 1 ]; then
echo -e "error: Can't compile waf application"
do_clean
exit 1
fi
sudo mkdir -p /tmp/modsecurity/INSTALL/include
sudo cp -R /tmp/modsecurity/standalone/.libs/ /tmp/modsecurity/INSTALL/include
sudo cp -R /tmp/modsecurity/standalone/ /tmp/modsecurity/INSTALL/include
sudo cp -R /tmp/modsecurity/apache2/ /tmp/modsecurity/INSTALL/include
sudo chown -R $(whoami):$(whoami) /tmp/modsecurity/
mv /tmp/modsecurity/INSTALL/include/.libs/* /tmp/modsecurity/INSTALL/include
mv /tmp/modsecurity/INSTALL/include/apache2/* /tmp/modsecurity/INSTALL/include
mv /tmp/modsecurity/INSTALL/include/standalone/* /tmp/modsecurity/INSTALL/include
wget -O /tmp/haproxy-"$VERSION".tar.gz http://www.haproxy.org/download/$VERSION_MAJ/src/haproxy-"$VERSION".tar.gz
if [ $? -eq 1 ]; then
echo -e "error: Can't download Haproxy application. Check the Internet connection"
do_clean
exit 1
fi
cd /tmp || exit
sudo tar xf /tmp/haproxy-"$VERSION".tar.gz
sudo mkdir "$HAPROXY_PATH"/waf
sudo mkdir "$HAPROXY_PATH"/waf/bin
sudo mkdir "$HAPROXY_PATH"/waf/rules
cd /tmp/haproxy-"$VERSION"/contrib/modsecurity || exit
if hash apt-get 2>/dev/null; then
sudo make MODSEC_INC=/tmp/modsecurity/INSTALL/include MODSEC_LIB=/tmp/modsecurity/INSTALL/include APR_INC=/usr/include/apr-1 >> /dev/null
else
sudo make MODSEC_INC=/tmp/modsecurity/INSTALL/include MODSEC_LIB=/tmp/modsecurity/INSTALL/include APACHE2_INC=/usr/include/httpd/ APR_INC=/usr/include/apr-1 >> /dev/null
fi
if [ $? -eq 1 ]; then
echo -e "error: Can't compile WAF application"
do_clean
exit 1
fi
sudo mv /tmp/haproxy-"$VERSION"/contrib/modsecurity/modsecurity "$HAPROXY_PATH"/waf/bin
if [ $? -eq 1 ]; then
echo -e "error: Can't compile WAF application"
do_clean
exit 1
fi
wget -O /tmp/modsecurity.conf https://github.com/SpiderLabs/ModSecurity/raw/v2/master/modsecurity.conf-recommended
sudo bash -c cat << EOF >> /tmp/modsecurity.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_10_ignore_static.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_10_setup.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_11_avs_traffic.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_11_brute_force.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_11_dos_protection.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_13_xml_enabler.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_16_authentication_tracking.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_16_scanner_integration.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_16_username_tracking.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_16_username_tracking.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_20_protocol_violations.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_21_protocol_anomalies.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_23_request_limits.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_25_cc_known.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_25_cc_track_pan.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_30_http_policy.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_35_bad_robots.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_40_generic_attacks.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_40_http_parameter_pollution.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_41_sql_injection_attacks.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_41_xss_attacks.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_42_comment_spam.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_42_tight_security.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_45_trojans.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_46_av_scanning.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_46_scanner_integration.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_46_slr_et_xss_attacks.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_46_slr_et_lfi_attacks.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_46_slr_et_sqli_attacks.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_47_common_exceptions.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_49_inbound_blocking.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_50_outbound.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_55_marketing.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_56_pvi_checks.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_59_outbound_blocking.conf
Include $HAPROXY_PATH/waf/rules/modsecurity_crs_60_correlation.conf
EOF
sudo mv /tmp/modsecurity.conf "$HAPROXY_PATH"/waf/modsecurity.conf
wget -O /tmp/unicode.mapping https://github.com/SpiderLabs/ModSecurity/raw/v2/master/unicode.mapping
sudo mv /tmp/unicode.mapping "$HAPROXY_PATH"/waf/unicode.mapping
wget -O /tmp/owasp.tar.gz https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/2.2.9.tar.gz
cd /tmp/ || exit
sudo tar xf /tmp/owasp.tar.gz
sudo mv /tmp/owasp-modsecurity-crs-2.2.9/modsecurity_crs_10_setup.conf.example $HAPROXY_PATH/waf/rules/modsecurity_crs_10_setup.conf
sudo mv /tmp/owasp-modsecurity-crs-2.2.9/*rules/* "$HAPROXY_PATH"/waf/rules/
sudo sed -i 's/#SecAction/SecAction/' "$HAPROXY_PATH"/waf/rules/modsecurity_crs_10_setup.conf
sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' "$HAPROXY_PATH"/waf/modsecurity.conf
sudo sed -i 's/SecAuditLogParts ABIJDEFHZ/SecAuditLogParts ABIJDEH/' "$HAPROXY_PATH"/waf/modsecurity.conf
sudo bash -c cat << EOF > /tmp/waf.service
[Unit]
Description=Haproxy WAF
After=syslog.target network.target
[Service]
ExecStart=$HAPROXY_PATH/waf/bin/modsecurity -n 4 -f $HAPROXY_PATH/waf/modsecurity.conf
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=waf
[Install]
WantedBy=multi-user.target
EOF
sudo mv /tmp/waf.service /etc/systemd/system/waf.service
sudo bash -c 'cat << EOF > /etc/rsyslog.d/waf.conf
if $programname startswith "waf" then /var/log/waf.log
& stop
EOF'
sudo bash -c cat << EOF > /tmp/waf.conf
[modsecurity]
spoe-agent modsecurity-agent
messages check-request
option var-prefix modsec
timeout hello 100ms
timeout idle 30s
timeout processing 15ms
use-backend waf
spoe-message check-request
args unique-id method path query req.ver req.hdrs_bin req.body_size req.body
event on-frontend-http-request
EOF
sudo mv /tmp/waf.conf "$HAPROXY_PATH"/waf.conf
if sudo grep -q "backend waf" "$HAPROXY_PATH"/haproxy.cfg; then
echo -e "Backend for WAF exists"
else
sudo bash -c 'cat << EOF >> /etc/haproxy/haproxy.cfg
backend waf
mode tcp
timeout connect 5s
timeout server 3m
server waf 127.0.0.1:12345 check
EOF'
fi
do_clean
sudo systemctl daemon-reload
sudo systemctl enable waf
sudo systemctl restart waf
if [ $? -eq 1 ]; then
echo "error: Can't start Haproxy WAF service"
exit 1
fi
echo "success"
rm -f $PWD/$HOST

View File

@ -1,74 +1,67 @@
{% set waf_modes = [] %}
{% do waf_modes.append("On") %}
{% do waf_modes.append("Off") %}
{% do waf_modes.append("DetectionOnly") %}
{% for service in service_status %}
{% if service.3 == "On" or service.3 == "Off" or service.3 == "DetectionOnly" %}
<td class="padding10 first-collumn-wi">
{% if service.2|int() >= 1 %}
<span class="serverUp server-status" title="running {{service.2 }} processes"></span>
{% else %}
<span class="serverDown server-status"></span>
{% endif %}
<a href="/app/logs.py?serv={{ service.1 }}&rows=10&grep=&hour=00&minut=00&hour1=24&minut1=00&waf=1" title="View {{service.0 }}'s WAF logs" class="logs_link">
{{ service.0 }}
</a>
</td>
<td>
{% if role <= 2 %}
<a id="{{ service.1 }}" class="start-waf" title="Start WAF service">
<span class="service-start" onclick="confirmAjaxAction('start', 'waf', '{{service.1}}')"></span>
</a>
<a id="{{ service.1 }}" class="stop-waf" title="Stop WAF service">
<span class="service-stop" onclick="confirmAjaxAction('stop', 'waf', '{{service.1}}')"></span>
</a>
<a id="{{ service.1 }}" class="restart-waf" title="Restart WAF service">
<span class="service-reload" onclick="confirmAjaxAction('restart', 'restart', '{{service.1}}')"></span>
</a>
{% endif %}
</td>
<td>
{% if role <= 2 %}
{% if service.3 == "On" or service.3 == "Off" or service.3 == "DetectionOnly" %}
<select class="waf_mode" id="{{ service.0 }}_select">
{% set waf_modes = [] %}
{% do waf_modes.append("On") %}
{% do waf_modes.append("Off") %}
{% do waf_modes.append("DetectionOnly") %}
{% for waf_mode in waf_modes %}
{% if service.3 == waf_mode %}
<option value={{waf_mode}} selected="selected">{{waf_mode}}</option>
{% else %}
<option value={{waf_mode}}>{{waf_mode}}</option>
{% endif %}
{% endfor %}
</select>
{%else %}
<a title="Install WAF"><button onclick="installWaf('{{ service.1 }}')">Install</button></a>
{% endif %}
{% else %}
{{ service.3 }}
{% endif %}
</td>
<td style="padding-top: 2px;" class="ajaxwafstatus">
{% if service.3 == "On" or service.3 == "Off" or service.3 == "DetectionOnly" %}
{% if service.4|int() == 1 %}
<label for="metrics{{ service.0 }}"></label><input type="checkbox" id="metrics{{ service.0 }}" checked />
{% else %}
<label for="metrics{{ service.0 }}"></label><input type="checkbox" id="metrics{{ service.0 }}" />
{% endif %}
{% endif %}
</td>
<td>
{% if role <= 2 %}
{% if service.3 == "On" or service.3 == "Off" or service.3 == "DetectionOnly" %}
<a href="/app/waf.py?manage_rules=1&serv={{service.1}}" class="ui-button ui-widget ui-corner-all">Open</a>
{% endif %}
{% endif %}
</td>
<td></td>
<td class="padding10 first-collumn-wi">
{% if service.5|int() >= 1 %}
{% if service.2|int() >= 1 %}
<span class="serverUp server-status" title="running {{service.2 }} processes"></span>
{% else %}
<span class="serverDown server-status" title="WAF is stopped"></span>
{% endif %}
<a href="/app/logs.py?serv={{ service.1 }}&rows=10&grep=&hour=00&minut=00&hour1=24&minut1=00&waf=1" title="View {{service.0 }}'s WAF logs" class="logs_link">
{{ service.0 }}
</a>
{% else %}
<td class="padding10 first-collumn-wi">
<span class="serverDown server-status"></span> {{ service.0 }}
</td>
{% if role <= 2 %}
<span class="serverNone server-status" title="WAF is not installed"></span> <span title="WAF is not installed">{{ service.0 }}</span>
{% endif %}
</td>
{% if service.3 == "On" or service.3 == "Off" or service.3 == "DetectionOnly" %}
<td>
{% if role <= 2 %}
<a id="{{ service.1 }}" class="start-waf" title="Start WAF service">
<span class="service-start" onclick="confirmAjaxAction('start', 'waf', '{{service.1}}')"></span>
</a>
<a id="{{ service.1 }}" class="stop-waf" title="Stop WAF service">
<span class="service-stop" onclick="confirmAjaxAction('stop', 'waf', '{{service.1}}')"></span>
</a>
<a id="{{ service.1 }}" class="restart-waf" title="Restart WAF service">
<span class="service-reload" onclick="confirmAjaxAction('restart', 'restart', '{{service.1}}')"></span>
</a>
{% endif %}
</td>
<td>
{% if role <= 2 %}
<select class="waf_mode" id="{{ service.0 }}_select">
{% for waf_mode in waf_modes %}
{% if service.3 == waf_mode %}
<option value={{waf_mode}} selected="selected">{{waf_mode}}</option>
{% else %}
<option value={{waf_mode}}>{{waf_mode}}</option>
{% endif %}
{% endfor %}
</select>
{% else %}
{{ service.3 }}
{% endif %}
</td>
<td style="padding-top: 2px;" class="ajaxwafstatus">
{% if service.4|int() == 1 %}
<label for="metrics{{ service.0 }}"></label><input type="checkbox" id="metrics{{ service.0 }}" checked />
{% else %}
<label for="metrics{{ service.0 }}"></label><input type="checkbox" id="metrics{{ service.0 }}" />
{% endif %}
</td>
<td>
{% if role <= 2 %}
<a href="/app/waf.py?manage_rules=1&serv={{service.1}}" class="ui-button ui-widget ui-corner-all">Open</a>
{% endif %}
</td>
<td></td>
{% else %}
{% if role <= 2 %}
<td colspan="5">
<a title="Install WAF"><button onclick="installWaf('{{ service.1 }}')">Install</button></a>
</td>
{% endif %}

View File

@ -8,12 +8,9 @@
<td class="padding10 first-collumn">
Rule name
</td>
<td style="width: 100px;">
Enabled
</td>
<td>
Description
</td>
<td style="width: 100px;">Enabled</td>
<td>Description</td>
<td></td>
</tr>
{% for r in rules %}
<tr class="{{ loop.cycle('odd', 'even') }}" id="rule-{{r.id}}">
@ -27,9 +24,44 @@
{% endif %}
</td>
<td style="padding-top: 5px;padding-bottom: 10px;">{{r.desc}}</td>
<td style="padding: 0 10px 0 10px;">
<a href="waf.py?waf_rule_id={{r.id}}&serv={{serv}}" class="ui-button ui-widget ui-corner-all" title="View this rule versions">View</a>
</td>
</tr>
{% endfor %}
</table>
{% elif waf_rule_file %}
<center>
<link rel="stylesheet" href="/inc/codemirror/codemirror.css">
<script src="/inc/codemirror/codemirror.js"></script>
<script src="/inc/codemirror/modsec.js"></script>
<h4>Config {{waf_rule_file}} from {{ serv }}</h4>
</center>
<form action="waf.py" name="saveconfig" id="saveconfig" method="post">
<input type="hidden" value="{{ serv }}" name="serv">
<input type="hidden" value="{{ cfg }}.old" name="oldconfig">
<input type="hidden" value="{{ token }}" name="token">
<input type="hidden" value="{{ service }}" name="service">
<div style="margin-left: 20%;width: 60%;">
<textarea name="config" id="config_text_area" class="config" rows="35" cols="100">{{ config }}</textarea>
</div>
<p>
<center>
<a href="waf.py?manage_rules=1&serv={{serv}}" class="ui-button ui-widget ui-corner-all" title="Return to rules management">Back</a>
</center>
</p>
</form>
<style>
.CodeMirror {
line-height: 1.2em;
height: 70%;
}
</style>
<script>
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("config_text_area"),
{mode: "modsec", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true, readOnly: true});
myCodeMirror.refresh();
</script>
{% else %}
<style>
.alert-danger {
@ -44,10 +76,12 @@
var ip = []
var hostnamea = []
{% for s in servers_all %}
{% if s.15|int() == 1 %}
ip.push("{{s[2]}}");
var host = "{{s[2]}}";
host = host.replace(/\./g, '\\.');
hostnamea.push(host);
{% endif %}
{% endfor %}
</script>

View File

@ -7,6 +7,14 @@ template = env.get_template('waf.html')
form = funct.form
manage_rules = form.getvalue('manage_rules')
waf_rule_id = form.getvalue('waf_rule_id')
waf_rule_file = ''
servers_waf = ''
autorefresh = 0
config_read = ''
serv = ''
rules = ''
cfg = ''
print('Content-type: text/html\n')
funct.check_login(service=1)
@ -21,15 +29,26 @@ if manage_rules == '1':
serv = funct.is_ip_or_dns(form.getvalue('serv'))
funct.check_is_server_in_group(serv)
title = "Manage rules - Web application firewall"
servers_waf = ''
autorefresh = 0
rules = sql.select_waf_rules(serv)
elif waf_rule_id:
serv = funct.is_ip_or_dns(form.getvalue('serv'))
funct.check_is_server_in_group(serv)
title = 'Edit a WAF rule'
waf_rule_file = sql.select_waf_rule_by_id(waf_rule_id)
configs_dir = sql.get_setting('tmp_config_path')
cfg = configs_dir + serv + "-" + funct.get_data('config') + "-" + waf_rule_file
error = funct.get_config(serv, cfg, waf=1, waf_rule_file=waf_rule_file)
try:
conf = open(cfg, "r")
config_read = conf.read()
conf.close()
except IOError:
print('Cannot read imported config file')
else:
title = "Web application firewall"
servers_waf = sql.select_waf_servers_metrics(user_id.value)
autorefresh = 1
serv = ''
rules = ''
template = template.render(h2=1, title=title,
autorefresh=autorefresh,
@ -41,5 +60,9 @@ template = template.render(h2=1, title=title,
manage_rules=manage_rules,
rules=rules,
user_services=user_services,
waf_rule_file=waf_rule_file,
waf_rule_id=waf_rule_id,
config=config_read,
cfg=cfg,
token=token)
print(template)

View File

@ -1000,7 +1000,7 @@ $( function() {
}
});
var add_server_var = '<br /><input name="servers" title="Backend IP" size=14 placeholder="xxx.xxx.xxx.xxx" class="form-control second-server">: ' +
'<input name="server_port" required title="Backend port" size=3 placeholder="yyy" class="form-control second-server add_server_number" type="number">' +
'<input name="server_port" required title="Backend port" size=3 placeholder="yyy" class="form-control second-server add_server_number" type="number"> ' +
'<input name="server_maxconn" required title="Maxconn. Default 200" size=5 value="200" class="form-control add_server_number" type="number">'
$('[name=add-server-input]').click(function() {
$("[name=add_servers]").append(add_server_var);