🏠 Home 

HTTPOnly Password Protection

Скрипт защищает все парольные поля от доступа со стороны JavaScript.

// ==UserScript==
// @name        HTTPOnly Password Protection
// @description Скрипт защищает все парольные поля от доступа со стороны JavaScript.
// @run-at      document-start
// @match       *://*/*
// @grant       none
// @author      L7K
// @license     GPL-3.0-or-later
// @version 0.0.1.2019####081538
// @namespace https://greasyfork.org/users/306456
// ==/UserScript==
(function()
{
'use strict';
//Константы
const PASSWORD_PLACEHOLDER = "Здесь мог быть пароль, но его нет"; //Фраза, которую отдает input.value вместо пароля
const KEYBOARD_EVENT_STRING_PLACEHOLDER = "";
const KEYBOARD_EVENT_NUMERIC_PLACEHOLDER = 0;
const keyboardEventLeakSourcesString = [
"char", "code", "key", "keyIdentifier" ];
const keyboardEventLeakSourcesNumber = [
"charCode", "keyLocation", "keyCode", "location", "which"
];
let inputTypeOriginalDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "type");
let inputNameOriginalDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "name");
let isThisAPassword = function(inputField)
{
return ((inputField instanceof HTMLInputElement) && (inputTypeOriginalDescriptor.get.call(inputField).toLowerCase() == "password"));
};
//1. Заблокировать изменение input.type с "password" на любое другое значение
let setInputType = function(inputElementType) {
if (!isThisAPassword(this))
{
inputTypeOriginalDescriptor.set.call(this, inputElementType);
}
};
Object.defineProperty(HTMLInputElement.prototype, "type", {configurable: true, get: inputTypeOriginalDescriptor.get, set: setInputType});
let typeAttributeOriginalSetter = Element.prototype.setAttribute;
let typeAttributeOriginalGetter = Element.prototype.getAttribute;
let typeAttributeProtectedSetter = function(attributeName, attributeValue) {
if (!isThisAPassword(this) || (attributeName.toLowerCase() != "type"))
{
typeAttributeOriginalSetter.call(this, attributeName, attributeValue);
}
};
Object.defineProperty(Element.prototype, "setAttribute", {configurable: true, writable: false, value: typeAttributeProtectedSetter});
Object.defineProperty(Element.prototype, "getAttribute", {configurable: true, writable: false, value: typeAttributeOriginalGetter});
//2. Запретить чтение input.value для паролей
let inputValueOriginalDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
let getInputValue = function() {
if (isThisAPassword(this))
{
return PASSWORD_PLACEHOLDER;
}
else
{
return inputValueOriginalDescriptor.get.apply(this);
}
};
Object.defineProperty(HTMLInputElement.prototype, "value", {configurable: true, get: getInputValue});
//3. Запретить считывание нажатий клавиш в поле ввода пароля
//3.1. Не регистрировать обработчики клавиатурных событий для полей ввода паролей
let addInputEventListenerOriginal = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(listenerType, listener)
{
if (!isThisAPassword(this) || (!listenerType.toLowerCase().startsWith("key")))
{
addInputEventListenerOriginal.apply(this, arguments);
}
}
//3.2. Предотвратить считывание нажатий клавиш через обработчики событий элемента, внутри которого находится поле ввода пароля
let redefineKeyboardEventGetters = function (targetPrototype)
{
for (let i = 0; i < keyboardEventLeakSourcesString.length; i++)
{
let originalPropertyDescriptor = Object.getOwnPropertyDescriptor(targetPrototype, keyboardEventLeakSourcesString[i]);
if (originalPropertyDescriptor)
{
let protectedPropertyGetter = function()
{
if (isThisAPassword(this.target))
{
return KEYBOARD_EVENT_STRING_PLACEHOLDER;
}
else
{
return originalPropertyDescriptor.get.call(this);
}
};
Object.defineProperty(targetPrototype, keyboardEventLeakSourcesString[i], {configurable: true, get: protectedPropertyGetter, set: originalPropertyDescriptor.set });
}
}
for (let i = 0; i < keyboardEventLeakSourcesNumber.length; i++)
{
let key = keyboardEventLeakSourcesNumber[i];
let originalPropertyDescriptor = Object.getOwnPropertyDescriptor(targetPrototype, key);
if (originalPropertyDescriptor)
{
let protectedPropertyGetter = function()
{
if (isThisAPassword(this.target))
{
return KEYBOARD_EVENT_NUMERIC_PLACEHOLDER;
}
else
{
return originalPropertyDescriptor.get.call(this);
}
};
Object.defineProperty(targetPrototype, key, {configurable: true, get: protectedPropertyGetter, set: originalPropertyDescriptor.set });
}
}
};
redefineKeyboardEventGetters(KeyboardEvent.prototype);
redefineKeyboardEventGetters(UIEvent.prototype); // для UIEvent.which
//4. Предотвратить считывание паролей из FormData
class ProtectedFormData extends FormData
{
constructor(form)
{
super(form);
if (form)
{
//this.form = form;
let passwordFields = form.querySelectorAll("input[type='password']");
for (let i = 0; i < passwordFields.length; i++)
{
let key = inputNameOriginalDescriptor.get.call(passwordFields[i]);
if (key && (key.length > 0))
{
this.delete(key);
this.set(key, PASSWORD_PLACEHOLDER);
}
}
}
}
}
FormData = ProtectedFormData;
})();