Insert Client Certificate In Serverside HTTP Headers
Problem this snippet solves:
An example iRule that pulls certain information from a client cert and passes it along to backend server in HTTP headers.
Here's one that illustrates how to use the "session" command in conjunction with SSL certificate information to allow passing of information to backend webservers.
As above, I want to deliver ssl cert serial number to http server behind BIG-IP, and redirect the users who has no cert to an error page at same time.
Code :
# client_cert_header_insert_rule
when CLIENTSSL_CLIENTCERT {
# Check if client presented at least one cert
if {[SSL::cert count] > 0}{
# Insert the following fields in the session table with a timeout of 7200 seconds:
# Do the processing now as opposed to in HTTP_REQUEST as there
# can be many HTTP requests using the same SSL session ID
#
# Index - item
# 0 - base64 encoding of the client SSL cert
# 1 - serial number of the cert
# 2 - the verification status text for the client cert against the client SSL profile's root CA cert
session add ssl [SSL::sessionid] [list \
[SSL::verify_result] \
[b64encode [SSL::cert 0]] \
[X509::serial_number [SSL::cert 0]] \
] 7200
log local0. "[IP::client_addr]:[TCP::client_port]: Added session data for cert. Status:\
[X509::verify_cert_error_string [lindex [session lookup ssl [SSL::sessionid]] 0]] with key [SSL::sessionid]"
}
}
when HTTP_REQUEST {
# Check if SSL session ID is in the cache (SSL::sessionid returns 64 zeroes if it's not in v9 and a null string in v10)
if {[SSL::sessionid] ne "0000000000000000000000000000000000000000000000000000000000000000" && [SSL::sessionid] ne ""}{
# Get the session table entry (a TCL list) for this session ID
set session_data [session lookup ssl [SSL::sessionid]]
# Check if the first element of the session table entry for this session ID is 0 (status for successful cert validation)
if {[lindex $session_data 0] == 0}{
log local0. "[IP::client_addr]:[TCP::client_port]: Valid cert per session table entry. Inserting cert details in HTTP headers."
# Insert cert details in the HTTP headers
HTTP::header insert SSLClientCertStatus "ok"
HTTP::header insert SSLClientCertb64 [lindex $session_data 1]
HTTP::header insert SSLClientCertSN [lindex $session_data 2]
# Exit this event in this rule
return
}
}
# If we're still in this rule, cert wasn't valid
# so send HTTP 302 redirect to an error page
HTTP::respond 302 Location "http://[HTTP::host]/cert_error.html"
log local0. "[IP::client_addr]:[TCP::client_port]: No or invalid cert from client."
}2 Comments
- tnaumovs_375792
Nimbostratus
Just note that the solution using ‘insert’ contains a vulnerability where the cert header info can be manipulated. To correct use 'header replace'
Ex. HTTP::header replace SSLClientCertSN [lindex $session_data 2]
- gersbah
Cirrostratus
If you are worried about possible tampering, 'replace' is only marginally better than 'insert'.
'replace' only replaces the last occurence of the header. So if an attacker adds their forged header twice, you end up with pretty much the same situation.
To be absolutely safe, you can do a 'remove' first (which removes all occurences of the header) and then 'insert'.