• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 356
  • Last Modified:

How to prevent XSS (cross site scripting)

Hi.... I'm desperatly in need of help as I've developed a whole site without considering XSS ramifications.

Most forms on the site are submitted to themselves and some basic validation is conducted on the input eg. is it a number, is it an email address etc.

I'm thinking that I can use a simple process within the validation block to test the input once the submit is clicked.  It would run through each field in the form and check for the usual suspects <,>,(,) etc....

How do I do this... does anyone have some sample code available?

Thanks
0
philwill4u
Asked:
philwill4u
  • 7
  • 6
  • 2
  • +1
2 Solutions
 
GhasanoCommented:
Cross site scripting is a big problem on any dynamic page that sends data back to the user.

can reult in cookie and session data been stolen, and other things.
prevention is cheaper than the cure with this function.

code:
-----------
function getUserInput(input, stringLength)

 dim newString, regEx
 Set regEx = New RegExp
 
 ' only specified length
 
 newString = left(trim(input),stringLength)  


  regEx.Pattern       = "([^A-Za-z0-9@=:/*|' _-]+.%)<>()"
  regEx.IgnoreCase       = True
  regEx.Global             = True
  newString             = regEx.Replace(newString, "")
  Set regEx             = nothing  
 
  newString      = replace(newString,"--","")
  newString      = replace(newString,";","")      
  newString      = replace(newString,"'","'")
  newString      = replace(newString,"=","=")
  newString      = replace(newString,"(","[")
  newString      = replace(newString,")","]")
  newString = replace(newString,"'","''")
  newString = replace(newString,"<","[")
  newString = replace(newString,">,"]")

getUserInput = newString
 
 end function
-----------------
to use this here is an example
Code:
Firstname = getUserInput(request.Form("fname"))
-----------------
thats it, and you can add anything you dont want in your site, including swear words, certain comments, email address, links to other sites etc.
----------------------
have not capitolized, as the output would be formatted, not filtered. and also i have asked it to ignor case with this line here:

regEx.ignorCase (as it was before)

have taken out script, and just filtered < >( )for [ [ ] ]

how this work:

