Forum Discussion
Turn off client auth if uri equals
Customers connect to one IP. They connect with an app, not a browser. They use port 5443 to register (obtain a cert we issue) for the service, and port 443 for the actual service.
register: https://5.5.5.5:5443/register (1-way ssl) (get the cert)
service: https://5.5.5.5/service (2-way ssl) (use the cert)
We have a registration VS and a service VS. Both VS's have their own client ssl profile (no server profile). Below are the differences in the ssl profiles:
I am tasked with getting rid of port 5443 and making it so that customers can both register and hit the service on port 443/https. The majority of the traffic comes in on 443 with the occasional new customer registering first on 5443. The VS's point to different pools. We are running BIG-IP 11.3.0 Build 2806.0 Final.
With that being said, I'd like to make the 2-way ssl profile the default and turn off client auth if uri equals "/register". Here is what I have so far...
when HTTP_REQUEST {
Turn off client auth for registration requests
if { [HTTP::uri] contains "/register" } {
SSL::cert mode ignore
SSL::renegotiate enable
SSL::renegotiate
pool registration-pool
return
} elseif { ([SSL::cert count] > 0) && ([HTTP::uri] contains "/service") } {
scrub header
HTTP::header remove chain
HTTP::header remove client
HTTP::header remove testCert
HTTP::header remove ClientCert-Subject
HTTP::header remove SSLClientCertSubject
HTTP::header remove SSLClientCertThumbprint
insert cert subject
HTTP::header insert SSLClientCertSubject [X509::subject [SSL::cert 0]]
} else {
drop
}
}
Concerns:
- When to use "return" and "SSL::renegotiate"
- Security (ssl renegotiate vulnerabilities)
- Do I need to set variables?
Very grateful for any help on this. Thanks.
19 Replies
- Kevin_Stewart
Employee
Try this (minor update):
when CLIENTSSL_CLIENTCERT { if { [SSL::cert count] < 1 } { if the client did not present a certificate - fail reject } else { do something with the cert here } HTTP::release } when CLIENT_ACCEPTED { set default_pool [LB::server pool] } when HTTP_REQUEST { non-registration URI space requested and F5AUTH cookie does not exist - prompt for client certificate if { not ( [HTTP::uri] equals "/favicon.ico" ) and not ( [HTTP::uri] starts_with "/register" ) and not ( [HTTP::cookie exists F5AUTH] ) } { invalidate SSL and renegotiate HTTP::collect SSL::session invalidate SSL::authenticate always SSL::authenticate depth 9 SSL::cert mode require SSL::renegotiate } elseif { [HTTP::cookie exists F5AUTH] } { F5AUTH cookie exists - send HTTP header data if { [table lookup -subtable CERTDATA [HTTP::cookie value F5AUTH]] ne "" } { HTTP::header replace X-CLIENT-CERT [table lookup -subtable CERTDATA [HTTP::cookie value F5AUTH]] } } if { [HTTP::uri] starts_with "/register" } { pool local-pool-2 } else { pool $default_pool } } when HTTP_REQUEST_SEND { clientside { if { ( [SSL::cert count] > 0 ) and not ( [HTTP::cookie exists F5AUTH] ) } { generate a GUID set uniqueid "_[string range [AES::key 256] 34 end]" add cert to local session table table add -subtable CERTDATA $uniqueid [X509::subject [SSL::cert 0]] } } } when HTTP_RESPONSE { if the uniqueid variable is set - send the F5AUTH cookie to client if { [info exists uniqueid] } { HTTP::header insert "Set-Cookie" "F5AUTH=$uniqueid; path=/; secure; HTTPOnly" unset uniqueid } }- iamsajjad
Cirrus
Dumb questions:
1. Whats' the purpose of HTTP::release? What's the harm not adding this?
2. Why should we do SSL::session invalidate when we are doing SSL::renogotiate
3. What happens if we skip add F5AUTH Cookie portions? clientside if SSL::cert count > 1 we insert filed values
Thank you!
- Kevin_Stewart
Employee
This sort of thing becomes a bit easier with APM, but here's an iRule that comes close to the same functionality:
when CLIENTSSL_CLIENTCERT { if { [SSL::cert count] < 1 } { if the client did not present a certificate - fail reject } else { do something with the cert here } HTTP::release } when HTTP_REQUEST { non-registration URI space requested and F5AUTH cookie does not exist - prompt for client certificate if { not ( [HTTP::uri] equals "/favicon.ico" ) and not ( [HTTP::uri] starts_with "/register" ) and not ( [HTTP::cookie exists F5AUTH] ) } { invalidate SSL and renegotiate HTTP::collect SSL::session invalidate SSL::authenticate always SSL::authenticate depth 9 SSL::cert mode require SSL::renegotiate } elseif { [HTTP::cookie exists F5AUTH] } { F5AUTH cookie exists - send HTTP header data if { [table lookup -subtable CERTDATA [HTTP::cookie value F5AUTH]] ne "" } { HTTP::header replace X-CLIENT-CERT [table lookup -subtable CERTDATA [HTTP::cookie value F5AUTH]] } } } when HTTP_REQUEST_SEND { clientside { if { ( [SSL::cert count] > 0 ) and not ( [HTTP::cookie exists F5AUTH] ) } { generate a GUID set uniqueid "_[string range [AES::key 256] 34 end]" add cert to local session table table add -subtable CERTDATA $uniqueid [X509::subject [SSL::cert 0]] } } } when HTTP_RESPONSE { if the uniqueid variable is set - send the F5AUTH cookie to client if { [info exists uniqueid] } { HTTP::header insert "Set-Cookie" "F5AUTH=$uniqueid; path=/; secure; HTTPOnly" unset uniqueid } }Configure your client SSL profile to ignore client certificates. The above iRule will trigger an SSL renegotiation for any URL that isn't in the /register namespace, and if the F5AUTH cookie does not exist. Once the client has presented a certificate, the F5AUTH cookie is written to the client so that the routine is never triggered again. The iRule also creates a session table entry, based on the unique ID of the F5AUTH cookie, so that you can store certificate data for later requests.
- Kevin_Davies_40
Nacreous
The problem here is you want to make layer 7 decisions on something that has happened in the past. The SSL connection has already been negotiated. My recommendation is when you make your decision, redirect them to virtual servers which have the SSL setup the way you want it.
when HTTP_REQUEST { if {not ([HTTP::uri] eq "/register")} { HTTP::redirect "https://[HTTP::host]:4443/" } }Then on port 4443 setup a virtual server with 2way SSL to the same backend pool.
- RiverFish
Altostratus
Does anyone have any suggestions? Is setting the 2-way ssl profile to "ignore" going to work? Currently it does not appear to work.
- Kevin_Davies_40
Nacreous
Just brainstorming here.... you will have to use a less secure profile until they come in then change the profile and force a SSL::renegotiate if they are not using /register. Something like...
when HTTP_REQUEST { if {!([HTTP::uri] eq "/register")} { SSL::profile ssl_2way SSL::renegotiate } }But this will make normal connections take longer to establish as a result because its a two step process for them instead of one.
- RiverFish
Altostratus
Thanks for your response, Kevin. I believe the "SSL::profile" command cannot be used in the "when HTTP_REQUEST" event, so I have shifted focus to the "SSL::mode ignore" command. We tested my iRule above and the ignore command is not working as hoped. The 2-way ssl profile that is assigned to the Virtual Server is requesting a cert from the client. Followed by a "Warning, No Certificate", then "Fatal, Handshake Failure". - Kevin_Davies_40
Nacreous
This assumes your application is sending HTTP traffic.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)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
