Framework for Testing WAFs (FTW!)
This project was created by researchers from ModSecurity and Fastly to help provide rigorous tests for WAF rules. It uses the OWASP Core Ruleset V3 as a baseline to test rules on a WAF. Each rule from the ruleset is loaded into a YAML file that issues HTTP requests that will trigger these rules.
Goals / Use cases include:
git clone [email protected]:fastly/ftw.git
cd ftw
apt-get install python-pip
pip install -r requirements.txt
py.test test/test_default.py --ruledir test/yaml
If you require an environment for testing WAF rules, there has been one created with Apache, Modsecurity and version 3.0.0 of the OWASP core ruleset. This can be deployed by:
git clone https://github.com/fastly/waf_testbed.git
vagrant up
py.test test/test_default.py --ruledir=test/yaml --destaddr=domain.com --port 443 --protocol https
py.test test/integration/test_logcontains.py -s --ruledir=test/integration/
*.pyfile with the necessary imports, an example is shown in
test/integration/test_logcontains.py
test*in the beginning will be ran by
py.test, so make a function
def test_somewaf
LogChecker
get_logs()function. FTW will call this function after it runs the test, and it will set datetimes of
self.startand
self.end
get_logs()
py.test fixtures. Use a function decorator
@pytest.fixture, return your new
LogCheckerobject. Whenever you use a function argument in your tests that matches the name of that
@pytest.fixture, it will instantiate your object and make it easier to run tests. An example of this is in the python file from step 1.
*.yamlformat as seen in
test/integration/LOGCONTAINSFIXTURE.yaml, the
log_containsline requires a string that is a regex. FTW will compile the
log_containsstring from each stage in the YAML file into a regex. This regex will then be used alongside the lines of logs passed in from
get_logs()to look for a match. The
log_containsstring, then, should be a unique rule-id as FTW is greedy and will pass on the first match. False positives are mitigated from the start/end time passed to the
LogCheckerobject, but it is best to stay safe and use unique regexes.
get_logs()function is called, so be sure to account for API calls if thats how you retrieve your logs.
Although it is preferred to make requests using the YAML format, often automated tests require making many dynamic requests. In such a case it is recommended to make use of the py.test framework in order to produce test cases that can be run as part of the whole. Generally making an HTTP request is simple: 1. create an instance of the
HttpUA()class 2. create an instance of the
Input()class providing whatever parameters you don\'t want to be defaulted 3. provide the instance of the input class to
HttpUA.send_request()
For some examples see the http integration tests