Thierry FOURNIER | a5ec06d | 2017-04-10 23:47:23 +0200 | [diff] [blame] | 1 | ModSecurity for HAProxy |
| 2 | ----------------------- |
| 3 | |
Ilya Shipitsin | e011bc3 | 2020-03-14 17:47:28 +0500 | [diff] [blame] | 4 | This is a third party daemon which speaks SPOE. It gives requests send by HAProxy |
Thierry FOURNIER | a5ec06d | 2017-04-10 23:47:23 +0200 | [diff] [blame] | 5 | to ModSecurity and returns the verdict. |
| 6 | |
| 7 | Compilation |
| 8 | --------------- |
| 9 | |
| 10 | You must compile ModSecurity in standalone mode. Below an example for |
| 11 | ModSecurity-2.9.1. Note that ModSecurity depends the Apache APR. I assume that |
| 12 | the Apache dependencies are installed on the system. |
| 13 | |
| 14 | ./configure \ |
| 15 | --prefix=$PWD/INSTALL \ |
| 16 | --disable-apache2-module \ |
| 17 | --enable-standalone-module \ |
| 18 | --enable-pcre-study \ |
| 19 | --without-lua \ |
| 20 | --enable-pcre-jit |
| 21 | make |
| 22 | make -C standalone install |
| 23 | mkdir -p $PWD/INSTALL/include |
| 24 | cp standalone/*.h $PWD/INSTALL/include |
| 25 | cp apache2/*.h $PWD/INSTALL/include |
| 26 | |
Ilya Shipitsin | e011bc3 | 2020-03-14 17:47:28 +0500 | [diff] [blame] | 27 | Note that this compilation method works, but is a little bit rustic. I can't |
| 28 | deal with Lua, I supposed that is a dependencies problem on my computer. |
Thierry FOURNIER | a5ec06d | 2017-04-10 23:47:23 +0200 | [diff] [blame] | 29 | |
| 30 | Start the service |
| 31 | --------------------- |
| 32 | |
| 33 | After you have compiled it, to start the service, you just need to use "spoa" |
| 34 | binary: |
| 35 | |
| 36 | $> ./modsecurity -h |
| 37 | Usage: ./spoa [-h] [-d] [-p <port>] [-n <num-workers>] [-f <config-file>] |
| 38 | -h Print this message |
| 39 | -d Enable the debug mode |
| 40 | -f <config-file> Modsecurity configuration file |
| 41 | -m <max-frame-size> Specify the maximum frame size (default : 16384) |
| 42 | -p <port> Specify the port to listen on (default: 12345) |
| 43 | -n <num-workers> Specify the number of workers (default: 5) |
| 44 | -c <capability> Enable the support of the specified capability |
| 45 | -t <time> Set a delay to process a message (default: 0) |
| 46 | The value is specified in milliseconds by default, |
| 47 | but can be in any other unit if the number is suffixed |
| 48 | by a unit (us, ms, s) |
| 49 | |
| 50 | Note: A worker is a thread. |
| 51 | |
| 52 | |
| 53 | Configure a SPOE to use the service |
| 54 | --------------------------------------- |
| 55 | |
| 56 | All information about SPOE configuration can be found in "doc/SPOE.txt". Here is |
| 57 | the configuration template to use for your SPOE with ModSecurity module: |
| 58 | |
| 59 | [modsecurity] |
| 60 | |
| 61 | spoe-agent modsecurity-agent |
| 62 | messages check-request |
| 63 | option var-prefix modsec |
| 64 | timeout hello 100ms |
| 65 | timeout idle 30s |
| 66 | timeout processing 15ms |
| 67 | use-backend spoe-modsecurity |
| 68 | |
| 69 | spoe-message check-request |
| 70 | args unique-id method path query req.ver req.hdrs_bin req.body_size req.body |
| 71 | event on-frontend-http-request |
| 72 | |
| 73 | The engine is in the scope "modsecurity". So to enable it, you must set the |
| 74 | following line in a frontend/listener section: |
| 75 | |
| 76 | frontend my-front |
| 77 | ... |
| 78 | filter spoe engine modsecurity config spoe-modsecurity.conf |
| 79 | ... |
| 80 | |
| 81 | |
| 82 | Because, in SPOE configuration file, we declare to use the backend |
| 83 | "spoe-modsecurity" to communicate with the service, you must define it in |
| 84 | HAProxy configuration. For example: |
| 85 | |
| 86 | backend spoe-modsecurity |
| 87 | mode tcp |
| 88 | balance roundrobin |
| 89 | timeout connect 5s |
| 90 | timeout server 3m |
Yann Cézard | 494ddbf | 2019-04-25 14:48:38 +0200 | [diff] [blame] | 91 | server modsec1 127.0.0.1:12345 |
Thierry FOURNIER | a5ec06d | 2017-04-10 23:47:23 +0200 | [diff] [blame] | 92 | |
| 93 | The modsecurity action is returned in a variable called txn.modsec.code. It |
| 94 | contains the HTTP returned code. If the variable contains 0, the request is |
| 95 | clean. |
| 96 | |
Yann Cézard | 494ddbf | 2019-04-25 14:48:38 +0200 | [diff] [blame] | 97 | http-request deny if { var(txn.modsec.code) -m int gt 0 } |
Thierry FOURNIER | a5ec06d | 2017-04-10 23:47:23 +0200 | [diff] [blame] | 98 | |
Yann Cézard | 494ddbf | 2019-04-25 14:48:38 +0200 | [diff] [blame] | 99 | With this rule, all the request not clean are rejected. |
Thierry FOURNIER | a5ec06d | 2017-04-10 23:47:23 +0200 | [diff] [blame] | 100 | |
| 101 | |
| 102 | Known bugs, limitations and TODO list |
| 103 | ----------------------------------------- |
| 104 | |
| 105 | Modsecurity bugs: |
| 106 | ----------------- |
| 107 | |
| 108 | * When the audit_log is used with the directive "SecAuditLogType Serial", in |
| 109 | some systems, the APR mutex initialisation silently fails, this causes a |
| 110 | segmentation fault. For my own usage, I have a patched version of modsec where |
| 111 | I use another mutex than "APR_LOCK_DEFAULT" like "APR_LOCK_PROC_PTHREAD" |
| 112 | |
| 113 | - rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_DEFAULT, mp); |
| 114 | + rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_PROC_PTHREAD, mp); |
| 115 | |
Ilya Shipitsin | e011bc3 | 2020-03-14 17:47:28 +0500 | [diff] [blame] | 116 | * Configuration file loaded with wildcard (eg. Include rules/*.conf), are loaded |
Thierry FOURNIER | a5ec06d | 2017-04-10 23:47:23 +0200 | [diff] [blame] | 117 | in reverse alphabetical order. You can found a patch below. The ModSecurity |
| 118 | team ignored this patch. |
| 119 | |
| 120 | https://github.com/SpiderLabs/ModSecurity/issues/1285 |
| 121 | http://www.arpalert.org/0001-Fix-bug-when-load-files.patch |
| 122 | |
| 123 | Or insert includes without wildcards. |
| 124 | |
| 125 | Todo: |
| 126 | ----- |
| 127 | |
| 128 | * Clarify the partial body analysis. |
| 129 | * The response body is not yet analyzed. |
| 130 | * ModSecurity can't modify the response body. |
| 131 | * Implements real log management. Actually, the log are sent on stderr. |
| 132 | * Implements daemon things (forks, write a pid, etc.). |