Forum Discussion
Strict header Insertion
Howdy!
Incredibly new to the F5 world, and trying to learn fast after the last F5 SME left.
Here's my issue:
Our organization currently has a static page being served up directly on the F5. This is how the former SME implemented the page -
when HTTP_REQUEST {
switch [HTTP::uri] {
"/" {
HTTP::respond 200 content [ifile get webpage_ifile]
}
"/mainpage.png" {
HTTP::respond 200 content [ifile get mainpage_ifile]
}
"/favicon.ico" {
HTTP::respond 200 content [ifile get favicon_ifile]
}
}
}
It's three files - an html file, the page png, and the fav icon.
It was just pinged on a security audit for not having HSTS implemented for this static page. Having read a few of the HSTS implementation guide, I cannot seem to get it to work with this irule. I've tried http_response and http_response_release, and even defining the strict security on the same http::respond line. None of it seems to work.
Is there a better way to implement this static page or a way to implement strict security in this situation?
Thank you for any help someone can provide!
Nick
You’re running into a very common issue: when you use `HTTP::respond` in an iRule, you completely generate the full response, meaning F5 won’t automatically add additional headers afterward.
So if you want HSTS (or any other header) applied, you must include it directly inside the HTTP::respond command that sends the content.
Also, you can’t use `HTTP_RESPONSE` or `HTTP_RESPONSE_RELEASE` here because there is no server response coming back—you are short-circuiting the request and generating the response directly on the F5.
That means `HTTP_RESPONSE` will never fire.
To solve this situation
Add the HSTS header directly in your `HTTP::respond` commands, like this:
```
when HTTP_REQUEST {
set hsts_header {Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"}switch [HTTP::uri] {
"/" {
HTTP::respond 200 \
content [ifile get webpage_ifile] \
"Content-Type" "text/html" \
$hsts_header
}"/mainpage.png" {
HTTP::respond 200 \
content [ifile get mainpage_ifile] \
"Content-Type" "image/png" \
$hsts_header
}"/favicon.ico" {
HTTP::respond 200 \
content [ifile get favicon_ifile] \
"Content-Type" "image/x-icon" \
$hsts_header
}
}
}
```This will work as the HSTS header is inserted at the moment the response is generated.
Since the F5 is creating the response internally, this is the only chance to add the header.
Make sure this is HTTPS-onlyHSTS must only be applied to HTTPS responses.
If this iRule applies on an HTTP virtual server, you should either redirect HTTP to HTTPS first or add a protocol check.
You can do this once with a small TCL variable
As shown, using a `set` for the header at the top avoids repeating long strings.
If you want to enforce TLS-only redirect
Add this at the top:
```
if { [TCP::local_port] == 80 } {
HTTP::respond 301 Location "https://[HTTP::host][HTTP::uri]"
return
}
```I usually prefer using an HTTP Profile instead of iRule
If your VIP is HTTPS and you want HSTS globally, you can simply:
1. Go to:
```
Local Traffic → Profiles → HTTP → <your HTTP Profile>
```2. Set:
```
HSTS = Enabled
Max Age = 31536000
Include Subdomains = Checked
```This is cleaner and doesn't need iRules.
However, since you're generating the response via `HTTP::respond`, the rule still overrides everything—so adding the header directly in the rule is required unless you switch to standard server responses.
So here is the summary`HTTP::respond` bypasses the normal response pipeline.
Therefore, you must add `Strict-Transport-Security` in the same command that generates the response.
Your updated iRule as above will satisfy the security scan.
let me now for any further assistance.
F5 Design Engineer
10 Replies
- Shyy
Cirrus
Hey,
I think you were looking at old guides, I'd suggest to look at the following articlehttps://my.f5.com/s/article/K68657325
you can enable HSTS through the http profile itself.
- nmaynard
Altocumulus
I've attempted both solutions - activating HSTS through an HTTP profile for the VS and through attempting to define Strict-Transport-Security within the iRule. However, I'm extremely new to this so I'm not sure I'm doing the iRule additions correctly:
when HTTP_RESPONSE {
HTTP::header insert Strict-Transport-Security "max-age=16070400; includeSubDomains"
}I've included this before and after the iRule, and even tried HTTP_RESPONSE_RELEASE (Which I believe alters the server response?) to no avail.
Hi,
Try this, some options for u
1. If you can change VS profiles: Enable HSTS in the HTTP profile on the HTTPS VS (clean, global, supported).
f5-agility-labs-irules.readthedocs.io2. If you must keep the static iRule: add the Strict-Transport-Security header as shown in the HTTP::respond examples above.
3. Ensure HTTP→HTTPS redirect exists so browsers first see the header over TLS and verify with tools like curl -I https://yourhost/ or securityheaders.com.
BR
Aswin- nmaynard
Altocumulus
I've attempted both solutions - activating HSTS through an HTTP profile for the VS and through attempting to define Strict-Transport-Security within the iRule. However, I'm extremely new to this so I'm not sure I'm doing the iRule additions correctly:
when HTTP_RESPONSE {
HTTP::header insert Strict-Transport-Security "max-age=16070400; includeSubDomains"
}I've included this before and after the iRule, and even tried HTTP_RESPONSE_RELEASE (Which I believe alters the server response?) to no avail.
For option 3.) - How would I create an HTTPS redirect? Would that be a separate iRule? I think this VS is only accepting connections over 443, so I would assume that is already HTTPS?
You should define the header directly in the HTTP::respond call. The HTTP_RESPONSE and HTTP_RESPONSE_RELEASE events are not triggered in this case.
Simply append the header to the HTTP::respond calls and adding noserver is always a good idea.
Reference: https://clouddocs.f5.com/api/irules/HTTP__respond.html
HTTP::respond 200 content [ifile get webpage_ifile] noserver "Strict-Transport-Security" "max-age=16070400; includeSubDomains"And another well-intentioned hint: Do not try to manage a F5 without the help of a professional. There are many things that can be wrong from a security perspective.
- nmaynard
Altocumulus
Would this also change the return I would get with curl -I? Is there even a way to change it since its using HTTP::respond? If I try defining a version or declaring 'noserver', curl still seems to return the HTTP::respond default:
HTTP/1.0 200 OK
Server: BigIP
Connection: Keep-Alive
Content-Length: 633
Thank you very much for responding!
HTTP::respond should always returns the same, but you can test it with curl -v to be sure. In this case the HTTP method is unimportant as far I know.
You’re running into a very common issue: when you use `HTTP::respond` in an iRule, you completely generate the full response, meaning F5 won’t automatically add additional headers afterward.
So if you want HSTS (or any other header) applied, you must include it directly inside the HTTP::respond command that sends the content.
Also, you can’t use `HTTP_RESPONSE` or `HTTP_RESPONSE_RELEASE` here because there is no server response coming back—you are short-circuiting the request and generating the response directly on the F5.
That means `HTTP_RESPONSE` will never fire.
To solve this situation
Add the HSTS header directly in your `HTTP::respond` commands, like this:
```
when HTTP_REQUEST {
set hsts_header {Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"}switch [HTTP::uri] {
"/" {
HTTP::respond 200 \
content [ifile get webpage_ifile] \
"Content-Type" "text/html" \
$hsts_header
}"/mainpage.png" {
HTTP::respond 200 \
content [ifile get mainpage_ifile] \
"Content-Type" "image/png" \
$hsts_header
}"/favicon.ico" {
HTTP::respond 200 \
content [ifile get favicon_ifile] \
"Content-Type" "image/x-icon" \
$hsts_header
}
}
}
```This will work as the HSTS header is inserted at the moment the response is generated.
Since the F5 is creating the response internally, this is the only chance to add the header.
Make sure this is HTTPS-onlyHSTS must only be applied to HTTPS responses.
If this iRule applies on an HTTP virtual server, you should either redirect HTTP to HTTPS first or add a protocol check.
You can do this once with a small TCL variable
As shown, using a `set` for the header at the top avoids repeating long strings.
If you want to enforce TLS-only redirect
Add this at the top:
```
if { [TCP::local_port] == 80 } {
HTTP::respond 301 Location "https://[HTTP::host][HTTP::uri]"
return
}
```I usually prefer using an HTTP Profile instead of iRule
If your VIP is HTTPS and you want HSTS globally, you can simply:
1. Go to:
```
Local Traffic → Profiles → HTTP → <your HTTP Profile>
```2. Set:
```
HSTS = Enabled
Max Age = 31536000
Include Subdomains = Checked
```This is cleaner and doesn't need iRules.
However, since you're generating the response via `HTTP::respond`, the rule still overrides everything—so adding the header directly in the rule is required unless you switch to standard server responses.
So here is the summary`HTTP::respond` bypasses the normal response pipeline.
Therefore, you must add `Strict-Transport-Security` in the same command that generates the response.
Your updated iRule as above will satisfy the security scan.
let me now for any further assistance.
F5 Design Engineer- nmaynard
Altocumulus
Apologies on the extremely slow response!
I really appreciate your lengthy response to my post! This was the solution that ended up working in my specific situation. For some reason, blowing away the iRule altogether and adding the headers as a set variable seemed to do the trick. I have had the auditors scan the static page again, and it is now showing the strict header insertion.
Thank you again!
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
