I have made a email validation program in C#, but how do I check data outside of the string?
Here is my C# code:
private bool CheckEmail()
{
string email1 = email.Text;
//calculating the length of the email
int EmailLen = email1.Length;
int num = 0;
//the first character of the email must not be the "#"
if (email1.Substring(0, 1) != "#")
{
//checking the email entered after the first character as it is not a "#" so i will start from 1.
for (int i = 1; i < EmailLen; i++)
{
//prevents there from being two "#"next to each other
if (email1[i] == '#' && (i + 1) < email1.Length && email1[i + 1] != '#')
{
//if there is an "#" in the email then num will increase by one
num = num + 1;
//now the stored value of i is the position where the "#" is placed. j will be i+2 as there should be at least one character after the "#"
int j = i + 2;
if (j < EmailLen)
{
for (int k = j; k < EmailLen; k++)
{
//when it finds a "." In the email, the character after the "." Should not be empty or have a space, e.g. it should be something like ".com"
if (email1[k] == '.' && k + 1 < email1.Length && email1[k + 1] != ' ')
{
num = num + 1;
}
}
}
else
{
break;
}
}
}
}
else
{
num = 0;
}
//if the num is 2, then the email is valid, otherwise it is invalid. If the email had more than one "#" for example, the num will be greater than 2.
if (num == 2)
{
return true;
}
else
{
return false;
}
}
When I try typing in “aa#”, I get this error: “Index and length must refer to a location within the string.”
When I ty typing in aa#a. , I get this error: “Index and length must refer to a location within the string.”
You cannot access data outside of the string. This is for a very good reason - doing so would violate the type safety that is a major attraction of a virtual machine like the .NET CLR.
You just want to check your bounds to make sure you're not trying to access a part of the string that doesn't exist. BTW, for checking single characters, you totally want to be doing email1[i], not email1.Substring(i, 1), so you're not constructing new string objects left, right and center.
Your first test should be:
if (email1[i] == '#' && i + 1 < email1.Length && email1[i + 1] != '#')
Your problem is
email1.Substring(i + 1, 1)
On the last iteration of the for loop, i == EmailLen -1.
So i + 1 == EmailLen, which is one past the end of the string.
Related
My program needs to check for 3 consecutive letters in a string (and check through the whole string). I could make it check for them in a harcoded manner, like "check for qwe", "check for "wer", check for "ert", but that looks messy and badly done.
static void Main(string[] args)
{
string BadLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
for (int i = 1; i <= 30; i++)
{
// This checks if it contains "qwe" but i want it to
// cycle through the rest (such as "wer" or "rty")
if (password.Contains(BadLetters.Substring(0, 3))) {
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
Console.ReadKey();
}
The problem is that this only checks the first 3 letters of BadLetters (qwe), and it doesn't look for "ert", etc.
It would be better if you loop on the password variable instead, like this:
string badLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
for (int i = 0; i < password.Length-2; i++)
{
if (badLetters.Contains(password.Substring(i,3)))
{
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
Obviously you also have to check that the password is at least 3 characters.
This loop could fail on keyboard row crossing letters, i.e. "opa" or "pas", that should be considered right values, so you could do this instead:
string badLettersR1 = "qwertyuiop";
string badLettersR2 = "asdfghjkl";
string badLettersR3 = "zxcvbnm";
string password = "Blablauio";
for (int i = 0; i < password.Length-2; i++)
{
if (badLettersR1.Contains(password.Substring(i,3)) ||
badLettersR2.Contains(password.Substring(i,3)) ||
badLettersR3.Contains(password.Substring(i,3)))
{
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
Maybe you can try to edit your string, so the 3 letters are gone and then you do the same job as before for the next ones.
Or you can add to the 2 variables firstletter and secondletter 4 so it skips the first 3 as well and is repeating with the following ones
Sry i understood your string as 3 in a row...
You need to iterate through each character in password, find its index in BadLetters, and check if the next two characters in password match the next two in BadLetters. I also changed the stop condition of the for loop because you only need to iterate through the antepenultimate character in password
string BadLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
for (int i = 0; i < password.Length - 2; i++)
{
var j = BadLetters.IndexOf(password[i]);
if (j > -1 && j + 2 < BadLetters.Length &&
password[i + 1] == BadLetters[j + 1] &&
password[i + 2] == BadLetters[j + 2])
{
Console.WriteLine("password contains 3 consequtive letters in BadLetters");
}
}
The simple one I found is
using System;
public class Program
{
public static void Main()
{
string BadLetters = "qwertyuiopasdfghjklzxcvbnm";
string password = "Blablauio";
Console.WriteLine(password.IndexOf(BadLetters.Substring(0,3))>=0?"Present":"Not Present");
Console.ReadLine();
}
}
You may need to check for null condition of both strings
TL; DR
You could just go through array of symbols and compare it's indexes like this:
if (BadLetters.IndexOf(my_word[i]) - BadLetter.IndexOf(my_word[i-1]) == 1) {
Console.WriteLine("Consequent letters detected!");
}
you could just count consequent letters and alert when count more then 3
I provide detailed code with all lines from keyboard. And you could add another lines (i.e. upper case) without any modification of code.
You also have control on N - number of forbidden consequent characters in string.
Also there is Check method which using only for demonstrate results of working:
q - ok
qw - ok
qwe - password contains 3 consequtive letters in BadLetters
abdfsk - ok
ehjk - password contains 3 consequtive letters in BadLetters
bnm - password contains 3 consequtive letters in BadLetters
The code
Code on .net fiddle: https://dotnetfiddle.net/4oILkj
public static String[] KeyboardLines = new [] {
"1234567890",
"qwertyuiop[]",
"asdfghjkl;'\\",
"`zxcvbnm,./"
};
public static Int32 GetLine(char c){
for (int i = 0; i < KeyboardLines.Length; i++) {
if (KeyboardLines[i].IndexOf(c) > -1) {
return i;
};
}
return -1;
}
public static bool HasConsequenceLetters(string str, int n = 3) {
if (str.Length < n) {
return false;
}
char previousLetter = str[0];
int previousLine = GetLine(previousLetter);
int previousLetterIndex = KeyboardLines[previousLine].IndexOf(previousLetter);
Int32 consequentLettersCount = 1;
for (int i = 1; i < str.Length; i++) {
var currentLetter = str[i];
var currentLine = GetLine(currentLetter);
var currentLetterIndex = KeyboardLines[currentLine].IndexOf(currentLetter);
if (currentLine != -1 && currentLine == previousLine) {
if (currentLetterIndex - previousLetterIndex == 1) {
consequentLettersCount += 1;
}
}
else {
consequentLettersCount = 1;
}
if (consequentLettersCount == n) {
return true;
}
previousLetter = currentLetter;
previousLetterIndex = currentLetterIndex;
previousLine = currentLine;
}
return false;
}
Improvements
This approach could be improved if GetLine function will return character index with line number and then compare not just characters but pairs (LetterLine, LetterIndex). But this require from us to using tuples or classes but I don't think you really want this.
I have below code:
String[] splititemcol;
String[] splititem;
String singlestring;
while (reader.Read())
{
splititemcol = reader.GetValue(2).ToString().Split((char)16); //split each item
for (int i = 0; i < splititemcol.Count(); i++)
{
splititem = splititemcol[i].ToString().Split((char)14);
resultstr.Append("<tr><td>" + splititem[0] + "</td><td>");
singlestring = "";
for(int k=0;k<splititem.Count();k++)
{
if(k==2)
{
singlestring = splititem[k].ToString();
break;
}
}
resultstr.Append(singlestring + "</td></tr>");
}
}
In above code I could get value of 3rd splititem.
String[] splititemcol;
String[] splititem;
String singlestring;
while (reader.Read())
{
splititemcol = reader.GetValue(2).ToString().Split((char)16); //split each item
for (int i = 0; i < splititemcol.Count(); i++)
{
splititem = splititemcol[i].ToString().Split((char)14);
resultstr.Append("<tr><td>" + splititem[0] + "</td><td>");
singlestring =splititem[2].ToString();
resultstr.Append(singlestring + "</td></tr>");
}
}
In above code I try to get value of 3rd splititem only by array index i.e. without foreach.
But it throws Index was outside the bounds error on line 9 as below.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.IndexOutOfRangeException: Index was outside the bounds of the array.
When I test splititem.Count it shows 4.
EDIT:
I manually store every value of the array in variable as like this and all are return values. So I come to the conclusion that either we have to iterate array by for loop or this script is stuck due to my strange delimiter in the strings (character 14).
String[] splititemcol;
String[] splititem;
String singlestring;
String item="";
String weight="";
String quantity="";
String amount="";
while (reader.Read())
{
splititemcol = reader.GetValue(2).ToString().Split((char)16); //split each item
for (int i = 0; i < splititemcol.Count(); i++)
{
splititem = splititemcol[i].ToString().Split((char)14);
resultstr.Append("<tr><td>" + splititem[0] + "</td><td>");
singlestring = "";
for(int k=0;k<splititem.Count();k++)
{
if (k == 0)
item = splititem[k].ToString();
else if (k == 1)
weight = splititem[k].ToString();
else if (k == 2)
quantity = splititem[k].ToString();
else if (k == 3)
amount = splititem[k].ToString();
}
resultstr.Append(weight + "</td><td>" + quantity + "</td><td>" + amount + "</td></tr>");
}
}
Thank you for all you guys try to give solution in this issue.
That means splititem[2] doesn't exists. In your first case you have the below condition which considering only lines which will have splititem[2] but in second case you are trying to access index 2 directly resulting in exception
if(k==2)
{
singlestring = splititem[k].ToString();
break;
}
Compare this (from first snippet):
if(k==2)
{
singlestring = splititem[k].ToString();
break;
}
with this (from the second snippet):
singlestring =splititem[2].ToString();
In the first case you make a check and provided that k==2 is true you read the corresponding value. That misses from the second case and nobody guarantees that splititem has a Length of 3.
I am making a code that decrements the line index in an array of strings. My array is like this:
1.ExampleFirst\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
2.ExampleSecond\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
and so on. The lengths of the lines are not the same.
I want the text to be like this:
0.ExampleFirst\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
1.ExampleSecond\n
SomeText\n
SomeOtherText\n
FinalLine\n\n
I have made this code:
int s = 0;
while(s < lineCounter.Count())
{
if (int.TryParse(lineCounter[s].Substring(0, 1), out v) == true && lineCounter[s] != "\n")
{
int m = int.Parse(lineCounter[s].Substring(0,1));
lineCounter[s].Remove(0, lineCounter[s].IndexOf(".")).Insert(0, (m - 1).ToString());
Console.WriteLine(lineCounter[s]);
}
else
Console.WriteLine(lineCounter[s]);
s++;
The "if" is executed only when the line contains the number and when the line is not a new line. The else is executed to write the other lines in the array.(I'm using console.writeLine to see the results. I know I have to change that part)
When I execute this code, I get the following exception in the "if" statement:
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
Additional information: Index and length must refer to a location within the string.
To me this means that "if" is executed even when the new line between the last line of the first text block and the first line of the second text block is encountered. I can't explain why. Help please!
Declaring dotIndex with combination of string.Remove() and string.Insert() may do the trick.
string[] lineCounter = new string[]{
"1.ExampleFirst\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n\n",
"2.ExampleSecond\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n\n"
};
for (int i = 0; i < lineCounter.Count(); ++i) {
int dotIndex = lineCounter[i].IndexOf('.');
if (dotIndex < 1) //must be at least in the position of 2 or above
continue;
int lineIndex = 0;
if (int.TryParse(lineCounter[i].Substring(0, dotIndex), out lineIndex)) { //if can be parsed
lineIndex--; //decrement lineIndex
lineCounter[i] = lineIndex.ToString() + lineCounter[i].Remove(0, dotIndex);
}
}
I prefer to use for-loop to make the loop more definite, but you could change that to while/do.
This works fine in my PC. Output:
Edit:
All the results should be in the lineCounter. If you want to see them along the function, you could do:
for (int i = 0; i < lineCounter.Count(); ++i) {
int dotIndex = lineCounter[i].IndexOf('.');
if (dotIndex < 1) { //must be at least in the position of 2 or above
//Print here
continue;
}
int lineIndex = 0;
if (int.TryParse(lineCounter[i].Substring(0, dotIndex), out lineIndex)) { //if can be parsed
lineIndex--; //decrement lineIndex
lineCounter[i] = lineIndex.ToString() + lineCounter[i].Remove(0, dotIndex);
}
//Print here also
}
you probably want this:
string[] lineCounter=new string[]{
"1.ExampleFirst\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n",
"\n",
"2.ExampleSecond\n",
" SomeText\n",
" SomeOtherText\n",
" FinalLine\n",
"\n"
};
int v = 0;
int s = 0;
while (s < lineCounter.Count())
{
if (int.TryParse(lineCounter[s].Substring(0, 1), out v) == true && lineCounter[s] != "\n")
{
int m = int.Parse(lineCounter[s].Substring(0, 1));
Console.WriteLine(lineCounter[s].Remove(0, lineCounter[s].IndexOf(".")).Insert(0, (m - 1).ToString()));
}
else
Console.WriteLine(lineCounter[s]);
s++;
}
I believe you may be having issues with empty lines on the string array.
Maybe something like this works for you.
IEnumerable<string> ShiftIndexes(IEnumerable<string> lines) {
foreach (string line in lines) {
if (!string.IsNullOrEmpty(line) && char.IsDigit(line, 0)) {
int dotPos = line.IndexOf('.');
int index = int.Parse(line.SubString(0, dotPos));
yield return (index - 1).ToString() + line.SubString(dotPos);
}
else
yield return line;
}
}
And then use it like this:
string[] shiftedLines = ShiftIndexes(originalLines).ToArray();
I am trying to extract information out of a string - a fortran formatting string to be specific. The string is formatted like:
F8.3, I5, 3(5X, 2(A20,F10.3)), 'XXX'
with formatting fields delimited by "," and formatting groups inside brackets, with the number in front of the brackets indicating how many consecutive times the formatting pattern is repeated. So, the string above expands to:
F8.3, I5, 5X, A20,F10.3, A20,F10.3, 5X, A20,F10.3, A20,F10.3, 5X, A20,F10.3, A20,F10.3, 'XXX'
I am trying to make something in C# that will expand a string that conforms to that pattern. I have started going about it with lots of switch and if statements, but am wondering if I am not going about it the wrong way?
I was basically wondering if some Regex wizzard thinks that Regular expressions can do this in one neat-fell swoop? I know nothing about regular expressions, but if this could solve my problem I am considering putting in some time to learn how to use them... on the other hand if regular expressions can't sort this out then I'd rather spend my time looking at another method.
This has to be doable with Regex :)
I've expanded my previous example and it test nicely with your example.
// regex to match the inner most patterns of n(X) and capture the values of n and X.
private static readonly Regex matcher = new Regex(#"(\d+)\(([^(]*?)\)", RegexOptions.None);
// create new string by repeating X n times, separated with ','
private static string Join(Match m)
{
var n = Convert.ToInt32(m.Groups[1].Value); // get value of n
var x = m.Groups[2].Value; // get value of X
return String.Join(",", Enumerable.Repeat(x, n));
}
// expand the string by recursively replacing the innermost values of n(X).
private static string Expand(string text)
{
var s = matcher.Replace(text, Join);
return (matcher.IsMatch(s)) ? Expand(s) : s;
}
// parse a string for occurenses of n(X) pattern and expand then.
// return the string as a tokenized array.
public static string[] Parse(string text)
{
// Check that the number of parantheses is even.
if (text.Sum(c => (c == '(' || c == ')') ? 1 : 0) % 2 == 1)
throw new ArgumentException("The string contains an odd number of parantheses.");
return Expand(text).Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
}
I would suggest using a recusive method like the example below( not tested ):
ResultData Parse(String value, ref Int32 index)
{
ResultData result = new ResultData();
Index startIndex = index; // Used to get substrings
while (index < value.Length)
{
Char current = value[index];
if (current == '(')
{
index++;
result.Add(Parse(value, ref index));
startIndex = index;
continue;
}
if (current == ')')
{
// Push last result
index++;
return result;
}
// Process all other chars here
}
// We can't find the closing bracket
throw new Exception("String is not valid");
}
You maybe need to modify some parts of the code, but this method have i used when writing a simple compiler. Although it's not completed, just a example.
Personally, I would suggest using a recursive function instead. Every time you hit an opening parenthesis, call the function again to parse that part. I'm not sure if you can use a regex to match a recursive data structure.
(Edit: Removed incorrect regex)
Ended up rewriting this today. It turns out that this can be done in one single method:
private static string ExpandBrackets(string Format)
{
int maxLevel = CountNesting(Format);
for (int currentLevel = maxLevel; currentLevel > 0; currentLevel--)
{
int level = 0;
int start = 0;
int end = 0;
for (int i = 0; i < Format.Length; i++)
{
char thisChar = Format[i];
switch (Format[i])
{
case '(':
level++;
if (level == currentLevel)
{
string group = string.Empty;
int repeat = 0;
/// Isolate the number of repeats if any
/// If there are 0 repeats the set to 1 so group will be replaced by itself with the brackets removed
for (int j = i - 1; j >= 0; j--)
{
char c = Format[j];
if (c == ',')
{
start = j + 1;
break;
}
if (char.IsDigit(c))
repeat = int.Parse(c + (repeat != 0 ? repeat.ToString() : string.Empty));
else
throw new Exception("Non-numeric character " + c + " found in front of the brackets");
}
if (repeat == 0)
repeat = 1;
/// Isolate the format group
/// Parse until the first closing bracket. Level is decremented as this effectively takes us down one level
for (int j = i + 1; j < Format.Length; j++)
{
char c = Format[j];
if (c == ')')
{
level--;
end = j;
break;
}
group += c;
}
/// Substitute the expanded group for the original group in the format string
/// If the group is empty then just remove it from the string
if (string.IsNullOrEmpty(group))
{
Format = Format.Remove(start - 1, end - start + 2);
i = start;
}
else
{
string repeatedGroup = RepeatString(group, repeat);
Format = Format.Remove(start, end - start + 1).Insert(start, repeatedGroup);
i = start + repeatedGroup.Length - 1;
}
}
break;
case ')':
level--;
break;
}
}
}
return Format;
}
CountNesting() returns the highest level of bracket nesting in the format statement, but could be passed in as a parameter to the method. RepeatString() just repeats a string the specified number of times and substitutes it for the bracketed group in the format string.
is anybody aware of a list of exactly what triggers ASP.NET's HttpRequestValidationException? [This is behind the common error: "A potentially dangerous Request.Form value was detected," etc.]
I've checked here, around the Web, and MSDN Library but can't find this documented. I'm aware of some ways to generate the error, but would like to have a complete list so I can guard against and selectively circumvent it (I know how to disable request validation for a page, but this isn't an option in this case).
Is it a case of "security through obscurity"?
Thanks.
[Note: Scripts won't load for me in IE8 (as described frequently in the Meta forum) so I won't be able to "Add comment."]
EDIT 1: Hi Oded, are you aware of a list that documents the conditions used to determine a "potentially malicious input string"? That's what I'm looking for.
EDIT 2: #Chris Pebble: Yeah, what you said. :)
I couldn't find a document outlining a conclusive list, but looking through Reflector and doing some analysis on use of HttpRequestValidationException, it looks like validation errors on the following can cause the request validation to fail:
A filename in one of the files POSTed to an upload.
The incoming request raw URL.
The value portion of the name/value pair from any of the incoming cookies.
The value portion of the name/value pair from any of the fields coming in through GET/POST.
The question, then, is "what qualifies one of these things as a dangerous input?" That seems to happen during an internal method System.Web.CrossSiteScriptingValidation.IsDangerousString(string, out int) which looks like it decides this way:
Look for < or & in the value. If it's not there, or if it's the last character in the value, then the value is OK.
If the & character is in a &# sequence (e.g., for a non-breaking space), it's a "dangerous string."
If the < character is part of <x (where "x" is any alphabetic character a-z), <!, </, or <?, it's a "dangerous string."
Failing all of that, the value is OK.
The System.Web.CrossSiteScriptingValidation type seems to have other methods in it for determining if things are dangerous URLs or valid JavaScript IDs, but those don't appear, at least through Reflector analysis, to result in throwing HttpRequestValidationExceptions.
Update:
Warning: Some parts of the code in the original answer (below) were removed and marked as OBSOLETE.
Latest source code in Microsoft site (has syntax highlighting):
http://referencesource.microsoft.com/#System.Web/CrossSiteScriptingValidation.cs
After checking the newest code you will probably agree that what Travis Illig explained are the only validations used now in 2018 (and seems to have no changes since 2014 when the source was released in GitHub). But the old code below may still be relevant if you use an older version of the framework.
Original Answer:
Using Reflector, I did some browsing. Here's the raw code. When I have time I will translate this into some meaningful rules:
The HttpRequestValidationException is thrown by only a single method in the System.Web namespace, so it's rather isolated. Here is the method:
private void ValidateString(string s, string valueName, string collectionName)
{
int matchIndex = 0;
if (CrossSiteScriptingValidation.IsDangerousString(s, out matchIndex))
{
string str = valueName + "=\"";
int startIndex = matchIndex - 10;
if (startIndex <= 0)
{
startIndex = 0;
}
else
{
str = str + "...";
}
int length = matchIndex + 20;
if (length >= s.Length)
{
length = s.Length;
str = str + s.Substring(startIndex, length - startIndex) + "\"";
}
else
{
str = str + s.Substring(startIndex, length - startIndex) + "...\"";
}
throw new HttpRequestValidationException(HttpRuntime.FormatResourceString("Dangerous_input_detected", collectionName, str));
}
}
That method above makes a call to the IsDangerousString method in the CrossSiteScriptingValidation class, which validates the string against a series of rules. It looks like the following:
internal static bool IsDangerousString(string s, out int matchIndex)
{
matchIndex = 0;
int startIndex = 0;
while (true)
{
int index = s.IndexOfAny(startingChars, startIndex);
if (index < 0)
{
return false;
}
if (index == (s.Length - 1))
{
return false;
}
matchIndex = index;
switch (s[index])
{
case 'E':
case 'e':
if (IsDangerousExpressionString(s, index))
{
return true;
}
break;
case 'O':
case 'o':
if (!IsDangerousOnString(s, index))
{
break;
}
return true;
case '&':
if (s[index + 1] != '#')
{
break;
}
return true;
case '<':
if (!IsAtoZ(s[index + 1]) && (s[index + 1] != '!'))
{
break;
}
return true;
case 'S':
case 's':
if (!IsDangerousScriptString(s, index))
{
break;
}
return true;
}
startIndex = index + 1;
}
}
That IsDangerousString method appears to be referencing a series of validation rules, which are outlined below:
private static bool IsDangerousExpressionString(string s, int index)
{
if ((index + 10) >= s.Length)
{
return false;
}
if ((s[index + 1] != 'x') && (s[index + 1] != 'X'))
{
return false;
}
return (string.Compare(s, index + 2, "pression(", 0, 9, true, CultureInfo.InvariantCulture) == 0);
}
-
private static bool IsDangerousOnString(string s, int index)
{
if ((s[index + 1] != 'n') && (s[index + 1] != 'N'))
{
return false;
}
if ((index > 0) && IsAtoZ(s[index - 1]))
{
return false;
}
int length = s.Length;
index += 2;
while ((index < length) && IsAtoZ(s[index]))
{
index++;
}
while ((index < length) && char.IsWhiteSpace(s[index]))
{
index++;
}
return ((index < length) && (s[index] == '='));
}
-
private static bool IsAtoZ(char c)
{
return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')));
}
-
private static bool IsDangerousScriptString(string s, int index)
{
int length = s.Length;
if ((index + 6) >= length)
{
return false;
}
if ((((s[index + 1] != 'c') && (s[index + 1] != 'C')) || ((s[index + 2] != 'r') && (s[index + 2] != 'R'))) || ((((s[index + 3] != 'i') && (s[index + 3] != 'I')) || ((s[index + 4] != 'p') && (s[index + 4] != 'P'))) || ((s[index + 5] != 't') && (s[index + 5] != 'T'))))
{
return false;
}
index += 6;
while ((index < length) && char.IsWhiteSpace(s[index]))
{
index++;
}
return ((index < length) && (s[index] == ':'));
}
So there you have it. It's not pretty to decipher, but it's all there.
How about this script? Your code can not detect this script, right?
";}alert(1);function%20a(){//
Try this regular expresson pattern.
You may need to ecape the \ for javascript ex \\
var regExpPattern = '[eE][xX][pP][rR][eE][sS][sS][iI][oO][nN]\\(|\\b[oO][nN][a-zA-Z]*\\b\\s*=|&#|<[!/a-zA-Z]|[sS][cC][rR][iI][pP][tT]\\s*:';
var re = new RegExp("","gi");
re.compile(regExpPattern,"gi");
var outString = null;
outString = re.exec(text);
Following on from Travis' answer, the list of 'dangerous' character sequences can be simplified as follows;
&#
<A through to <Z (upper and lower case)
<!
</
<?
Based on this, in an ASP.Net MVC web app the following Regex validation attribute can be used on a model field to trigger client side validation before an HttpRequestValidationException is thrown when the form is submitted;
[RegularExpression(#"^(?![\s\S]*(&#|<[a-zA-Z!\/?]))[\s\S]*$", ErrorMessage = "This field does not support HTML or allow any of the following character sequences; "&#", "<A" through to "<Z" (upper and lower case), "<!", "</" or "<?".")]
Note that validation attribute error messages are HTML encoded when output by server side validation, but not when used in client side validation, so this one is already encoded as we only intend to see it with client side validation.
From MSDN:
'The exception that is thrown when a potentially malicious input string is received from the client as part of the request data. '
Many times this happens when JavaScript changes the values of a server side control in a way that causes the ViewState to not agree with the posted data.