OpenResty

OpenResty

Installation

1
sudo luarocks install botbye-openresty

Configuration

Configure the botbye_phishing module in your nginx http block. On construction the client reports the server-side integration via a best-effort initRequest() handshake — it needs a botbye_state shared dict (the once-per-instance guard) and a call from init_worker_by_lua_block.

Getting clientKey

clientKey is the public, browser-safe identifier of your phishing project. It travels in the asset URL path, so it is safe to expose — no secret token and no Base64 encoding are required.

Find it on the Get Started screen of your phishing project in the BotBye dashboard.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
http {
    # ...
    lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
    lua_ssl_verify_depth 3;

    lua_shared_dict botbye_state 1m;

    init_by_lua_block {
        require("botbye_phishing").setConf({
            endpoint = "https://verify.botbye.com",
            client_key = "<public-client-key>",
        })
    }

    init_worker_by_lua_block {
        require("botbye_phishing").initRequest()
    }
}

Usage

Anti-phishing needs two routes on your own origin: an SVG route — the URL your client code passes to getCatcher({ url }) — and a PNG route that the SVG references. The paths are arbitrary, so name them like ordinary static assets and let the route decide the format. A path that spells out the vendor or the feature (/api/phishing/…) is what a copied page is searched for and stripped of, and a format query param on the pixel URL reads the same way.

On the SVG route, pass inner_png_url — the absolute URL of your PNG route: the returned SVG embeds it as its tracking pixel. It is required for format = "svg": Lua has no type to demand it the way the other SDKs do, so the module checks at call time and returns nil, "missing inner_png_url" without it. Build that URL from your own host — image_id is owned by the SDK and is not read from the forwarded query. skip_execution defaults to true, the script-less SVG; pass false only for browsers predating crossorigin on svg <image> (Chrome 118, Firefox 114, Safari 17.2), where the script-driven variant is the one that still reports.

These examples forward no query: format, image_id and executable are set by the call itself, and only module_name / module_version pass through from the browser's pixel query — which a catcher mounted on your own routes never receives.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
location /your-image-route.svg {
    content_by_lua_block {
        local phishing = require("botbye_phishing")

        -- Origin and Referer are read off the request by the module itself
        local res, err = phishing.fetchCatcher({
            format = "svg",
            inner_png_url = "https://" .. ngx.var.host .. "/your-image-route.png",
        })

        if not res then
            ngx.status = 502
            ngx.say(err or "upstream error")
            return ngx.exit(502)
        end

        ngx.status = res.status or 200
        ngx.header["Content-Type"] = (res.headers and res.headers["Content-Type"]) or "image/svg+xml"

        if res.body ~= nil then
            ngx.print(res.body)
        end
    }
}

location /your-image-route.png {
    content_by_lua_block {
        local phishing = require("botbye_phishing")

        local res, err = phishing.fetchCatcher({ format = "png" })

        if not res then
            ngx.status = 502
            ngx.say(err or "upstream error")
            return ngx.exit(502)
        end

        ngx.status = res.status or 200
        ngx.header["Content-Type"] = (res.headers and res.headers["Content-Type"]) or "image/png"

        if res.body ~= nil then
            ngx.print(res.body)
        end
    }
}

Settings

Configuration parameters for phishing integration (botbye_phishing.setConf):

Setting Description Required Default Value
endpoint Host of the phishing API no https://verify.botbye.com
client_key Public client-key of your phishing project yes -
connection_timeout Connect / send / read timeout of one upstream call, ms no 1000

setConf takes these keys verbatim: an unknown key (clientKey, for one) is logged as [BotBye] ignoring unknown config key and dropped, leaving the client-key empty.