Write custom Lua scripts to intercept and modify web request processing, enabling security logic beyond WAF's built-in rules. Configurable scripts and parameters let you address complex, business-specific requirements with greater flexibility.
Enable the Extensions feature
To use Extensions, complete the following activation steps:
Applicable editions: Only Subscription-based WAF Enterprise Edition, Ultimate Edition, and Pay-As-You-Go Edition support this feature.
Billing: This is a paid service. The billing method is as follows:
-
Pay-As-You-Go Edition: You can use it directly without a prior purchase. Additional charges apply based on actual usage.
-
Subscription Edition: You must purchase the feature before use.
-
Log on to the Web Application Firewall 3.0 console. From the top menu bar, select the resource group and region (Chinese Mainland or Outside Chinese Mainland) for the WAF instance.
-
In the left-side navigation pane, choose .
-
Click Buy Now and follow the on-screen instructions to activate the feature.
Create an extension
On the Extensions page, click Create Extension, and then configure the following parameters.
-
Basic Info: Enter a recognizable Plugin Name and Plugin Description.
-
Plugin Code: Write the Lua script here to implement your custom security logic. Example: For more information about the API, see Appendix: Custom Lua script API reference.
-- Custom Lua script example: Extract a query parameter and compare it with a custom parameter. Block if they do not match. -- Step 1: Extract the request parameter local token = aliwaf.req.get_arg('token') -- Step 2: Compare with the custom parameter if token ~= params.token then aliwaf.func.punish() endImportant-
To ensure WAF system stability, a single Lua script's execution time per request is limited to 2 ms. During the Debug and Test phase, if the execution time exceeds this limit, the script fails the test and creation fails. During actual runtime, if a script's execution time exceeds 2 ms for a request, the system skips that execution.
-
Do not hardcode sensitive information (such as keys) in your code. Use the Parameter Definition feature below instead.
-
-
Parameter Definition: Extract hardcoded values from scripts into configurable parameters to decouple logic from data. This lets you adjust policies dynamically without modifying code, and manage keys securely. Click Add Parameter and complete the following configuration:
-
Parameter Name: The variable name referenced in the script (for example,
secret_key). -
Parameter Type: Supported types include String, Number, Boolean, JSON Object, and JSON Array. Ensure the type matches the handling logic in your script.
-
Parameter Description: Describes the purpose of the parameter.
-
Parameter Value: Supports the following two modes:
-
Manual Input: Enter the value directly.
-
Use KMS Credential: Reference a credential already created in Key Management Service to securely store sensitive data. For WAF to successfully reference the credential, you must attach the following tag to it:
-
Tag Key:
waf:access:enable -
Tag Value:
true
-
-
-
-
Debug and Test:
-
Plugin Action Parameters: Currently only supports the Block mode, which blocks the request.
-
Traffic Parameters: Simulates real HTTP request traffic. Click Add Parameter, and enter a Parameter Name (such as
method,uri, orargs) and its corresponding Parameter Value.Example: Set
methodtoPOSTandurito/loginto test the protection logic for a login endpoint.
-
-
Execution Result: Click Run and Debug. The system executes the script against the simulated traffic, and you can view the Execution Result panel on the right. If the result shows failure, fix the code based on the specific error messages.
What to do next
After creating an extension, you must reference it in a Custom Rule protection template. For more information, see Custom rules.
Daily operations
On the Extensions page, you can perform the following operations:
-
View the plugin list: Displays all extensions. Use the search box to enter a plugin name for quick lookup.
-
View associated protection rules: Locate the target plugin and click the
icon in the Associated Rules column to display the associated protection rule IDs. You can copy an ID and search for it on the Core Web Protection or Security Reports page. -
Edit an extension: Locate the target plugin and click Edit in the Actions column to modify its configuration.
-
Delete an extension: Locate the target plugin and click Delete in the Actions column to remove the extension.
Appendix: Custom Lua script API reference
Core interfaces for custom Lua scripts, covering request data reading, encryption and decryption, and request flow control.
HTTP request example
POST /api/v1/orders?source=web&campaign=spring2024 HTTP/1.1
Host: shop.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
Cookie: session_id=abc123xyz; user_prefs=lang%3Den%26theme%3Ddark
Content-Type: application/json
Content-Length: 68
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
Accept: application/json
eyJwcm9kdWN0X2lkIjogNzg5LCAicXVhbnRpdHkiOiAyLCAidXJnZW50IjogdHJ1ZX0=
Read request data
All interfaces return a string. If a field does not exist, an empty string is returned.
Read the method
|
Item |
Type |
Description |
|
Parameter |
- |
- |
|
Return value |
string |
The HTTP request method, such as "GET" or "POST". |
-- POST --
local method = aliwaf.req.get_method()
Read the URI
|
Item |
Type |
Description |
|
Parameter |
- |
- |
|
Return value |
string |
The URI path of the request. |
-- /api/v1/orders --
local uri = aliwaf.req.get_uri()
Read the domain
|
Item |
Type |
Description |
|
Parameter |
- |
- |
|
Return value |
string |
The Host domain name of the request. |
-- shop.example.com --
local domain = aliwaf.req.get_domain()
Read the query
|
Item |
Type |
Description |
|
Parameter |
- |
- |
|
Return value |
string |
The full query string of the request. |
-- source=web&campaign=spring2024 --
local query = aliwaf.req.get_query()
Read a query parameter
|
Item |
Type |
Description |
|
Parameter |
string |
The query parameter name. |
|
Return value |
string |
The corresponding parameter value. Returns an empty string "" if the parameter does not exist. |
-- web --
local source = aliwaf.req.get_arg('source')
Read a cookie
|
Item |
Type |
Description |
|
Parameter |
string |
The cookie name. |
|
Return value |
string |
The corresponding cookie value. Returns an empty string "" if the cookie does not exist. |
-- abc123xyz --
local session_id = aliwaf.req.get_cookie('session_id')
Read a header
|
Item |
Type |
Description |
|
Parameter |
string |
The HTTP request header name. |
|
Return value |
string |
The corresponding header value. Returns an empty string "" if the header does not exist. |
-- Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx --
local auth = aliwaf.req.get_header('Authorization')
Read the body
Check the request body status
-
Whether the body has been fully received
Item
Type
Description
Parameter
-
-
Return value
boolean
true indicates that the request body has been fully received. false indicates that more data is still pending.
local last = aliwaf.func.is_last_fragment_arrived() -
Whether the body has been truncated
Item
Type
Description
Parameter
-
-
Return value
boolean
true indicates that the request body exceeded the limit and was truncated. false indicates that the request body is intact.
By default, WAF stores up to 128 KB of the request body. Requests exceeding this limit are truncated (the excess portion is discarded).
local discard = aliwaf.func.is_request_body_discarded()
Wait for the body
Request bodies arrive at WAF in a streaming manner, so the body may not yet be fully received when the script executes. To process the complete body, explicitly notify the framework to wait for the full body before re-executing the script.
|
Item |
Type |
Description |
|
Parameter |
- |
- |
|
Return value |
- |
- |
aliwaf.func.wait_request_body()
Example: Read the request body
-- Body not fully received; wait for it --
if not aliwaf.func.is_last_fragment_arrived() then
aliwaf.func.wait_request_body()
return
end
-- Body fully received; check if truncated --
if aliwaf.func.is_request_body_discarded() then
return
end
-- eyJwcm9kdWN0X2lkIjogNzg5LCAicXVhbnRpdHkiOiAyLCAidXJnZW50IjogdHJ1ZX0= --
local body = aliwaf.req.get_body()
-- TODO: Apply business logic to the complete body --
Common utility functions
Basic encoding and decoding
The URL, hex, and base64 encoding/decoding interfaces accept a string parameter and return a processed string. On failure, they return an empty string.
URL encoding and decoding
-
escape_uri
Item
Type
Description
Parameter
string
The raw string to be encoded.
Return value
string
The encoded string.
-
unescape_uri
Item
Type
Description
Parameter
string
The URL-encoded string to be decoded.
Return value
string
The decoded raw string.
-- a%20b --
local data1 = aliwaf.util.escape_uri('a b')
-- a b --
local data2 = aliwaf.util.unescape_uri('a%20b')
Hex encoding and decoding
-
hex_encode
Item
Type
Description
Parameter
string
The binary string to be encoded.
Return value
string
The uppercase hex-encoded string.
-
hex_decode
Item
Type
Description
Parameter
string
The hex string to be decoded.
Return value
string
The decoded raw string. Returns an empty string "" if the input is invalid.
-- DEADBEEF --
local data1 = aliwaf.util.hex_encode(string.char(0xDE, 0xAD, 0xBE, 0xEF))
-- \xDE\xAD\xBE\xEF --
local data2 = aliwaf.util.hex_decode('DEADBEEF')
Base64 encoding and decoding
-
base64_encode
Item
Type
Description
Parameter
string
The raw string to be encoded.
Return value
string
The Base64-encoded string.
-
base64_decode
Item
Type
Description
Parameter
string
The Base64 string to be decoded.
Return value
string
The decoded raw string. Returns an empty string "" if the input is invalid.
-- aGVsbG8= --
local data1 = aliwaf.util.base64_encode('hello')
-- hello --
local data2 = aliwaf.util.base64_decode('aGVsbG8=')
MD5/CRC/SHA
-
md5
Item
Type
Description
Parameter
string
The raw string to be hashed.
Return value
string
The MD5 digest in 32-character lowercase hex format.
-
sha256
Item
Type
Description
Parameter
string
The raw string to be hashed.
Return value
string
The SHA-256 digest in 64-character lowercase hex format.
-
crc32
Item
Type
Description
Parameter
string
The raw string to be computed.
Return value
integer
The CRC32 checksum (unsigned 32-bit integer).
-- 5d41402abc4b2a76b9719d911017c592 --
local md5 = aliwaf.util.md5('hello')
-- 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 --
local sha = aliwaf.util.sha256('hello')
-- 3287646509 --
local crc = aliwaf.util.crc32('hello')
Encryption and decryption (AES/DES)
-
evp_encrypt
Item
Type
Description
Parameter 1
string
The encryption algorithm type, such as "aes-128-cbc".
Parameter 2
string
The encryption key (binary-safe string).
Parameter 3
string
The initialization vector. Can be an empty string "" if IV is not used.
Parameter 4
string
The plaintext to be encrypted.
Return value
string
The encrypted ciphertext. Returns an empty string "" if the parameters are invalid or encryption fails.
-
evp_decrypt
Item
Type
Description
Parameter 1
string
The decryption algorithm type. Must match the algorithm used for encryption, such as "aes-128-cbc".
Parameter 2
string
The decryption key. Must match the key used for encryption.
Parameter 3
string
The initialization vector. Must match the IV used for encryption. Can be an empty string "".
Parameter 4
string
The ciphertext to be decrypted.
Return value
string
The decrypted plaintext. Returns an empty string "" if the parameters are invalid or decryption fails.
local data1 = aliwaf.util.evp_encrypt('aes-128-cbc', 'key-12345678-key', 'iv-1234567890-iv', 'hello')
local data2 = aliwaf.util.evp_decrypt('aes-128-cbc', 'key-12345678-key', 'iv-1234567890-iv', data1)
Signing and verification (ES256)
-
es256_sign
Item
Type
Description
Parameter 1
string
The ES256 private key in PEM format.
Parameter 2
string
The raw data to be signed.
Return value
string
The signature result (binary string). Returns an empty string "" if the parameters are invalid or signing fails.
-
es256_verify
Item
Type
Description
Parameter 1
string
The ES256 public key in PEM format.
Parameter 2
string
The raw data used for signing (must match the data used during signing).
Parameter 3
string
The signature value to verify (generated by es256_sign).
Return value
boolean
true indicates that the signature verification passed. false indicates verification failure or invalid parameters.
local sign = aliwaf.util.es256_sign('private_key-1234', 'hello')
local result = aliwaf.util.es256_verify('public_key-12345', 'hello', sign)
Time
|
Item |
Type |
Description |
|
Parameter |
- |
- |
|
Return value |
integer |
The current millisecond-level UNIX timestamp. |
-- Current millisecond-level timestamp (integer) --
local timestamp = aliwaf.util.get_current_ms()
Business helper functions
Business helper functions coordinate between Lua scripts and the WAF framework.
Action
|
Item |
Type |
Description |
|
Parameter |
- |
- |
|
Return value |
- |
- |
-- Take action on the current request based on the pre-selected action --
aliwaf.func.punish()