Preview #
About #
GraffitiFirewall is a Web Application Firewall for Xojo Web apps. It’s as fast as lightning and scans each incoming connection nearly instantaneously against a list of more than 30,000 criteria. It includes a guided setup wizard and intuitive dashboard. It can go everywhere your app can go and can help provide security from:
- Known Malicious IPs
- Known Malicious UserAgents
- Known Malicious Referrers
- Local File Inclusions
- Cross Site Scripting
- SQL Injections
- Crawlers
- Direct Denial of Service attacks
- Login or sensitive action Security via custom event tracking
- Custom blocklists for IPs or UserAgents with expiration
Security features include:
- Time-base One-Time Password (TOTP) login
- Encrypted Database
- Managed and curated definition updates
Enumerations #
Name | Values |
---|---|
EvaluationTypes | All LocalFileInclusion CrossSiteScripting SQLInjection |
HTTPSecurityModes | Off Block RedirectTemporary RedirectPermanent |
Constants #
This class exposes no constants.
Events #
This class exposes no events.
Methods #
This class exposes no methods.
Shared Methods #
Name | Parameters | Return Value | Description |
---|---|---|---|
Block | instance as GraffitiFirewallBlock | None | Blocks the address identified by the GraffitiFirewallBlock object. |
CountEvents | identifier as String type as Integer | Integer | Counts the matching events for the identifier (typically an IP Address) that have been added using RegisterEvents which have not yet expired. Type values of 0 and 1 are reserved. |
CountEvents | request as WebRequest type as Integer | Integer | Counts the matching events for the requesting user that have been added using RegisterEvents which have not yet expired. This is not WebRequest-specific, but uses the WebRequest object to get the information required. Type values of 0 and 1 are reserved. |
CountEvents | session as WebSession type as Integer | Integer | Counts the matching events for the session that have been added using RegisterEvents which have not yet expired. This is not WebSession-specific, but uses the WebSession object to get the information required. Type values of 0 and 1 are reserved. |
DeleteDatabase | None | None | Deletes the database from the system. This should only be used if uninstalling GraffitiFirewall from your application. Once this method is called, all data will be unrecoverable. |
EvaluateConnection | request as WebRequest response as WebResponse | Boolean | Evaluates a WebRequest to determine if the user is potentially malicious. Returns True if an action is taken or False if the request matches none of the criteria to block the connection. |
EvaluateContent | type as EvaluationTypes content as String | Boolean | Evaluates a string of data to scan for potentially malicious data. Useful for checking form data before performing database operations. |
EvaluateEvent | identifier as String type as Integer threshhold as Integer = 0 | Boolean | Returns whether the threshhold for this event type has been exceeded based on the identifier (typically an IP Address). |
EvaluateEvent | request as WebRequest type as Integer threshhold as Integer = 0 | Boolean | Returns whether the threshhold for this event type has been exceeded based on the requesting user. This is not WebRequest-specific, but uses the WebRequest object to get the information required. |
EvaluateEvent | session as WebSession type as Integer threshhold as Integer = 0 | Boolean | Returns whether the threshhold for this event type has been exceeded based on the requesting user. This is not WebSession-specific, but uses the WebSession object to get the information required. |
GeofencingClearCache | None | None | Clears the geofencing cache. Results are cached for 30 days to reduce calls to the third-party API. |
GetBlock | ipaddress as String | GraffitiFirewallBlock | Returns an unexpired block entry, if found, for the ipaddress. |
GetBlock | request as WebRequest | GraffitiFirewallBlock | Returns an unexpired block entry, if found, for the requesting user. This is not WebRequest-specific, but uses the WebRequest object to get the information required. |
GetBlock | session as WebRequest | GraffitiFirewallBlock | Returns an unexpired block entry, if found, for the requesting user. This is not WebSession-specific, but uses the WebSession object to get the information required. |
Instantiate | None | None | Creates a new shared instance of the class and, if not created previously, sets up the basic database configuration. |
LastUpdate | None | DateTime | Returns the last DateTime that the firewall phoned home for updates. |
RebuildDatabase | None | None | Deletes and recreates the database. Useful if you have somehow locked yourself out of the database. Behaves the same as if you’ve deleted the database files on the system then called the Instantiate method. |
RegisterEvent | identifier as String type as Integer comment as String = “” expiresAfterSeconds as Integer = 0 | None | Registers a new event for use with CountEvents and EvaluateEvent. |
RegisterEvent | request as WebRequest type as Integer comment as String = “” expiresAfterSeconds as Integer = 0 | None | Registers a new event for use with CountEvents and EvaluateEvent. |
RegisterEvent | session as WebSession type as Integer comment as String = “” expiresAfterSeconds as Integer = 0 | None | Registers a new event for use with CountEvents and EvaluateEvent. |
Unblock | instance as GraffitiFirewallBlock | None | Removes any matching access blocks based on the criteria specified in the GraffitiFirewallBlock. |
UpdateDatabase | Force as Boolean = False | None | Updates the definitions in the database if the set update frequency has been exceeded or Force = True. It would be most beneficial to setup a path in App.HandleURL that calls this method then create a cronjob to execute it as updates may stall a user connection when an update is due to be performed. |
Properties #
This class exposes no properties.
Shared Properties #
Name | Type | Default Value | Description |
---|---|---|---|
ApplicationName | String | “” | The application name assigned during setup. This value should not be changed as it may invalidate TOTP logins. |
BypassLocal | Boolean | False | Bypasses all checks for connections originating from 127.0.0.1 when True. |
DatabaseSchemaVersion (Read Only) | String | 0 | Schema version of the currently loaded database. |
EnabledOnDebug | Boolean | True | When False, bypasses all checks when running the web application in debug mode. |
GeofencingBlockHosting | Boolean | False | Optionally blocks IP addresses that are known to belong to hosting networks. |
GeofencingBlockMobile | Boolean | False | Optionally blocks IP addresses that are known to belong to mobile networks. |
GeofencingBlockProxy | Boolean | False | Optionally blocks IP addresses that are known proxy nodes. |
GeofencingEnabled | Boolean | False | Enables the geofencing engine. Blocked countries must be set via the dashboard. |
HTTPSecurityMode | HTTPSecurityModes | HTTPSecurityModes.Off | Determines how the firewall handles insecure connections. Should be set to Off if behind a load balancer such as nginx or Apache (or when deployed via Xojo Cloud). |
Lockdown | Boolean | False | Used to lockdown the server and refuse all connections. Can be cleared by setting to True or restarting server app instance. |
ManagementAPIEnabled | Boolean | False | Controls whether the Management API is enabled for using GET requests with query strings to perform maintenance operations such as updates of log truncations. |
ManagementAPIRemoteEnabled | Boolean | False | Controls whether remote networks may be used to initiate calls to the Management API. |
ManagementAPITruncateLogsEnabled | Boolean | False | Controls whether the Management API may be used to truncate logs. |
ManagementAPIUpdateEnabled | Boolean | False | Controls whether the Management API may be used to perform definition updates. |
MaximumCookieSize | Integer | 10240 | Maximum size, in bytes, of all cookie data. |
MaximumCookieSizeEnabled | Boolean | True | Enforces the maximum cookie size when True. |
MaximumPathSize | Integer | 1024 | Maximum size, in bytes, of path data. |
MaximumPathSizeEnabled | Boolean | True | Enforces the maximum path size when True. |
MaximumQuerySize | Integer | 2048 | Maximum size, in bytes, of all query string data. |
MaximumQuerySizeEnabled | Boolean | True | Enforces the maximum query size when True. |
MaximumRequestSize | Integer | 8192 | Maximum size of request body data. |
MaximumRequestSizeEnabled | Boolean | True | Enforces the maximum request size when True. |
OutputDebugMessage | Boolean | False | Replaces the #DEBUG# token in BlockedTemplate for block messages when True. |
RateLimitEnabled | Boolean | True | Applies the rate limit property values to repeated connections when True. |
RateLimitMaxRequests | Integer | 50 | Maximum number of connection attempts allowed within RateLimitPeriod. |
RateLimitMaxPeriod | Integer | 300 | Number of seconds within which connections are counted toward the RateLimitMaximum. |
RateLimitMaxTimeout | Integer | 300 | Number of seconds new connection attempts will be blocked for the affected remote host when they exceed the RateLimitMaximum within RateLimitPeriod. |
RateLimitRejectionCount | Integer | 5 | Number of rejections a single remote client is allowed with the time supplied by RateLimitBlockedPeriod. |
RateLimitRejectionPeriod | Integer | 10 | Amount of seconds over which rejections count toward a block. |
RateLimitRejectionTimeout | Integer | 300 | Number of seconds a client is blocked after exceeding RateLimitRejectionCount within RateLimitRejectionSeconds. |
RegisteredEmail | String | “” | The email address used when setting up the firewall. This is used for providing definition updates and TOTP and is sent to the GraffitiSuite server for determining if the user has access to updates. |
RejectAnonymousUserAgents | Boolean | True | Rejects requests with an invalid or empty UserAgent string when True. |
RejectCrawlers | Boolean | False | Rejects known “bad” crawlers when True. |
RejectBodySQLI | Boolean | True | Scans body data of request for attempts to inject SQL when True. May generate false positives if using on a REST service application. Test thoroughly. |
RejectBodyXSS | Boolean | True | Scans body data of request for attempts to inject JavaScript when True. May generate false positives if using on a REST service application. Test thoroughly. |
RejectCookieSQLI | Boolean | True | Scans cookie data for attempts to inject SQL when True. |
RejectCookieXSS | Boolean | True | Scans cookie data for attempts to inject JavaScript when True. |
RejectionTemplate | String | <Large HTML String> | The HTML data rendered to blocked clients. Use the token #DEBUG# to output the block reason on the page when OutputDebugMessage is True. |
RejectLocalFileInclusion | Boolean | True | Scans body, cookie data, path, and querystring for attempts to include local system files in responses. |
RejectPathSQLI | Boolean | True | Scans the request path for attempts to inject SQL when True. |
RejectPathXSS | Boolean | True | Scans path for attempts to include JavaScript when True. |
RejectQuerySQLI | Boolean | True | Scans query strings for attempts to inject SQL when True. |
RejectQueryXSS | Boolean | True | Scans query strings for attempts to include JavaScript when True. |
RejectSpamReferrers | Boolean | True | Scans requests’ “referer” property for known spam bots. As the “referer” property has been increasingly blocked by clients from being transmitted to servers, this will only catch old/blatant offenders. |
RejectUnknownEndpoints | Boolean | False | When True, any attempt to access an endpoint that does not have a specified permissions setting will be rejected. This may help prevent probing. |
ShareStats | Boolean | True | Optionally share basic anonymous statistics with GraffitiSuite during the update process. This includes only the number of accesses, redirects, and blocks. |
UpdateAPIKey | String | “” | Generated API key to use when requesting definition updates. |
UpdateEnabled | Boolean | True | Determines whether to attempt to retrieve periodic updates from the server. GraffitiFirewall has many functions that do not rely on an active subscription, but more advanced features can not function optimally without periodically updated data. |
UpdateFrequency | Integer | 172800 | Number of seconds between update attempts. Minimum is 86400 (24 hours), default is 172800 (48 hours). |
UpdateLastPerformed (Read Only) | DateTime | Nil | DateTime of the last update check. |
UpdateLastResult (Read Only) | Boolean | False | Used to determine whether the last update completed successfully or failed. |
Examples #
Evaluating Custom Events #
As a simple example, we’ll setup evaluation for login attempts. In your login form, upon submission, register failed login attempts:
'// The second parameter of 100 here is an identifier used
' to separate different custom criteria. It is recommended
' that you use values of 100 or greater as anything lower
' is reserved for internal use within the firewall.
'
' The second parameter is logged to the database for informational
' purposes.
'
' The final parameter is the lifespan of the event in seconds,
' during which it will be returned as valid in CountEvents. In
' this instance we're using 300 seconds(5 minutes).
GraffitiFirewall.RegisterEvent(Session, 100, "Failed login attempt", 300)
You can then use the CountEvents method to see if they’ve exceeded your threshold for failed login attempts, and block the source if they have:
If GraffitiFirewall.CountEvents(Session, 100) >= 5 Then '// Maximum of 5 login failures allowed.
Var block as new GraffitiFirewallBlock(Session, 300) '// Block this source for five minutes.
GraffitiFirewall.Block(block) '// Register the block to be applied automatically by EvaluateConnection.
Session.Close '// Close the session so that any new attempts will be evaluated as new connections.
End If
Using these methods, you can create protection schemes for nearly any operation in your web application and respond appropriately. It is important that you call Session.Close. Session.Close is not done automatically to allow you to display a custom message if you so desire.
Notes #
Adding/Updating GraffitiFirewall #
- Open the GraffitiFirewall project file in Xojo.
- Copy the GraffitiFirewall folder in the IDE’s Project Navigator.
- Open the destination project file in Xojo.
- Select Edit > Paste in the IDE’s menu bar.
- Save and close the destination project.
- Reopen the destination project.
- Continue the following steps only is adding GraffitiFirewall to a project.
- In the App.Opening event, add the following code:
GraffitiFirewall.Instantiate
- In the App.HandleURL event, add the following code:
If GraffitiFirewall.EvaluateConnection(Request, Response) Then Return True