Data Leakage Protection

Problem this snippet solves:

You can limit the possibility that sensitive data can be sent to a user to prevent data leakage (DLP). By using "Regular Expression" matching we scrub out credit card or other sensitive data from server responses.

Sensitive data regular expressions

The basis of this iRule is to use regular expression matching to find patterns in the data flowing out of your network.

General credit card regular expression from CreditCardScrubber which matches Diners, Amex, Visa, Mastercard and Discover card numbers:

(3[4|7]\d{2})([ ,-]?(\d{5}(\d{1})?)){2}|(4\d{3})([ ,-]?(\d{4})){3}|(5[1-5]\d{2})([ ,-]?(\d{4})){3}|(6011)([ ,-]?(\d{4})){3}

Additional regular expression suggestions (modified from OpenDLP)

Credit_Card_Track_1:              \%?[Bb]\d{13,19}^[-/.\w\s]{2,26}\^\d{2}[01]\d{4}
Credit_Card_Track_2:              \;\d{13,19}\=(\d{3}|)(\d{4}|\=)
Credit_Card_Track_Data:           [1-9]\d{2}-\d{2}-\d{4}(?!\d)
Mastercard:                       5[1-5]\d{2}[ -]\d{4}[ -]\d{4}[ -]\d{4}(?!\d)
Visa:                             4\d{3}[ -]\d{4}[ -]\d{4}[ -]\d{4}(?!\d)
AMEX:                             (34|37)\d{2}[ -]\d{6}[ -]\d{5}(?!\d)
Diners_Club_1:                    30[0-5]\d[ -]\d{6}[ -]\d{4}(?!\d)
Diners_Club_2:                    (36|38)\d{2}[ -]\d{6}[ -]\d{4}(?!\d)
Discover:                         6011[ -]\d{4}[ -]\d{4}[ -]\d{4}(?!\d)
JCB_1:                            3\d{3}[ -]\d{4}[ -]\d{4}[ -]\d{4}(?!\d)
JCB_2:                            (2131|1800)\d{11}(?!\d)
Social_Security_Number:           \d{3}[ -]\d{2}[ -]\d{4}(?!\d)

How to use this snippet:

Implementation Details

This iRule requires LTM v10. or higher.

Code :

when RULE_INIT {

# Log debug to /var/log/ltm? 1=yes, 0=no
set static::dlp_debug 1

# Mask or remove sensitive response content? 1=mask, 0=remove
set static::dlp_mask 1

# Regular expressions which match sensitive data we want to mask or remove
# Format for the list is:
#
# set static::regexes [list \
# {regex1} \
# {regex2} \
# {regexN} \
# ]
set static::regexes [list \
{\d{3}[- ]\d{2}[- ]\d{4}} \
{(3[4|7][0-9]{2})([ ,-]?([0-9]{5}([0-9]{1})?)){2}|(4[0-9]{3})([ ,-]?([0-9]{4})){3}|(5[1-5][0-9]{2})([ ,-]?([0-9]{4})){3}|(6011)([ ,-]?([0-9]{4})){3}} \
{another regex example wrapped in curly braces} \
]
if {$static::dlp_debug}{log local0. "\$static::regexes ([llength $static::regexes]): $static::regexes"}

# Create a STREAM::expression expression from the regexes
# The format is "&regex1&& &regex2&&"
set static::stream_expr ""
foreach re $static::regexes {
append static::stream_expr "&$re&& "
}
# Trim the last trailing space from the stream expression
set static::stream_expr [string trimright $static::stream_expr]
if {$static::dlp_debug}{log local0. "STREAM::expression: $static::stream_expr, [URI::encode $static::stream_expr]"}

if {$static::dlp_debug}{

# Some test strings to check for matches on
# This and the next section can be removed when you are done testing
set static::strings [list \
"123-45-6789" \
"123-45 6789" \
"text123-45-6789TEXT" \
"text123-45-6789" \
"amex378282246310005" \
"378282246310005" \
"4222222222222" \
"6331101999990016" \
"4012888888881881" \
"6011000990139424" \
"3566002020360505" \
]

# Debug testing of regexes on the test strings
# This and the previous section can be removed when you are done testing
foreach re $static::regexes {
log local0. "[string repeat - 100]"
log local0. "Checking strings using regex: $re"
foreach str $static::strings {
log local0. "string: $str, match: [regexp -inline $re $str] "
}
}
}
}