StrfirstName = GetUserInput(Trim(request.Form("firstName"),20)

simply it takes the string and the max lenght you want it to be ie 20, and then filters. it first checks that it meets are pattern ie A-Z a-z ? . < > ( ) rather than chinese or anything else.

the trim is just to drop any extra spaces after or before the string, once these basic settings are set it will then (if found) replace the charactor in the first " " with what is in the second

so if you wanted to ban the word tickle but have it say wiggle

you would add this:

newString=Replace(newString,"tickle","wiggle")

the data stored would be the data with the new changes applied.

can also be used to format for database to stop single ' etc

0
 
GhasanoCommented:
0
 
chisholmdCommented:
I have started the habit of always validating and converting my parameters into local variables first and never using them directly in my code.

e.g.
vSnee = no_xss(request("snree")
'do this for all expected params then only use the local var in your page code.  This helps make the code easier to read then running the params through your function in the main code. Also, since many params are used more then once, you only have to parse them once.
 

I can't garuntee that it is 100% proof against XSS but it should be a good start. If you find something else that needs to be parsed out of a param just add it to your no_xss() function.   What I can say is that I ran the trial edition of a $4,500 web vulnerability scanner and this method passed its tests.

For example:
<%

Function stripHTML(strHTML)
      set re = New RegExp
      with re
            .IgnoreCase = True
            .Global = True
            .Pattern = "<(.|\n)+?>"
            strOutput = .Replace(strHTML, "")
            strOutput = Replace(strOutput, "<", "&lt;")
            strOutput = Replace(strOutput, ">", "&gt;")
      end with
      set re = nothing
      stripHTML = strOutput    'Return the value of strOutput
End Function

function no_xss(strIn)
      no_xss = stripHTML(strIn)
end function


'Validate params
----------------------------------------------------
if len(request("snee")) > 0 then
   vSnee = no_xss(request("snee"))
end if
.
.
.

'Page code
----------------------------------------------------
'Only use local vars


0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
philwill4uAuthor Commented:
chisholmd.... which vunerability scanner did you use.... probably a good idea that I run my site through a scanner.

0
 
chisholmdCommented:
0
 
philwill4uAuthor Commented:
Hi chisholmd,

When I put the code in as follows...

<%
Function stripHTML(strHTML)
     set re = New RegExp
     with re
          .IgnoreCase = True
          .Global = True
          .Pattern = "<(.|\n)+?>"
          strOutput = .Replace(strHTML, "")
          strOutput = Replace(strOutput, "<", "&lt;")
          strOutput = Replace(strOutput, ">", "&gt;")
     end with
     set re = nothing
     stripHTML = strOutput    'Return the value of strOutput
End Function

function no_xss(strIn)
      if len(strIn) > 0 then
           no_xss = stripHTML(strIn)
            print ("first " & no_xss)
      else
            no_xss = strIn
            print ("second " & no_xss)
      end if
end function
%>

and call it.... the output in the PRINT function (a response.write call) is the same as the data going in.  Any ideas what I've done wrong?

Thanks
0
 
philwill4uAuthor Commented:
and the data going in contains > {()  etc
0
 
chisholmdCommented:
Try this, I updated my function to simply replace the 6 most common offending characters.  Place this in a page called noxsstest.asp

<%
function no_xss(strIn)
     if len(strIn) > 0 then
          strOut = Replace(strIn, "<", "&lt;")
          strOut = Replace(strOut, ">", "&gt;")
          strOut = Replace(strOut, "(", "&#40;")
          strOut = Replace(strOut, ")", "&#41;")
          strOut = Replace(strOut, "#", "&#35;")
          strOut = Replace(strOut, "&", "&#38;")
          no_xss = strOut
     end if
end function

response.write no_xss(request.querystring("test"))
%>

Then call it as
http://yourdomain/noxsstest.asp?test=<script>alert('boo');</script>

This works for me in testing.




0
 
philwill4uAuthor Commented:
Thanks ...works a treat... :)
0
 
philwill4uAuthor Commented:
An interesting one with Dreamweaver 8... it includes an INSERT that reads through Request.Form thereby eliminating all the benefit of the functions that you've provided.  I can work around it but it seems odd that DM would get it so wrong when it comes to XSS.

0
 
chisholmdCommented:
What do you mean? SAmple code pls
0
 
philwill4uAuthor Commented:
Hi,

This is part of a standard DW INSERT/ UPDATE

  For MM_i = LBound(MM_fields) To UBound(MM_fields) Step 2
    MM_fields(MM_i+1) = CStr(Request.Form(MM_fields(MM_i)))
  Next

where MM_fields is a list of the form fields

You see... it pulls the Request.Form fields .... what I've done is include no_xss in front of the Request.Form.... which seems to be ok.

0
 
chisholmdCommented:
Reading dreamweavercode hurts my head but it looks like you can just add your function here:

For MM_i = LBound(MM_fields) To UBound(MM_fields) Step 2
    MM_fields(MM_i+1) = NO_XSS(CStr(Request.Form(MM_fields(MM_i))))
  Next
0
 
philwill4uAuthor Commented:
Yes... that's what I've done and its working great.  I've got XSS traps everywhere.. in the form input, database reads/writes, URLs etc... the NO_XSS has been terific ... thanks
0
 
JAndyEvansCommented:
I have a related question (or solution):

Couldn't you use Server.HTMLEncode() for database reads/writes?
0
 
chisholmdCommented:
I think doing an HTMLEncode for saving your data could work but if you are using that data anywhere else it might be hard to decode it.  Also,  if the data is to be made available for the client to edit in a <textarea> you would want to decode it..

My original no_xss function removes HTML tags (including <script>) rather then just encoding them.

I haven't looked at this thread in a long time but I think philwill4u would have been better advised to stick with the RegExp method.  It looks like his function was recursively calling itself.

SO I would have changed this:
function no_xss(strIn)
      if len(strIn) > 0 then
           no_xss = stripHTML(strIn)
            print ("first " & no_xss)
      else
            no_xss = strIn
            print ("second " & no_xss)
      end if
end function

TO THIS:

function no_xss(strIn)
   DIM RETVAL
      if len(strIn) > 0 then
           RETVAL = stripHTML(strIn)
            print ("first " & RETVAL)
      else
            RETVAL = strIn
            print ("second " & RETVAL)
      end if
      no_xss = RETVAL
end function
0

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

  • 7
  • 6
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now