Implementing Python Scripts

You can create Python scripts to expand the scope of vWAF to suit your specific requirements. This provides additional options and flexibility for administrators with Python scripting experience to expand the functionality of the included handlers.

To create and apply scripts:

  • Using the script editor, create the required script(s). Each script is added to the script library (the script library hosts all configured scripts at the application level)
  • Using the script library, sort the scripts to determine the order in which they run.
  • Using the script handler, enable the required scripts for the application and each path, as needed.

Scripts can include all basic Python operators plus additional modules and functions. For details of the supported modules and functions, see Accessible Python Modules and Functions.

Script Editor

You create and edit scripts using the script editor. The editor checks the syntax and highlights issues as you enter your script. For each script you can add the following 'parts':

  • Init

    executed during the script handler initialization phase. These are typically significant set up tasks, for example.

  • Request

    executed during the Script Handler request.

  • Response

    executed during the Script Handler response.

Script Library

The scripts you create are saved in a script library. Scripts can be enabled at the application level and to relevant paths, as needed. The script library allows you to specify the order in which scripts are executed.

Script Handler

The script handler executes the scripts. You configure the script handler for each application and path, as needed, to enable the required scripts. The scripts available for the application are stored in the script library.

A selection of example scripts are included below.

Creating scripts

To create a script.

  1. To start the script editor, from the Application Control menu select the required application and click the Script Library tab.
    The Script Library appears.

    This example shows an empty script library. If any scripts were created previously, they appear in the list.
  2. In the Add new script field, enter the name for your script and click Create.
    The script editor appears.
    Your script can include several parts including Init, Request and Response. Click the relevant part to expand the section and to create the necessary script. This example shows the script editor with the Init part expanded.

  3. Create your script. vWAF automatically checks the syntax of the script. Should there be any syntax errors, the input field turns red and vWAF tells you which line the error is in.
    You also set the appropriate 'response mode' for the script, using the drop-down menu, to determine how response handling is implemented:
    • No response handling - no response handling. In this mode, calling any filter_response_* functions in the request script has no effect (no exception is raised). In this mode the response section is not accessible.
    • Response header handling - the relevant response script is called with the response headers only (no access to the body). In this mode, calling any filter_response_* functions in the request script has no effect (no exception is raised). In this part you can manipulate headers (for example, add a custom header); any manipulation on the body has no effect.
    • Response body handling - the relevant response script is called with the full response (headers and body). In this mode, it is possible to provide the script with a list of content types (comma separated strings) to handle; only responses with a matching content-type are handled. Calling any filter_response_* functions in the request script has no effect (no exception is raised). This part allows you to manipulate both headers and the body.
    • Script based handling - In this mode, any filter_response_* functions in the script are handled based on the script logic (the script determines if and how response handling is enabled). This is intended for legacy scripts, created before the script editor providing the ability to create scripts with separate parts was released.
    Use the Comment option to add comments, as needed.
  4. Click Save.
  5. Commit the change.
The script is added to the script library.

Repeat the process to add further scripts.

Managing scripts in the script library

Scripts you create are stored in the script library. You can enable any or all of the scripts for your application and appropriate paths. The scripts in the library are available to any path.

Scripts are executed in the order in which they are sorted. You can change the order of the scripts by clicking the relevant up or down icon.

To edit a script, click the edit icon.

To delete a script, click the delete icon.

If you edit or delete a script, commit the change.

Enabling scripts

You apply the required scripts to your application and application paths as needed.

  1. Navigate to the required application (and path, if necessary).
  2. If not configured previously, add the Script Handler (from the Handler Templates tab, select Script Handler from the Add Handler menu).
  3. Click the Script Handler edit icon The Script Handler screen appears.
  4. Enable the required scripts. In this example, Script 1 and Script 2 are enabled.

  5. Click Save.
  6. Commit the change.

The scripts are enabled and executed in the order specified.

Example Scripts

This section provides a selection of example scripts.

Example script: Add content to end of page

The following simple example script adds some own content (e.g. a company logo) to the end of each page:

