哪些字符被认为不安全,以允许用户在文本输入字段中键入内容,以防止黑客等执行SQL注入等?应该阻止哪些字符输入?
为了记录,我目前正在使用以下HTML阻止AngularJS的输入:
<input type="text" ng-pattern-restrict='^[^<>#*"]+$'>
这是我发现的漂亮指令:
/* RESTRICT CERTAIN CHARACTERS IN INPUT FIELDS
<input type="text" ng-pattern-restrict="^[A-Za-z0-9]*$">
Alpha numeric chars only ^[A-Za-z0-9]*$
Date format YYYY-MM-DD ^\d{0,4}(-\d{0,2}(-\d{0,2})?)?$
*/
/*jslint browser: true, plusplus: true, indent: 2 */
// This will be removed by uglify, along with the DEBUG code
if (typeof DEBUG === 'undefined') {
DEBUG = true;
}
// Logic and fallbacks based on the following SO answers:
// - Getting caret position cross browser: http://stackoverflow.com/a/9370239/147507
// - Selection API on non input-text fields: http://stackoverflow.com/a/24247942/147507
// - Set cursor position on input text: http://stackoverflow.com/q/5755826/147507
angular.module('ngPatternRestrict', [])
.directive('ngPatternRestrict', ['$log', function ($log) {
'use strict';
function showDebugInfo() {
$log.debug("[ngPatternRestrict] " + Array.prototype.join.call(arguments, ' '));
}
return {
restrict: 'A',
require: "?ngModel",
compile: function uiPatternRestrictCompile() {
DEBUG && showDebugInfo("Loaded");
return function ngPatternRestrictLinking(scope, iElement, iAttrs, ngModelController) {
var regex, // validation regex object
oldValue, // keeping track of the previous value of the element
caretPosition, // keeping track of where the caret is at to avoid jumpiness
// housekeeping
initialized = false, // have we initialized our directive yet?
eventsBound = false, // have we bound our events yet?
// functions
getCaretPosition, // function to get the caret position, set in detectGetCaretPositionMethods
setCaretPosition; // function to set the caret position, set in detectSetCaretPositionMethods
//-------------------------------------------------------------------
// caret position
function getCaretPositionWithInputSelectionStart() {
return iElement[0].selectionStart; // we need to go under jqlite
}
function getCaretPositionWithDocumentSelection() {
// create a selection range from where we are to the beggining
// and measure how much we moved
var range = document.selection.createRange();
range.moveStart('character', -iElement.val().length);
return range.text.length;
}
function getCaretPositionWithWindowSelection() {
var s = window.getSelection(),
originalSelectionLength = String(s).length,
selectionLength,
didReachZero = false,
detectedCaretPosition,
restorePositionCounter;
do {
selectionLength = String(s).length;
s.modify('extend', 'backward', 'character');
// we're undoing a selection, and starting a new one towards the beggining of the string
if (String(s).length === 0) {
didReachZero = true;
}
} while (selectionLength !== String(s).length);
detectedCaretPosition = didReachZero ? selectionLength : selectionLength - originalSelectionLength;
s.collapseToStart();
restorePositionCounter = detectedCaretPosition;
while (restorePositionCounter-- > 0) {
s.modify('move', 'forward', 'character');
}
while (originalSelectionLength-- > 0) {
s.modify('extend', 'forward', 'character');
}
return detectedCaretPosition;
}
function setCaretPositionWithSetSelectionRange(position) {
iElement[0].setSelectionRange(position, position);
}
function setCaretPositionWithCreateTextRange(position) {
var textRange = iElement[0].createTextRange();
textRange.collapse(true);
textRange.moveEnd('character', position);
textRange.moveStart('character', position);
textRange.select();
}
function setCaretPositionWithWindowSelection(position) {
var s = window.getSelection(),
selectionLength;
do {
selectionLength = String(s).length;
s.modify('extend', 'backward', 'line');
} while (selectionLength !== String(s).length);
s.collapseToStart();
while (position--) {
s.modify('move', 'forward', 'character');
}
}
// HACK: Opera 12 won't give us a wrong validity status although the input is invalid
// we can select the whole text and check the selection size
// Congratulations to IE 11 for doing the same but not returning the selection.
function getValueLengthThroughSelection(input) {
// only do this on opera, since it'll mess up the caret position
// and break Firefox functionality
if (!/Opera/i.test(navigator.userAgent)) {
return 0;
}
input.focus();
document.execCommand("selectAll");
var focusNode = window.getSelection().focusNode;
return (focusNode || {}).selectionStart || 0;
}
//-------------------------------------------------------------------
// event handlers
function revertToPreviousValue() {
if (ngModelController) {
scope.$apply(function () {
ngModelController.$setViewValue(oldValue);
});
}
iElement.val(oldValue);
if (!angular.isUndefined(caretPosition)) {
setCaretPosition(caretPosition);
}
}
function updateCurrentValue(newValue) {
oldValue = newValue;
caretPosition = getCaretPosition();
}
function genericEventHandler(evt) {
DEBUG && showDebugInfo("Reacting to event:", evt.type);
//HACK Chrome returns an empty string as value if user inputs a non-numeric string into a number type input
// and this may happen with other non-text inputs soon enough. As such, if getting the string only gives us an
// empty string, we don't have the chance of validating it against a regex. All we can do is assume it's wrong,
// since the browser is rejecting it either way.
var newValue = iElement.val(),
inputValidity = iElement.prop("validity");
if (newValue === "" && iElement.attr("type") !== "text" && inputValidity && inputValidity.badInput) {
DEBUG && showDebugInfo("Value cannot be verified. Should be invalid. Reverting back to:", oldValue);
evt.preventDefault();
revertToPreviousValue();
} else if (newValue === "" && getValueLengthThroughSelection(iElement[0]) !== 0) {
DEBUG && showDebugInfo("Invalid input. Reverting back to:", oldValue);
evt.preventDefault();
revertToPreviousValue();
} else if (regex.test(newValue)) {
DEBUG && showDebugInfo("New value passed validation against", regex, newValue);
updateCurrentValue(newValue);
} else {
DEBUG && showDebugInfo("New value did NOT pass validation against", regex, newValue, "Reverting back to:", oldValue);
evt.preventDefault();
revertToPreviousValue();
}
}
//-------------------------------------------------------------------
// setup based on attributes
function tryParseRegex(regexString) {
try {
regex = new RegExp(regexString);
} catch (e) {
throw "Invalid RegEx string parsed for ngPatternRestrict: " + regexString;
}
}
//-------------------------------------------------------------------
// setup events
function bindListeners() {
if (eventsBound) {
return;
}
iElement.bind('input keyup click', genericEventHandler);
DEBUG && showDebugInfo("Bound events: input, keyup, click");
}
function unbindListeners() {
if (!eventsBound) {
return;
}
iElement.unbind('input', genericEventHandler);
//input: HTML5 spec, changes in content
iElement.unbind('keyup', genericEventHandler);
//keyup: DOM L3 spec, key released (possibly changing content)
iElement.unbind('click', genericEventHandler);
//click: DOM L3 spec, mouse clicked and released (possibly changing content)
DEBUG && showDebugInfo("Unbound events: input, keyup, click");
eventsBound = false;
}
//-------------------------------------------------------------------
// initialization
function readPattern() {
var entryRegex = !!iAttrs.ngPatternRestrict ? iAttrs.ngPatternRestrict : iAttrs.pattern;
DEBUG && showDebugInfo("RegEx to use:", entryRegex);
tryParseRegex(entryRegex);
}
function notThrows(testFn, shouldReturnTruthy) {
try {
return testFn() || !shouldReturnTruthy;
} catch (e) {
return false;
}
}
function detectGetCaretPositionMethods() {
var input = iElement[0];
// Chrome will throw on input.selectionStart of input type=number
// See http://stackoverflow.com/a/21959157/147507
if (notThrows(function () { return input.selectionStart; })) {
getCaretPosition = getCaretPositionWithInputSelectionStart;
} else {
// IE 9- will use document.selection
// TODO support IE 11+ with document.getSelection()
if (notThrows(function () { return document.selection; }, true)) {
getCaretPosition = getCaretPositionWithDocumentSelection;
} else {
getCaretPosition = getCaretPositionWithWindowSelection;
}
}
}
function detectSetCaretPositionMethods() {
var input = iElement[0];
if (typeof input.setSelectionRange === 'function') {
setCaretPosition = setCaretPositionWithSetSelectionRange;
} else if (typeof input.createTextRange === 'function') {
setCaretPosition = setCaretPositionWithCreateTextRange;
} else {
setCaretPosition = setCaretPositionWithWindowSelection;
}
}
function initialize() {
if (initialized) {
return;
}
DEBUG && showDebugInfo("Initializing");
readPattern();
oldValue = iElement.val();
if (!oldValue) {
oldValue = "";
}
DEBUG && showDebugInfo("Original value:", oldValue);
bindListeners();
detectGetCaretPositionMethods();
detectSetCaretPositionMethods();
initialized = true;
}
function uninitialize() {
DEBUG && showDebugInfo("Uninitializing");
unbindListeners();
}
iAttrs.$observe("ngPatternRestrict", readPattern);
iAttrs.$observe("pattern", readPattern);
scope.$on("$destroy", uninitialize);
initialize();
};
}
};
}]);
请注意,还必须在开始时加载此指令:
var app = angular.module("myApp", ['ngPatternRestrict']);
答案 0 :(得分:1)
正如其他人指出的那样,您应该通过使用准备好的语句在后端解决此问题。这是唯一的方法,因为可以相对轻松地编辑客户端。
例如,在Java中,您可以使用以下代码:
PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, userInput);
stmt.execute();
通过这种方式将输入作为纯文本输入查询中,因此不会出现SQL注入问题,Little Bobby Tables可以上学了。