when HTTP_REQUEST {

# Prevent the server from sending chunked response data
if { [HTTP::version] eq "1.1" } {

# Force downgrade to HTTP 1.0, but still allow keep-alive connections.
# Since HTTP 1.1 is keep-alive by default, and 1.0 is not,
# we need make sure the headers reflect the keep-alive status.
if { [HTTP::header is_keepalive] } {
  HTTP::header replace "Connection" "Keep-Alive"
}
}

# Disable the stream filter by default
STREAM::disable
}
when HTTP_RESPONSE {

# Check if the response is text
if {[HTTP::header "Content-Type"] contains "text"}{

if {$static::dlp_debug}{log local0. "Enabling stream filter for this response with expression: $static::stream_expr / [URI::encode $static::stream_expr]"}
STREAM::expression $static::stream_expr
STREAM::enable
}
}
# STREAM_MATCHED is triggered when the stream filter find string is found
when STREAM_MATCHED {

# Log the string which matched the stream profile
# Comment out this logging once testing is complete so you do not log sensitive data from the iRule
log local0. "[string repeat * 100]"
log local0. "[IP::client_addr]:[TCP::client_port]: Matched sensitive data: [STREAM::match]"

# To replace the matched strings with asterisks use the following:
if {$static::dlp_mask}{
STREAM::replace "[string repeat * [string length [STREAM::match]]]"
}
}

Tested this on version:

10.0
Published Mar 17, 2015
Version 1.0
  • I have a similar use case, but with a non HTTP VIP that is in front of a DB2 database. It's a standard VS with only a TCP wan optimized profile attached that we need to DLP protect whether it be iRule or similar to ASM. In looking a sample packet capture I was able to capture a below from a sample database entry created to see if we can mask and log when we get hits for our SIEM.

     

    .X.Q...R

    .D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!....!F..7.S...1$P....'FOR READ ONLY WITH EXTENDED INDICATORS ..*.C...$$......SELECT * FROM tblAccounts..S.A...M ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!F..[.....U ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!.......!]..n.C...h$......00000SQL11014.........................          ..TESTDB           ..............U................................................ACCTINT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTINT......................................ACCTCHAR..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTCHAR......................................COMMENTS..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....COMMENTS......................................DT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....DT..........C....$...2.R...,"....I....!.$...!....!P...![..........$`$B.(.S..."$..v....>..?..%..        q.T......q.....B.S...<$....q........1111111111111111...Contains an account number 1111-1111-1111-1111.2019-07-08-16.15.29.444000.....[......2111111111111111...Contains an account number 2111-1111-1111-1111.2019-07-08-16.15.53.382000...q...

    ....3111111111111111...Contains an account number 3111-1111-1111-1111.2019-07-08-16.18.25.071000.&.R... "....I....!.......@@@@@@@@@@@@.Y.....S$..d...02000SQLRI01F.........................          ..TESTDB           ............. ..........+.R...%"....I....!....!.......@@@@@@@@@@@@...S....$.......................U.X.Q...R

    .D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!....!F..7.S...1$P....'FOR READ ONLY WITH EXTENDED INDICATORS ..*.C...$$......SELECT * FROM tblAccounts..S.A...M ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!F..[.....U ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!.......!]..n.C...h$......00000SQL11014.........................          ..TESTDB           ..............U................................................ACCTINT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTINT......................................ACCTCHAR..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTCHAR......................................COMMENTS..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....COMMENTS......................................DT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....DT..........C....$...2.R...,"....I....!.$...!....!P...![..........$`$B.(.S..."$..v....>..?..%..        q.T......q.....B.S...<$....q........1111111111111111...Contains an account number 1111-1111-1111-1111.2019-07-08-16.15.29.444000.....[......2111111111111111...Contains an account number 2111-1111-1111-1111.2019-07-08-16.15.53.382000...q...

    ....3111111111111111...Contains an account number 3111-1111-1111-1111.2019-07-08-16.18.25.071000.&.R... "....I....!.......@@@@@@@@@@@@.Y.....S$..d...02000SQLRI01F.........................          ..TESTDB           ............. ..........+.R...%"....I....!....!.......@@@@@@@@@@@@...S....$.......................p.X.Q...R

    .D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!....!F..7.S...1$P....'FOR READ ONLY WITH EXTENDED INDICATORS ..*.C...$$......SELECT * FROM tblAccounts..S.A...M ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!F..[.....U ..D!.......@@@@@@@@@@@@......@@@@@@@@@@@@........@@@@@@@@@@SYSLVL01....!.......!]..n.C...h$......00000SQL11014.........................          ..TESTDB           ..............U................................................ACCTINT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTINT......................................ACCTCHAR..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....ACCTCHAR......................................COMMENTS..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....COMMENTS......................................DT..........................TESTDB..TBLACCOUNTS....TBLACCOUNTS....DB2ADMIN....DT..........C....$...2.R...,"....I....!.$...!....!P...![..........$`$B.(.S..."$..v....>..?..%..        q.T......q.....B.S...<$....q........1111111111111111...Contains an account number 1111-1111-1111-1111.2019-07-08-16.15.29.444000.....[......2111111111111111...Contains an account number 2111-1111-1111-1111.2019-07-08-16.15.53.382000...q...

    ....3111111111111111...Contains an account number 3111-1111-1111-1111.2019-07-08-16.18.25.071000.&.R... "....I....!.......@@@@@@@@@@@@.Y.....S$..d...02000SQLRI01F.........................          ..TESTDB           ............. ..........+.R...%"....I....!....!.......@@@@@@@@@@@@...S....$.......................R