Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to add new parameter and generate parser for new code #347

Open
vzhirnov opened this issue Feb 20, 2025 · 4 comments
Open

How to add new parameter and generate parser for new code #347

vzhirnov opened this issue Feb 20, 2025 · 4 comments

Comments

@vzhirnov
Copy link

Hello, I have encountered issues in understanding how the parser generator works in the project.


Task:

  • I need to add a new parameter called domain_id.
  • My custom parameter domain_id is used in the ngx_modsecurity_module module and determines the value of the domain_id directive in the server context.

Example usage:

server { 
    server_name vts;
    domain_id 1150;  # <<<<<<=======
    listen 80;
    access_log off;
    location /status { vhost_traffic_status_display; vhost_traffic_status_display_format html; }
    location /stub-status {
        stub_status on;
    }
}
  • I would like my code owasp-modsecurity/ModSecurity to be able to receive the domain_id parameter from ngx_modsecurity_module and use it in rules, as well as see the domain_id value in modsec json logs.
  • I added code (briefly, just to show what exactly was done and at what stage I got stuck):
    1. m_variableDomainId(t, "DOMAIN_ID"),
    2. int msc_add_domain_id(Transaction *transaction, int domain_id);
    3. int Transaction::addDomainId(int domain_id) {
      this->m_domainId = domain_id;
      m_variableDomainId.set(std::to_string(this->m_domainId), m_variableOffset);
      return true;
      }
  1. domain_id.h file
  2. int msc_add_domain_id(Transaction *transaction, int domain_id);
  3. Call of the msc_add_domain_id function in the ngx_modsecurity_module module.

Problem:
I don’t understand how to generate the code in such a way that the appropriate code appears in the necessary files. It seems that bison, lex, and yacc are needed for this.

Searching for a solution:
I searched for similar PRs, and this one has something similar to what I need:
owasp-modsecurity/ModSecurity@fa6e418

But I don't fully understand:

  1. What code needs to be written before running the parser generator.
  2. At what stage to run the parser (which code should be written before running the parser).
  3. How exactly to run the parser correctly.

Could you please help me understand what the entire process of adding a new parameter looks like?

For example, my domain_id.

If needed, and if it is relevant, I will later write a part of the documentation that describes the process of adding a new parameter, based on our dialogue, and make a PR.

@vzhirnov
Copy link
Author

I figured it out. Sorry for bothering you.

@airween
Copy link
Member

airween commented Feb 20, 2025

@vzhirnov,

no worries, feel free to ask here, we are happy to help. And sorry for the late reply.

Just to clarify: do you want to use this modification only for yourself, or you want to add it into repository?

An other remark: why do you want to change/modify the library's parser? It seems you want to add a specific directive to the Nginx, not to the library.

And finally, may be that's not a solution what you are looking for, but you should take a look at SecWebAppId. That works out of box.

@vzhirnov
Copy link
Author

hi @airween , thank you so much for your quick answer!

do you want to use this modification only for yourself , or you want to add it into repository?

I'd like to use this modification only by myself (to be clear, for our project). As far as I understand, there is no need to add DOMAIN_ID to github modsec project because the domain_id is the directive we only use in our nginx, with several modules, and ngx_http_modsecurity_module module as example. The main puprose is to identify vhost, and see it in modsec logs. Also it would be great to work with DOMAIN_ID as a variable (say, IF domain_id eq some_number THAN some_action).

So we need ngx_http_modsecurity_module to have the opportunity to work with domain_id although this directive is the ngx_http_core directive. We get it from http core module, and pass to msc_add_domain_id(Transaction *transaction, int domain_id) within ngx_http_modsecurity_module, after that we can see the corresponding domain_id in modsec logs, and can work with DOMAIN_ID as the variable.

why do you want to change/modify the library's parser

yes, we want to:

  1. use domain_id value in modsec logs
  2. use DOMAIN_ID as a variable for modsec rules.

may be that's not a solution what you are looking for, but you should take a look at SecWebAppId.

thanks, I didn't know about that. I will ask about our devops guys if we can use it (and also I have a hunch that we could use the setvar for our purposes.)

@rookie-man-fack
Copy link

rookie-man-fack commented Mar 3, 2025

You can try the following three solutions.

I can retrieve it successfully in my local tests.

方案 1:使用 SecWebAppId 设置应用 ID

适用场景

  • 适用于使用 SecWebAppId 作为应用标识。
  • 通过 WEBAPPID 变量存储 DOMAIN_ID,并在 ModSecurity 规则中记录。

配置步骤

1️⃣ Nginx 配置

server {
    listen 80;
    server_name app1.example.com;

    modsecurity on;
    modsecurity_rules 'SecWebAppId "1150"';
    modsecurity_rules_file /usr/local/openresty/nginx/conf/modsecurity/modsecurity.conf;

    location /app1 {
        return 200;
    }
}