if http.is_request(): http.filter_response_full() else: ct = http.get_response_header("content-type") if ct and ct.split(';')[0].lower() == "text/html": body = http.get_response_body() if len(body) > 0: try: idx = body.upper().index("</BODY>") newbody = [] newbody.append(body[:idx]) newbody.append("<BR/><IMG SRC='logo.gif'/></BODY>") newbody.append(body[idx+len("</BODY>"):]) http.set_response_body("".join(newbody)) except ValueError: http.log("no closing html body tag found")

Example script: Call server scripts based on request URL

The following script takes the request URI (e.g. /image/mandelbrot1.gif) and translates it to /image_handler.php with the subpath argument set to the rest of the URI (e.g. /mandelbrot1.gif):

if http.is_request(): uri = http.get_request_uri() path = [ s for s in uri.split('/') if len(s) > 0 ] if len(path) > 0: uri = "/%s_handler.php" % path[0] subpath = '/' if len(path) > 1: subpath += '/'.join(path[1:]) http.set_request_uri(uri,[("subpath",subpath)])

Example script: checking and setting a cookie

The following script retrieves a cookie given in a request. If the cookie isn’t valid in the session, the script redirects to a given URL. If no cookie has been given at all, the script generates and sets a random response cookie.

if http.is_request(): s = http.get_storage() c = http.get_request_cookie('MYVALIDATOR') if 'MYVALIDATOR' in s: if s['MYVALIDATOR'] != c: http.log('found session with invalid validator') http.redirect('/') elif c: s['MYVALIDATOR'] = c else: s['MYVALIDATOR'] = http.make_random_cookie() http.set_response_cookie('MYVALIDATOR', s['MYVALIDATOR'])

Example script: adding an IP address to the global IP blacklist

If a user calls the URL /honeypot, the following script adds the IP address of the request to the global IP blacklist for a duration of 5 minutes (300 seconds).

if http.is_request() and http.get_url() == "/honeypot": ip = http.get_client_ip() http.generate_blacklist_event(ip, 300)

Example scripts: Validating XML

The following is a simple example of how to verify some incoming XML requests against a given XML Schema:

xml_schema_string = ''' ... ''' if http.is_request() and http.get_request_method() == 'POST' and http.get_request_header('content-type').lower() == 'text/xml': xml_body = str(http.get_request_body()).strip() xml = lxml_etree.parse(StringIO(xml_body)) xml_schema = lxml_etree.XMLSchema(lxml_etree.parse (StringIO(xml_schema_string.strip()))) if not xml_schema.validate(xml): http.log("xml request does not match schema") http.set_returncode(403)

The following example validates the XML against a defined XML DTD. If the XML is valid, the script writes the value true to the vWAF Log Files.

xml_string = '''<?xml version="1.0" encoding="ISO-8859-1"?> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note>'''; dtd_string = '''<!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)><!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)><!ELEMENT body (#PCDATA)>''' xml = lxml_etree.XML(xml_string) dtd_io = StringIO(dtd_string) dtd = lxml_etree.DTD(dtd_io) http.log(str(dtd.validate(xml)))

The following example validates the XML against a given XML Schema file. If the XML is valid, the script writes the value true to the vWAF Log Files.

xml_string = '''<?xml version="1.0" encoding="ISO-8859-1"?> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note>'''; schema_string = '''<xsd:schema xmlns:xsd="http://www.w3.org/ 2001/XMLSchema"> <xsd:element name="note" type="noteType"/> <xsd:complexType name="noteType"> <xsd:sequence> <xsd:element name="to" type="xsd:string" /> <xsd:element name="from" type="xsd:string" /> <xsd:element name="heading" type="xsd:string" /> <xsd:element name="body" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:schema>''' xml_io = StringIO(xml_string) schema_io = StringIO(schema_string) schema_doc = lxml_etree.parse(schema_io) schema = lxml_etree.XMLSchema(schema_doc) xml_doc = lxml_etree.parse(xml_io) http.log(str(schema.validate(xml_doc)))