Hi;
I am trying to have an i-rule that checks for URLs in a data group, then based on the URL value it allows certain methods.
For example, the URL path /abc/xyz/ can have GET and POST. However a different URL path can only have GET.
It would be great if I can check the URL against a certain data group of URLs and then for each URL in this data group, there is a specific data group of http methods.
I guess more like a two dimensional array or like a data group of URLs but each member is a “URL and its associated methods”.
Or a data group with “data group” members, each member is referenced by a URL and has a list of methods.
Kindly
Wasfi
Sounds like a great project. I’d go for the spirit of maintainability and avoid two-dimensional stuff in favor of using some kind of simple delimiter in the data section like this:
ltm data group internal http_method_acls {
records {
/foo/bar {
data "POST|CONNECT|GET|HEAD"
}
type string
}
Then to check for a match you can just use “contains [HTTP::method]”, which has extra fast optimization (as compared to the stock TCL string functions) in the iRules engine. Maybe something kind of like this:
when HTTP_REQUEST <span class="token punctuation">{</span>
<span class="token keyword">set</span> <span class="token variable">allowedmethods</span> <span class="token punctuation">[</span>class match <span class="token operator">-</span>value <span class="token punctuation">[</span><span class="token keyword">string</span> tolower <span class="token punctuation">[</span>HTTP::path<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">eq</span> http_method_acls <span class="token punctuation">]</span>
<span class="token builtin">if</span> <span class="token punctuation">{</span> allowedmethods contains <span class="token punctuation">[</span>HTTP::method<span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span>
log local0. <span class="token string">"allowed"</span>
<span class="token punctuation">}</span> <span class="token builtin">else</span> <span class="token punctuation">{</span>
log local0. <span class="token string">"deny"</span>
HTTP::respond 400 <span class="token string">"not allowed here"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
We do sell a module called “Advanced WAF” that can do this kind of filtering automatically if you have these allowed definitions created already in an OpenAPI spec file: https://my.f5.com/manage/s/article/K81943444
Hi Lucas;
Thank you for your response. Just wanted to check the syntax for your suggestion though. For example, would this work? The idea is to allow the request if the URL and HTTP method match. If only the URL is a match then deny. and if the URL is not a match then allow everything.
ltm data group internal http_method_acls {
records {
/foo/bar/ {
data "POST|CONNECT|GET|HEAD"
}
/abc/xyz/ {
data "POST"
}
}
type string
}
when HTTP_REQUEST <span class="token punctuation">{</span>
<span class="token keyword">set</span> <span class="token variable">uri_path_name</span> <span class="token punctuation">[</span><span class="token keyword">string</span> tolower <span class="token punctuation">[</span>URI::path <span class="token punctuation">[</span>HTTP::uri<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
<span class="token keyword">set</span> <span class="token variable">http_method</span> <span class="token punctuation">[</span><span class="token keyword">string</span> toupper <span class="token punctuation">[</span>HTTP::method<span class="token punctuation">]</span><span class="token punctuation">]</span>
<span class="token builtin">if</span> <span class="token punctuation">{</span><span class="token operator">!</span> <span class="token punctuation">[</span>class match $<span class="token variable">uri_path_name</span> equals http_method_acl<span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span>
<span class="token builtin">return</span>
<span class="token punctuation">}</span> <span class="token builtin">else</span> <span class="token punctuation">{</span>
<span class="token builtin">if</span> <span class="token punctuation">{</span><span class="token operator">!</span><span class="token punctuation">[</span>class match $<span class="token variable">uri_path_name</span> <span class="token operator">-</span>value contains $<span class="token variable">http_method</span><span class="token punctuation">]</span><span class="token punctuation">}</span> <span class="token punctuation">{</span>
reject
<span class="token builtin">return</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
I did a quick test and this seems to work pretty well. You’ll want to use an “allow list” rather than a “block list” for security reasons.
Of course all code should be thoroughly tested before use in production. Use at your own risk.
when HTTP_REQUEST <span class="token punctuation">{</span>
<span class="token keyword">set</span> <span class="token variable">uri_path_name</span> <span class="token punctuation">[</span><span class="token keyword">string</span> tolower <span class="token punctuation">[</span>HTTP::uri<span class="token punctuation">]</span> <span class="token punctuation">]</span>
<span class="token keyword">set</span> <span class="token variable">http_method</span> <span class="token punctuation">[</span><span class="token keyword">string</span> toupper <span class="token punctuation">[</span>HTTP::method<span class="token punctuation">]</span> <span class="token punctuation">]</span>
<span class="token keyword">set</span> <span class="token variable">allowed_methods</span> <span class="token punctuation">[</span>class match <span class="token operator">-</span>value $<span class="token variable">uri_path_name</span> equals http_method_allowlist <span class="token punctuation">]</span>
log local0. <span class="token string">"Allowed methods: $allowed_methods for URI: ${uri_path_name}, this request is ${http_method}"</span>
<span class="token builtin">if</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">expr</span> <span class="token punctuation">{</span> $<span class="token variable">{allowed_methods}</span> contains $<span class="token variable">{http_method}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span>
log local0. <span class="token string">"allow"</span>
<span class="token builtin">return</span>
<span class="token punctuation">}</span> <span class="token builtin">else</span> <span class="token punctuation">{</span>
log local0. <span class="token string">"disallow"</span>
reject
<span class="token builtin">return</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>