Forum Discussion

svs's avatar
svs
Icon for Cirrus rankCirrus
Feb 15, 2017

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

 

4 Replies

  • This is an Example Output of the iRule:

    : 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
    : User password is: Thi`isMyHig!S%&cu)eP,ssword
    : Masked password is: ***************************
    : 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=***************************
    
  • 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

     

  • Hi,

    I have some comments about your irule:

    POST data are not included in HTTP_REQUEST but in HTTP_REQUEST_DATA. when you will have to log these informations, there will be:

    • [HTTP::request] in HTTP_REQUEST event
    • [HTTP::payload] in HTTP_REQUEST_DATA event

    if you want to parse only POST data, you can use this irule::

    when HTTP_REQUEST {
         Collect Post Data to be parsed in HTTP_REQUEST_DATA
        if { [HTTP::method] eq "POST" }{
            set clength 0
            if {[HTTP::header exists "Content-Length"] && [HTTP::header Content-Length] <= 1048576}{
              set clength [HTTP::header Content-Length]
            } else { set clength 1048576 }
            if { [info exists clength] && $clength > 0} { HTTP::collect $clength }
        }   
    }
    when HTTP_REQUEST_DATA {
        set payload [HTTP::payload]
         Convert POST Data to URI with query string to extract password parameter
        set password  [URI::query "/?$payload" password]
         Replace Post 
        set new_data [string map "password=$password password=[string repeat "*" [string length $password]]"  $payload]
    }