2️⃣ ModSecurity 规则配置 (test.conf)

SecRule WEBAPPID "!@streq ''" "id:10011,phase:1,log,msg:'domain_id: %{WEBAPPID}'"

结果

  • WEBAPPID 变量会存储 1150,并写入 ModSecurity 日志。
  • WEBAPPID 变量不能直接在 tx. 变量空间中使用,适用场景受限。
  ModSecurity: Warning. Matched "Operator `StrEq' with parameter `''' against variable `' (Value: `1150"' ) [file "/usr/local/openresty/nginx/conf/modsecurity/rules/test.conf"] [line "2"] [id "10011"] [rev ""] [msg "domain_id: 1150""] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "192.100.2.110"] [uri "/app1"] [unique_id "174103244874.402481"] [ref ""]

方案 2:使用 SecAction 设置 tx.domain_id

适用场景

  • 适用于在 ModSecurity 规则中直接指定 DOMAIN_ID
  • 适用于 Nginx 不能传递 DOMAIN_ID,但希望在 ModSecurity 内部赋值。

配置步骤

1️⃣ Nginx 配置

server {
    listen 80;
    server_name app2.example.com;

    modsecurity on;
    modsecurity_rules_file /usr/local/openresty/nginx/conf/modsecurity/modsecurity.conf;

    location /app2 {
        return 200;
    }
}

2️⃣ ModSecurity 规则配置 (test.conf)

SecAction "id:10012,phase:1,nolog,pass,setvar:tx.domain_id=1150"
SecRule REQUEST_URI "@rx .*" "id:10012,phase:1,log,deny,msg:'Access to all requests',logdata:'domain_id: %{tx.domain_id}'"

结果

  • tx.domain_id 变量被强制设定为 1150,并在规则匹配时记录。
  • 适用于静态 domain_id 值,但 不适用于动态设置
ModSecurity: Access denied with code 403 (phase 1). Matched "Operator `Rx' with parameter `.*' against variable `REQUEST_URI' (Value: `/healthz' ) [file "/usr/local/openresty/nginx/conf/modsecurity/rules/test.conf"] [line "2"] [id "10012"] [rev ""] [msg "Access to all requests"] [data "domain_id: 1150"] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "192.100.2.110"] [uri "/healthz"] [unique_id "174103304564.933566"] [ref "o0,8v4,8"]

方案 3:使用 OpenResty 环境变量 + Nginx 传递请求头

适用场景

  • 适用于动态 DOMAIN_ID,从 OpenResty 读取环境变量并传递到 ModSecurity。
  • 适用于 Kubernetes / Docker 等环境,DOMAIN_ID 可能是 环境变量

配置步骤

1️⃣ Nginx 配置

env DOMAIN_ID;

server {
    listen 80;
    server_name app3.example.com;

    set_by_lua $domain_id 'return os.getenv("DOMAIN_ID")';

    modsecurity on;
    modsecurity_rules_file /usr/local/openresty/nginx/conf/modsecurity/modsecurity.conf;

    location /app3 {
        proxy_set_header X-Domain-ID $domain_id;
        return 200;
    }
}

2️⃣ ModSecurity 规则配置 (test.conf)

方法 1:使用 SecAction 读取 X-Domain-ID

SecAction "id:10020,phase:1,nolog,pass,setvar:tx.domain_id=%{REQUEST_HEADERS:X-Domain-ID}"
SecRule TX:domain_id "!@streq ''" "id:10021,phase:1,log,msg:'domain_id: %{TX.domain_id}'"

方法 2:直接在 SecRule 中获取 X-Domain-ID

SecRule REQUEST_HEADERS:X-Domain-ID "@rx .*" "id:10022,phase:1,log,pass,setvar:tx.domain_id=%{MATCHED_VAR},msg:'Captured domain_id: %{TX.domain_id}'"

结果

  • DOMAIN_ID 从环境变量获取,并传递给 Nginx 变量 $domain_id
  • Nginx 通过 proxy_set_headerX-Domain-ID 传给 ModSecurity。
  • ModSecurity 通过 SecActionSecRule 读取 X-Domain-ID 并存入 tx.domain_id
  • 适用于 多租户环境,可动态修改 DOMAIN_ID,适用性最强。

对比总结

方案 适用场景 变量来源 适配性 适用环境
方案 1 SecWebAppId 方式 固定 WEBAPPID 受限 单应用
方案 2 SecAction 直接赋值 静态 domain_id 中等 静态规则
方案 3 OpenResty 变量传递 环境变量 DOMAIN_ID 最佳 动态环境 (K8s, Docker)

推荐

如果 DOMAIN_ID 固定,使用 SecAction 方案(方案 2)。
如果 DOMAIN_ID 需要动态修改,使用 OpenResty 环境变量方案(方案 3)。
如果已经使用 SecWebAppId,可以尝试方案 1,但不适用于动态场景。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants