Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

iRule Optimization

Hi Folks,

a customer is using an iRule, which logs full POST requests, including the passwords of a login in cleartext. He asked me to masquerade the password. Unfortunately I didn't found an easy way to do this and therefore written the following snippet of code.

when HTTP_REQUEST {

    set data "POST /some_login HTTP/1.1\r\nHost: login.example.com\r\nAccept: */*\r\nContent-length: 65\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nusername=some_user&password=Thi`isMyHig!S%&cu)eP,ssword"

    log local0. "Request: $data"
    set user_password_match "&password="
    set user_password_match_len [string length $user_password_match]
    set user_password_pos [expr {[string last $user_password_match $data]+$user_password_match_len}]
    set user_password [string range $data $user_password_pos end]
    log local0. "User password is: $user_password"

    # Only necessary to have the same length of asterisk as chars in the origion password
    set user_password_list [split $user_password ""]
    set user_password_new ""
    foreach pwchar $user_password_list {
        append user_password_new "*"
    }

    log local0. "Masked password is: $user_password_new"

    set data_new [string map "$user_password $user_password_new" $data]

    log local0. "Request (masked): $data_new"
}

Of course the logging is testing purposes during the development. But to be honest, I don't believe that this is the most easiest and efficient way to reach my goal. Does anybody have an idea how to optimize this iRule and make it more efficient?

Thanks in advance.

Greets, svs

0
Rate this Question
Comments on this Question
Comment made 1 week ago by svs 280

This is an Example Output of the iRule:

<HTTP_REQUEST>: Request: POST /some_login HTTP/1.1  Host: login.example.com  Accept: */*  Content-length: 65  Content-Type: application/x-www-form-urlencoded    username=some_user&password=Thi`isMyHig!S%&cu)eP,ssword
<HTTP_REQUEST>: User password is: Thi`isMyHig!S%&cu)eP,ssword
<HTTP_REQUEST>: Masked password is: ***************************
<HTTP_REQUEST>: Request (masked): POST /some_login HTTP/1.1  Host: login.example.com  Accept: */*  Content-length: 65  Content-Type: application/x-www-form-urlencoded    username=some_user&password=***************************
0

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Comments on this Answer
Comment made 1 week ago by svs 280

Hi Jie,

thanks for your response.

I can't see why this iRule may be more efficient. This would result in an array of POST parameters, but I would need to loop through it, which may be more resource intensive then my way. Am I wrong? Furthermore, at the the point where I need to implement this code, only $data is available, which is filled within another event.

Greets, svs

0
Comment made 1 week ago by Jie 1707

Well, you can turn on timing for comparison, e.g.:

when HTTP_REQUEST timing on {
    set data "POST /some_login HTTP/1.1\r\nHost: login.example.com\r\nAccept: */*\r\nContent-length: 65\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nusername=some_user&password=Thi`isMyHig!S%&cu)eP,ssword"
    foreach x [split $data "&"] {
        if { $x starts_with "password=" } {
            log local0. "password=********"
        } else {
            log local0. "$x"
        }
    }
}
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hi svs,

you may try the iRule below. The password masking code function should run ~ 3-times faster then yours and also contains extended error handlings.

when RULE_INIT {
    set static::user_password_match "&password="
    set static::user_password_match_len [string length $static::user_password_match]    
}
when HTTP_REQUEST {
    # define input data
    set data "POST /some_login HTTP/1.1\r\nHost: login.example.com\r\nAccept: */*\r\nContent-length: 65\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nusername=some_user&password=Thi`isMyHig!S%xcu)eP,ssword&parmX=1&parmY=2&parmZ=3"
    # parse input data
    set data_new [substr $data 0 $static::user_password_match]
    if { [string length $data] != [string length $data_new] } then {
        set data_remain [findstr $data $static::user_password_match $static::user_password_match_len]
        if { $data_remain contains "&" } then {
            append data_new "$static::user_password_match[string repeat "*" [string length [substr $data_remain 0 "&"]]][findstr $data_remain "&" 0]"
        } else {
            append data_new "$static::user_password_match[string repeat "*" [string length $data_remain]]"
        }
    }
    # debug log 
    log local0.debug "Request: $data"
    log local0.debug "User password is: [substr $data_remain 0 "&"]"
    log local0.debug "Masked password is: [string repeat "*" [string length [substr $data_remain 0 "&"]]]"
    log local0.debug "Request (masked): $data_new"
}

Cheers, Kai

0
Comments on this Answer
Comment made 6 days ago by Kai Wilke 5536

Hi Svs,

based on Jie's post, you may also try the iRule below...

when HTTP_REQUEST {
    # define input data
    set data "POST /some_login HTTP/1.1\r\nHost: login.example.com\r\nAccept: */*\r\nContent-length: 65\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nusername=some_user&password=Thi`isMyHig!S%xcu)eP,ssword&parmX=1&parmY=2&parmZ=3"
    # parse input data
    set data_new ""
    foreach element [split $data "&"] {
        if { $element starts_with "password" } then {
            lappend data_new "password=[string repeat "*" [string length [findstr $element "=" 1]]]"
        } else {
            lappend data_new $element
        }
    }
    set data_new [join $data_new "&"]
    # debug log 
    log local0.debug "Request: $data"
    log local0.debug "Request (masked): $data_new"
}

... its much less complicated to read, but on the other hand slightly slower then my previous code example.

Cheers, Kai

0