I have a disagreement with a security auditor, whether a snippet of html/js is vulnerable to XSS or not.
In short this is it:
<html>
<form name="myform" action="page.php" method="post" onsubmit="return validate()">
<input name="field" type="text" size="50" />
<input type="submit" value="Submit" />
</form>
<script>
function validate()
{
var str=document.myform.field.value;
alert("Error in " + str);
return false
}
</script>
</html>
So, my auditor says that this can be vulnerable to DOM-based XSS, but has not yet given me an example.
I personally think that it is not, since because of the + inside alert, str is a string so it's not executed. For example if someone provides "document.cookie" in the form and hits submit, then the alert box is going to print "Error in document.cookie" (and not the actual cookie).
The only way this could be a potential threat is if you are including scripts that are not under your control from an untrustworthy source.
The malicious script could overwrite alert to be another function. For example, it could send the data passed to alert to its own servers.
The malicious script could overwrite the value of document.myform.field with an object containing a value property. The alert could be thus made to display a message that looked like a different error message, such as:
Error in authentication. Please go to www.phisherman.com and enter your user name and password.
If you are linking to scripts from untrustworthy sources, you have much greater security concerns than the above.
If you are linking to no such untrustworthy scripts, then no, this is not vulnerable to DOM-based XSS. form.field.value contains a string. It is not evaluated as script, escape characters have no effect, the string contained in the textbox will be displayed in the alert window. Nothing a user enters in that field could be used to harm your servers or corrupt your data based on the code you've posted.
I'd say that if your auditor is concerned with "DOM-based XSS" where-in a user might cause harm to your servers by manipulating the DOM, your auditor does not know much about DOM and browser-based JavaScript. A user can crack open a JavaScript console and execute all manner of scripts, including XMLHttpRequests to your server that can be made to look like they came from your own script. Precautions need to be made on the server for those types of attacks. Worrying about the security risks to the DOM or UI from user input in form fields is silly.
There is definitely no XSS problem with that.
What your "validate()" function does is:
Via the DOM API, copy a reference to a property of a DOM node (the "value" property of the <input> element) to a JavaScript variable.
Perform a JavaScript string concatenation operation. At that point, it absolutely does not matter what the string of characters is.
Pass the result string to the window.alert(). The "alert()" function always treats its argument strictly as a string. The only "special" character is newline, and all that does is cause text to wrap to a new line.
In particular, note that:
window.alert("<script>var u_r_so_hacked = true;</script>");
will show the "" tags just like that, angle brackets and all.
Related
I got following 2 questions as:
1) How to protect from this kind of XSS Attacks?
https://www.example.com/index.php?javascript:alert('XSS')
If suppose for some reason, the query parameter is embedded in an image load event then it would be like this
<img src=x onload="javascript:alert('XSS')">
//And browser treats as
<img src=x onload="javascript:alert('XSS')">
I am already using PHP's htmlspecialchars() and Filtar_var() with URL Sanitization, but this kind of encoded XSS will easily get pass through these functions
How can we defend such Encoded XSS or neutralize any such attack?
2) Is it necessary for an XSS attack to get embedded in HTML Page, Javascript or CSS etc in order to get triggered? or there can be a way where XSS does not need to be embedded?
htmlspecialchars is a perfectly good defence against XSS when you are inserting user input into an HTML document.
It stops any HTML syntax in the user input from breaking out of where you intend for it to go and being treated as JavaScript.
Your problem has nothing to do with the fact the attack is encoded. The problem is that are are putting user input somewhere that JavaScript is expected (and onload attribute) so it is already being treated as JavaScript.
json_encode is the usual solution here (and then htmlspecialchars because the JavaScript is inside an HTML attribute).
However, that only works when you are taking user input and putting it into a script to be used as data. Here it seems that you are taking user input and just treating the whole thing as a JavaScript function.
If you do that then you are going to be vulnerable to XSS. You can mitigate it to some degree by implementing defenses against CSRF, but you almost certainly shouldn't be doing this in the first place.
I'm creating an app that retrieves the text within a tweet, store it in the database and then display it on the browser.
The problem is that I'm thinking if the text has PHP tags or HTML tags it might be a security breach there.
I looked into strip_tags() but saw some bad reviews. I also saw suggestions to HTML Purifier but it was last updated years ago.
So my question is how can I be 100% secure that if the tweet text is "<script> something_bad() </script>" it won't matter?
To state the obvious the tweets are sent to the database from users so I don't want to check all individually before displaying them.
You are NEVER 100% secure, however you should take a look at this. If you use ENT_QUOTES parameter too, currently there are no ways to inject ANY XSS on your website if you're using valid charset (and your users don't use outdated browsers). However, if you want to allow people to only post SOME html tags into their "Tweet" (for example <b> for bold text), you will need to take a deep look at EACH whitelisted tag.
You've passed the first stage which is to recognise that there is a potential issue and skipped straight to trying to find a solution, without stopping to think about how you want to deal the scenario of the content. This is a critical pre-cusrsor to solving the problem.
The general rule is that you validate input and escape output
validate input
- decide whether to accept or reject it it in its entirety)
if (htmlentities($input) != $input) {
die "yuck! that tastes bad";
}
escape output
- transform the data appropriately according to where its going.
If you simply....
print "<script> something_bad() </script>";
That would be bad, but....
print JSONencode(htmlentities("<script> something_bad() </script>"));
...then you'd would have done something very strange at the front end to make the client susceptivble to a stored XSS attack.
If you're outputting to HTML (and I recommend you always do), simply HTML encode on output to the page.
As client script code is only dangerous when interpreted by the browser, it only needs to be encoded on output. After all, to the database <script> is just text. To the browser <script> tells the browser to interpret the following text as executable code, which is why you should encode it to <script>.
The OWASP XSS Prevention Cheat Sheet shows how you should do this properly depending on output context. Things get complicated when outputting to JavaScript (you may need to hex encode and HTML encode in the right order), so it is often much easier to always output to a HTML tag and then read that tag using JavaScript in the DOM rather than inserting dynamic data in scripts directly.
At the very minimum you should be encoding the < & characters and specifying the charset in metatag/HTTP header to avoid UTF7 XSS.
You need to convert the HTML characters <, > (mainly) into their HTML equivalents <, >.
This will make a < and > be displayed in the browser, but not executed - ie: if you look at the source an example may be <script>alert('xss')</script>.
Before you input your data into your database - or on output - use htmlentities().
Further reading: https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
I have an HTML form submitting via AJAX. So, one of the fields is:
<input type="url">
And by default, Chrome asks for the value of this field to be in the following format:
http://example.com
As I use bootstrap, I have the following input field visible: watch this screenshot.
I want user to enter the URL without the HTTP/HTTPS prefix, but in that case Chrome argues that it is not a valid URL.
What may the solution be? How could I make the browser think that the URL string does not need http prefix?
P.S. I use type="url" in order to make it easier to enter page addresses from Android/iOS devices.
EDITED:
There isn't to many options in this case. You essentially have two choices. Don't use type="url", which you already said you need to use. Or don't validate it using this method:
<input type="url" name="someUrl" novalidate="novalidate">
If you absolutely need to validate it, you could write a custom validation script. or use something like JQuery Validate.
This isn't a problem with the browser. It's the validation of the HTML5 input type. There are two solutions that you can implement. You can use
<input type="url" novalidate="novalidate" />
The second option is to use JavaScript to add the http:// to the field onsubmit if it isn't there. I've been trying to make it work with the type="URL" onsubmit, but the HTML5 validation kicks in before the JavaScript. Your best option, if you want to keep it that type will be a script executed by onkeyup: http://jsfiddle.net/gLN6X/1/ (posted at https://stackoverflow.com/a/17947355/3869056)
If you can do away with the type for one that doesn't have a default validation, you can use something like this: http://jsfiddle.net/u958xwr5/1/
<html>
<head>
<script type="text/javascript" src="//code.jquery.com/jquery-1.9.1.js"></script>
<script>
$(document).ready(function() {
$('#urlForm').submit(function() {
var url = $('#address');
if(url.val().match(/^http:\/\//) == null) {
url.val("http://" + url.val());
}
});
});
</script>
</head>
<body>
<form id="urlForm">
<input id="address" type="text" />
<button type="submit">Submit</button>
</form>
</body>
</html>
The JSFiddle has a little extra to show that after the correction has been made, it'll be submitting the correct information.
By definition, <input type="url"> represents a control for editing a single absolute URL. An absolute URL contains a protocol part; it is not an omissible “prefix”. Whether a browser has a way of prefixing user input with a default protocol part like http:// is a different issue, and at the discretion of the browser vendor.
Some people might consider using a prefilled part as in <input type="url" value="http://">, but this has several problems. It means setting an initial value that is invalid, which is confusing. It also makes it more difficult to the user to use the natural method of copy and paste.
The conclusion is that if you want a URL as input from the user, you should expect them to provide a full absolute URL.
if you don't want the browser validation (it can vary between browsers) you can add the following novalidate attribute
<input type="url" name="someUrl" novalidate="novalidate">
According to the OP, the issue was solved by using the HTML5 pattern attribute with the appropriate regular expression on the <input>, like so:
<input type="url" pattern="^[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$">
I'd like to add that this is not necessarily the best solution. It's hard to find the exact regular expression that will work for everyone, every time. If you have to use such explicit validation, I suggest you to listen to users' feedback, and alter the regular expression if necessary.
Personally, I don't do much validation on the URL inputs, that way the user will have the freedom of using any domain not just the good ol' example.com. Also, URLs can also be in the form of an IP address, like http://127.0.0.1/ or not have a dot in them, like http://localhost/. I just find it easier to allow whatever the user enters into the text box, obviously escaping the value as needed if it's being stored in a database.
As a closing word, I'd like to point out the fact that you shouldn't rely on the competence of the users. Why? Well, despite that http:// being in front of that input, lazy people (including me) will probably just paste the URL they CtrlC'd from the browser's address bar, and forget about removing that protocol from the beginning, hoping that the site would automatically do it for their own convenience. You should also take this into account when creating the input's validation, because it might throw off some people who just pasted a valid URL into your input, and it tells them that it's wrong.
Here is a rookie question, if I have a textarea that doesn't submit anywhere...
<form onsubmit="return false;">
<textarea name="new_title_text" id="new_title_text"></textarea>
</form>
and I use jQuery to prepend the value of the textarea to a div...
var textValue = $('#new_title_text').val()
$('#myDiv').prepend('<div>' + textValue + '</div>');
Are there any security vulnerabilities with this? Can someone somehow inject JavaScript and preform XSS, CSRF or any other type of attack? I understand that once I submit the value to my server then it needs to be checked, but is there anything that can happen before submission?
Thanks in advanced!
Basically you can't trust any validation done client side as people can (pretty easily) bypass JavaScript validation.
Do your proper validation and sanitation on your server and leave the client side validation simply for the user experience and to not "bother" your server with clearly invalid data - such as empty fields where a value is required.
Unless you are letting your users submit some PHP code or JavaSctipt code to be executed elsewhere on your site you should be safe. Always remember NOT to trust any data coming in from users. Treat all incoming data as a potential threat and sanitize anything you deal with if you plan to use it later.
Can someone somehow inject JavaScript and preform XSS, CSRF or any other type of attack
Yes. You are injecting text into an HTML string without HTML-escaping, so any metacharacters in that string (< or &) will fail and may be vulnerable to injection attacks (eg <script>...).
The question is who is that someone? From your current code it doesn't appear possible for an external party to pre-fill the textarea, so it would have to be the user attacking themselves (not really a vulnerability).
So you either need to HTML-escape the string going into HTML, or, better, use DOM-style access methods like .text() and .attr() to set text content and attributes without using crude string markup generation. Or the creation shorthand:
$('#myDiv').prepend(
$('<div>', {text: $('#new_title_text').val()})
);
The basic idea is that yes, it's unsafe to use prepend with untrusted data. However the exploitability does depend on the scenario. If an attacker can craft a url that causes that script to run with an untrusted value, you definitely have an XSS problem. If however a user can only trigger this himself by entering unsafe data and clicking the button, it's more safe, but not quite. This is often called self-xss and is sometimes exploited together with clickjacking etc.
For more info on unsafe jquery functions see: http://erlend.oftedal.no/blog/?blogid=127
This morning I woke up to a JavaScript alert on a project of mine that runs KnockoutJS, jQuery, and Underscore.js. It says "I can run any JavaScript of my choice on your users' browsers". The only third-party JavaScript I am downloading is Typekit, and removing that does not make this go away. I've searched my JavaScript and vendor JavaScript and this string does not come back up matching anything.
How would you troubleshoot this and/or is this something that is known to occur?
If you have a database for your application, that would be the next place to check. I'm guessing somebody found and exploited an Injection vulnerability (either un-sanitized HTML input or SQL) and injected the script into a page via the database.
The last place would be to look at the ruby code to see if somehow a malicious user modified your source.
You obviously take an input from user and then outputting it back as part of HTML without quoting or sanitizing. There's two quick checks to do:
1) Open source of page that outputs this alert and search inside source for exact text of alert - this should give you clear indication of what user-filled field is compromised.
2) To be sure, search all other fields in your database generated by users (login names, text of comments, etc.) for words "script" and "alert".
For future: always sanitize your input (remove HTML tags) before inserting it in HTML page OR escape symbols as entities according to standards OR explicitly treat is a plain text by assigning it to value of text node in DOM.
It sounds like a hack attempt on your site. Check any databases, text files, etc. that are being used that are receiving user input. It sounds like you're not checking what's being posted to your server I'm guessing.