@passmarked/ssl
Version:
Rules that relate to checking the SSL configuration of each individual resolved server from the domain to ensure locked down config with the broadest compatibility
268 lines (183 loc) • 6.61 kB
JavaScript
// pull in our modules
const S = require('string');
const url = require('url');
const cheerio = require('cheerio');
/**
* Regex for Chrome's regex:
* https://chromium.googlesource.com/chromium/chromium/+/master/chrome/browser/autofill/autofill_regex_constants.cc.utf8#122
**/
const CARD_PATTERNS = [
"card.?holder|name.*\\bon\\b.*card|cc.?name|cc.?full.?name|owner",
"karteninhaber", // de-DE
"nombre.*tarjeta", // es
"nom.*carte", // fr-FR
"nome.*cart", // it-IT
"名前", // ja-JP
"Имя.*карты", // ru
"信用卡开户名|开户名|持卡人姓名", // zh-CN
"持卡人姓名", // zh-TW
"card.?number|card.?#|card.?no|cc.?num|acct.?num",
"nummer", // de-DE
"credito|numero|número", // es
"numéro", // fr-FR
"カード番号", // ja-JP
"Номер.*карты", // ru
"信用卡号|信用卡号码", // zh-CN
"信用卡卡號", // zh-TW
"카드", // ko-KR
"verification|card identification|security code|cvn|cvv|cvc|csc"
];
/**
* Pulls the certificate and checks ge
**/
module.exports = exports = function(payload, fn) {
// get the data
var data = payload.getData();
// only if SSL
if(S( (data.url || '').toLowerCase() ).startsWith("https") == true) {
// debugging
payload.debug('fields', 'Skipping fields check as HTTPS is enabled for request');
// done
return fn(null);
}
// get the content
payload.getPageContent(function(err, content) {
// check for a error
if(err) {
// output the error
payload.error('fields', 'Problem getting the page content', err);
// done
return fn(err);
}
// check if the content is not empty
if(S(content || '').isEmpty() === true) {
// debug
payload.warning('fields', 'The content given was empty or blank');
// done
return fn(null);
}
// parse the url
var uri = url.parse(data.url);
// load the content
var $ = cheerio.load(content || '');
// get the lines of the file
var lines = content.split('\n');
// the last line for the code search
var lastLine = -1;
// flag if we found credit cards on this page
var creditCardFlag = false;
var passwordFlag = false;
// loop the fields on the page
$('body input').each(function(index, elem) {
// get the type of the input
var fieldType = $(elem).attr('type') || '';
var fieldAuto = $(elem).attr('autocomplete');
var fieldName = S($(elem).attr('name') || '').truncate(255).s;
// check if we found the type
if(S(fieldType || '').isEmpty() === true) {
// debug
payload.debug('fields', fieldType + ' was blank');
// done
return;
}
// check if password and protocol HTTPS
if(fieldType == 'text' &&
(uri.protocol || '').indexOf('http:') === 0 &&
creditCardFlag == false) {
// did we find the flag
var localCreditFlag = false;
// check if CC
if((fieldAuto || '').toLowerCase().indexOf('cc-') === 0) {
// yeap yeap
localCreditFlag = true;
}
// loop the patterns
for(var i = 0; i < CARD_PATTERNS.length; i++) {
// sanity check
if(localCreditFlag === true) break;
// check if this has anything to do with credit card information
if(fieldName.match(CARD_PATTERNS[i]) !== null) {
// debug
payload.debug('fields', CARD_PATTERNS[i] + ' matched for the name: ' + fieldName);
// set done
localCreditFlag = true;
// break it
break;
}
}
// should we add it ?
if(localCreditFlag === true) {
// build a code snippet
var build = payload.getSnippetManager().build(lines, lastLine, function(line) {
return line.toLowerCase().indexOf('<input') !== -1 &&
line.toLowerCase().indexOf('type="' + fieldType) !== -1;
});
// check if we got it
if(build) {
// set the subject
lastLine = build.subject;
// set as flagged
creditCardFlag = true;
// the occurrence to add
var occurrence = {
message: '',
identifiers: '',
display: 'code',
code: build
};
// if the name is blank
if(S(fieldName || '').isEmpty() === false) {
// yeap try and fallback to the autocomplete
occurrence.message = '<input name="$"';
occurrence.identifiers = [ fieldName ];
} else if(S(fieldAuto || '').isEmpty() === false) {
// yeap try and fallback to the autocomplete
occurrence.message = '<input autocomplete="$"';
occurrence.identifiers = [ fieldAuto ];
} else {
// well kinda out of ideas here
occurrence.message = '<input type="$" />';
occurrence.identifiers = [ fieldType ];
}
// add the rule
payload.addRule({
type: 'critical',
key: 'fields.creditcard',
message: 'Page will be marked as unsecure because of credit card input'
}, occurrence);
}
}
}
// check if password and protocol HTTPS
if(fieldType == 'password' &&
(uri.protocol || '').indexOf('http:') === 0 &&
passwordFlag == false) {
// build a code snippet
var build = payload.getSnippetManager().build(lines, lastLine, function(line) {
return line.toLowerCase().indexOf('<input') !== -1 &&
line.toLowerCase().indexOf('type="' + fieldType) !== -1;
});
// check if we got it
if(build) {
// set the subject
lastLine = build.subject;
// set as flagged
passwordFlag = true;
// add the rule
payload.addRule({
type: 'critical',
key: 'fields.password',
message: 'Page will be marked as unsecure because of password input'
}, {
message: '<input name="$"',
identifiers: [ uri.hostname ],
display: 'code',
code: build
});
}
}
});
// done !
fn(null);
});
};