#include "ips_sd_pattern.h"
+#include <cctype>
+
#include <hs_compile.h>
#include <hs_runtime.h>
#define s_name "sd_pattern"
#define s_help "rule option for detecting sensitive data"
-#define SD_SOCIAL_PATTERN R"(\b\d{3}-\d{2}-\d{4}\b)"
-#define SD_SOCIAL_NODASHES_PATTERN R"(\b\d{9}\b)"
-#define SD_CREDIT_PATTERN_ALL R"(\b\d{4}[- ]?\d{4}[- ]?\d{2}[- ]?\d{2}[- ]?\d{3,4}\b)"
+#define SD_SOCIAL_PATTERN R"(\d{3}-\d{2}-\d{4})"
+#define SD_SOCIAL_NODASHES_PATTERN R"(\d{9})"
+#define SD_CREDIT_PATTERN_ALL R"(\d{4}\D?\d{4}\D?\d{2}\D?\d{2}\D?\d{3,4})"
// we need to update scratch in the main thread as each pattern is processed
// and then clone to thread specific after all rules are loaded. s_scratch is
std::string pii;
unsigned threshold = 1;
bool obfuscate_pii = false;
+ bool forced_boundary = false;
int (* validate)(const uint8_t* buf, unsigned long long buflen) = nullptr;
inline bool operator==(const SdPatternConfig& rhs) const
struct hsContext
{
- hsContext(const SdPatternConfig& c_, Packet* p_, const uint8_t* const start_)
- : config(c_), packet(p_), start(start_) { }
+ hsContext(const SdPatternConfig& c_, Packet* p_, const uint8_t* const start_,
+ const uint8_t* _buf, unsigned int _buflen )
+ : config(c_), packet(p_), start(start_), buf(_buf), buflen(_buflen) { }
+
+ bool has_valid_bounds(unsigned long long from, unsigned long long len)
+ {
+ bool left = false;
+ bool right = false;
+
+ // validate the left side
+
+ if ( from == 0 )
+ left = true;
+ else if ( from && !::isdigit((int)buf[from-1]) )
+ left = true;
+
+ // validate the right side
+
+ if ( from+len == buflen )
+ right = true;
+ else if ( from + len < buflen && !::isdigit((int)buf[from+len]) )
+ right = true;
+
+ return left and right;
+ }
unsigned int count = 0;
Packet* packet = nullptr;
const uint8_t* const start = nullptr;
const uint8_t* buf = nullptr;
+ unsigned int buflen = 0;
};
static int hs_match(unsigned int /*id*/, unsigned long long from,
assert(ctx->start);
unsigned long long len = to - from;
+
+ if ( ctx->config.forced_boundary && !ctx->has_valid_bounds(from, len) )
+ return 0;
+
if ( ctx->config.validate && ctx->config.validate(ctx->buf+from, len) != 1 )
return 0;
SnortState* ss = snort_conf->state + get_instance_id();
assert(ss->sdpattern_scratch);
- hsContext ctx(config, p, start);
- ctx.buf = buf;
+ hsContext ctx(config, p, start, buf, buflen);
hs_error_t stat = hs_scan(config.db, (const char*)buf, buflen, 0,
(hs_scratch_t*)ss->sdpattern_scratch, hs_match, (void*)&ctx);
config.pii = SD_CREDIT_PATTERN_ALL;
config.validate = SdLuhnAlgorithm;
config.obfuscate_pii = sc->obfuscate_pii;
+ config.forced_boundary = true;
}
else if (config.pii == "us_social")
{
config.pii = SD_SOCIAL_PATTERN;
config.obfuscate_pii = sc->obfuscate_pii;
+ config.forced_boundary = true;
}
else if (config.pii == "us_social_nodashes")
{
config.pii = SD_SOCIAL_NODASHES_PATTERN;
config.obfuscate_pii = sc->obfuscate_pii;
+ config.forced_boundary = true;
}
return true;
#include "sd_credit_card.h"
#include <cctype>
+#include <cassert>
#define ISSUER_SIZE 4
#define CC_COPY_BUF_LEN 20 /* 16 digits + 3 spaces/dashes + null */
char cc_digits[CC_COPY_BUF_LEN]; /* Normalized CC# string */
uint32_t j;
- if (buf == nullptr || buflen < MIN_CC_BUF_LEN)
- return 0;
-
- /* Generally, the buffer has two non-digits, one on either side. Sometimes,
- * when the buffer is pointing to the first line of the data, it might
- * start with a digit, instead of a non-digit. Strip the non-digits
- * only.
- */
- if (isdigit((int)buf[0]))
- buflen -= 1;
+ assert(buf);
- else
- {
- buf++;
- buflen -= 2;
- }
+ if (buflen < MIN_CC_BUF_LEN)
+ return 0;
/* If the first digit is greater than 6, this isn't one of the major
credit cards. */