I'm getting a string from the current window's fragment identifier (location.hash). I want to use that string as the argument to location.replace(str).
Under normal circumstances, the string will come from code I control, so I'm not worried about validating that the string is a URL. If the string isn't a URL, the call to replace will just fail. That's fine.
What I am concerned about is making sure the string is NOT a javascript: URL or anything else that would allow someone to run arbitrary Javascript on my domain. Currently, I'm just checking that that str.indexOf('http') == 0.
Is that enough or should I sanitize this string some more?
The sanitization you propose is not enough.
An attacker could redirect to a data:uri url that contains base64 encoded html/javascript. This would allow the attacker to execute arbitrary javascript code. For example, this code snippet will alert 'xss' (in firefox, safari and opera)
var data = 'data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik8L3NjcmlwdD4=';
location.replace(data);
Besides, it may be possible to redirect to a anonymous FTP url, or use some other obscure protocol.
Instead of blacklisting protocols/keywords, use a whitelist approach instead. Maintain a list of good urls in your javascript code. Then, read the fragment identifier and see if it is in this known list of urls. If it is not, stop the process.
In security, whitelists are always preferable to blacklists.
Related
I'm testing a project I'm working on. Here I've put a filter on server side(Java) to redirect the page to Error page whenever I encounter any HTML tag like regex(URL Encoded is also checked) in query string. As per my skill set, it's working fine. But I'm very much sure it's not the end. There must be a way to still enter the vector to execute XSS script.
Examples : <hello> redirects to error page
%3Chello%3E converts to <hello> and redirected to error page
%253Chello%253E converts to %3Chello%3E & page works fine as no HTML tag is found.
The approach you're trying is black-list approach which is to search for bad characters (IE <, >) and redirect to an error page and\or encode it. This is the wrong approach.
You should use a white list of permitted characters and redirect to an error page if the input contains any non-permitted characters. One way to enforce this approach is regular expressions: ^[a-zA-Z0-9]*$ or ^[\s\w]*$. Adding both client validation and server validation would keep you safe and error-free (unless a hacker tries to bypass the client validation in which in this case the server validation would stop him).
If you try to guess the attacker's method you are destined to fail.
The right way to encode user originated input to prevent XSS is HTML Encoding, not URL encoding (not %3Chello%3E, but >hello<).
If you encode the user input you don't have to redirect the user to an error page as the examples you gave and the ones that I gave are harmless
Having said that, here is an example of XSS without < and >:
Let's say a page receives a picture file name and displays it, and does not encode the quote character:
https://contoso.com/displaypic?source=111.jpg
<img src="111.jpg"></img>
If you access this URL, you have yourself XSS:
https://contoso.com/displaypic?source=a"+onerror="alert('XSS')
<img src="a" onerror="alert('XSS')"></img>
Is it secure to use window.location.href without any validation?
For example:
<script>
var value = window.location.href;
alert(value);
</script>
From the above example, is it vulnerable to Cross-site scripting (XSS) attack?
If it is, then how? How the attacker can modify the value of window.location.href to the malicious content?
Edit (Second Situation)
This is the url : www.example.com?url=www.attack.com
Just assume taht I have a getQueryString() function that will return value without validation.
<script>
var value = getQueryString('url');
window.location.href = value;
</script>
Same question, is it vulnerable to Cross-site scripting (XSS) attack?
If it is, then how? How can an attacker just make use of "window.location.href = value" to perform XSS?
Using location.href can be understood to include two things:
Using the value of location.href by passing it around in your code, manipulating it and using it to guide the logic in your code.
Assigning someting to location.href, causing the browser to navigate to different URLs.
The first one, using the value, can be considered safe. The value of location.href is nothing more than a string. Of course it's part of user input, so you don't want to pass it to an eval statement, but that's true for all other forms of user input as well. In fact, the value of location.href is always a valid URL, so certain assumptions can be made of its content. In that sense you could argue it's more safe than most forms of user input. As long as you don't make any wrong assumptions.
The second one is something you should be careful with. Assigning unvalidated values to it can lead to open redirects that can be used for phishing and what's more, XSS issues arising from the use of javascript: and vbscript: URIs.
Edit: As requested, here's a more in-depth explanation of the problems with assiging to location.href:
Say you have an attacker controlled variable foo. The source of it can be anything really, but a query string parameter is a good example. When you assign the value of foo to location.href, what happens? Well, the browser does its best to interpret the value as a URI and then redirects the user to the resulting address. In most cases, this will trigger a page load; e.g. if value is "https://www.google.com/", Google's front page will be loaded. Allowing that to happen without user interaction is known as an open redirect and is considered a security vulnerability!
There are, however, types of URIs that won't trigger a page load. A common example of such a URI would be one that contains nothing but a fragment identifier, e.g. #quux. Assigning that to location.href would cause the page to scroll to the element with the ID "quux" and do nothing else. Fragment URIs are safe as long as you don't do anything stupid with the values of the fragments themselves.
Then to the interesting part: javascript: and vbscript: URIs. These are the ones that will bite you. The JavaScript and VBScript URI schemes are non-standard URI schemes that can be used to execute code in the context of the currently open web page. Sounds bad, doesn't it? Well, it should. Consider our attacker-controlled variable foo: all an attacker has to do to launch an attack against your users is inject a script URI into the variable. When you assign it to location.href, it's basically the same as calling eval on the script.
JavaScript URIs work in all modern browsers, while VBScript is IE-only, and requires the page to be rendered in quirks mode.
Finally, there's one more interesting URI scheme to consider: the data URI. Data URIs are file literals: entire files encoded as URIs. They can be used to encode any files, including HTML documents. And those documents, like any others, can contain scripts.
Most browsers treat each data URI as its own unique origin. That means the scripts in an HTML document wrapped in a data URI can not access any data on other pages. Except in Firefox.
Firefox treats data URIs a bit differently from all other browsers. In it, data URIs inherit the origin of whatever document is opening it. That means any scripts can access the data contained in the referring document. And that's XSS for you.
A XSS is not possible under #1
The worst case I can think of is someone using that for Social Engineering (lets say your domain is really popular like Ebay or Amazon), what an attacker could do is craft a message saying something like "Amazon/Ebay free stuff for you, just go to http://haxor.site" using the URL and sending it to someone.
But still I don't find it dangerous, because of the URL encoding the message would look pretty messy.
EDIT:
This only answer #1, since when I answered this question there wasn't a "#2"
var value = getQueryString('url');
window.location.href = encodeURI(value);
I think this is the easiest way
I am getting this message when I perform a post with some data encoded in the query string. I have browsed the web on this and all the solutions are about turning off the validation -- which seems backward to me. What I want to do is modify the query string so that it doesn't trigger the validation in the first place.
The query string is urlEncoded with this javascript:
var qs = 'i=' + id+ '&c=' + encodeURIComponent(c) + '&' + 'p=' + encodeURIComponent(p);
'Id' is just an integer, so the c and p parameters are the only ones likely to cause this, and they are both URIencoded.
What causes this error, and what, beyond uri encoding can I do to prevent the complaint?
I don't like turning off safety features. It is smart to wear a safety belt when you are driving.
This is a safety belt only for people that haven't passed their driving test. If output is correctly encoded, the "potentially dangerous" query string value is no longer dangerous.
For example, if the character " is output to HTML this should be encoded as ", or if the character ' is output to JavaScript then it should be encoded as \x27.
ASP.NET Request Validation only protects your code if you are not correctly encoding for output, and furthermore it only protects values that have been input via a website with Request Validation enabled. Anything input from any other sources (e.g. a shared database, another application or an external API) will not be validated by request validation. This is why I would code your application to handle correct output encoding instead. If stackoverflow.com blocked potentially dangerous input then it would not be possible for people to write code like this in their posts: <script>alert('example');</script>, but with proper output encoding, as you can see this is safe.
Check out my post on ASP.NET Security (A3-Cross-Site Scripting (XSS) section).
Also see the OWASP XSS Prevention Cheat Sheet.
You're right, most "fixes" for this tell you to turn off validation so it was kind of difficult to find something other than that. I think you're going to have to turn it off just for that request and then manually validate it. According to microsoft, you can disable it for a request like this:
Request.Unvalidated("userInput"); // Validation bypassed
Request.Unvalidated().Form["userInput"]; // Validation bypassed
If you disable request validation, you must manually check the unvalidated user input for potentially dangerous input
See this article: http://msdn.microsoft.com/en-us/library/hh882339(v=vs.110).aspx
Good Luck!
The ASP.NET team doesn't want you rely on 'RequestValidation' so it is ok to turn it off (it's a crutch that gives a false sense of security because it isn't always up to speed).
For info on why this ok and what you should do instead, watch this video starting at 11:10. I would actually recommend watching the whole video.
I am calling a plsql procedure from window.opener.location.href, I want to pass an array as a parameter to this procedure.
window.opener.location.href="dt_bulk_test_pkg.pc_bulk_test?ps="+frmresult.ps.value+
"&p_step="+frmresult.p_step.value+
"&p_year="+frmresult.p_year.value+
"&p_quarter="+frmresult.p_quarter.value+
"&p_diagnostic_type="+frmresult.p_diagnostic_type.value+
"&p_overwrite="+frmresult.p_overwrite.value+
"&p_company_id="+v_comp_id;
v_comp_id is an array.
PL/SQL is a database technology, Javascript is an in-browser technology (unless you're doing server side JS with node or Rhino but you are not). The browser can only communicate with web servers. So from the point of javascript, you're not calling a stored procedure, you're calling a web-server that you must have running somewhere that calls that stored procedure.
How exactly arrays are represented is up to the server-side language/web-framework, but a fairly standard approach is that taken by jQuery's $.param method. For example, opening up the console on this site I can do this:
> $.param({example: [1,2,3]})
"example%5B%5D=1&example%5B%5D=2&example%5B%5D=3"
Words of warning.
Exposing database stored procedures directly via HTTP is not only bad design, but likely a crazy-bad security risk.
Embedding parameters in a url means you are using an HTTP GET request. GET requests are meant for resources that do not affect the state of the server so be careful that your stored procedure only gets data, not changes it. The danger is that someone could put that url in an email or even an img src tag on a webpage and people would hit that url simply by clicking a link or visiting a web page.
All parameters should pass through url encoding. Like I mentioned, jQuery.param will do this.
You are likely exposing yourself to XSS attacks as well.
I know that this is an old thread but I landed here so I guess others will.
It is quite possible to pass arrays to PL/SQL via a URL and it is explicitly supported, not a dodgy hack. Link to Oracle doc
You declare the PL/SQL input parameter as a table of varchar2. Then you pass the same parameter name repeatedly in the URL.
1/ Example PL/SQL source:
CREATE OR REPLACE PROCEDURE test_array(
p IN dbms_sql.varchar2_table )
AS
BEGIN
FOR i IN p.FIRST .. p.LAST
LOOP
htp.p(p(i)||'<br>');
END LOOP;
END test_array;
*2/ Example URL to invoke it: - substitute XXXXXXXXXXXXXX with your own setup *
http://XXXXXXXXXXXXXX/test_array?p=first ele&p=second ele
3/ Output
first ele
second ele
You can pass in as many elements as you want, I just used 2 for this example.
If your data type is not varchar2, capture them as varchar2 from the URL anyway and convert them to numbers etc inside the pl/sql.
I'm writing a JavaScript function that needs to uphold three properties:
be very small and lightweight - no external libraries
encode a string in such a way as to be able to be passed as a GET parameter
this string must be decoded again at its destination
Effectively, it authenticates the user by sending his username and password to a PHP page which then verifies it. This is done via GET because I haven't yet found a way of doing a background cross-domain POST request. The trouble is that if the user has a character such as '#' or similar in his password, it doesn't get sent properly.
Currently to avoid this, I encode() the password string before sending it, which allows it to be received without problems. However, I read that PHP's urldecode() is not a perfect analog for this, as there are corner cases which are treated differently (i.e. ' ', '+', etc). Sadly I cannot find this document anymore, so I cannot quote it, but the gist was that one of them converts spaces into '+' signs, which the other treats as an actual plus sign, or something like that...
As such, I'm looking for a Javascript function that can take a string and make it URL-safe, and which has a perfect reversal function in PHP so that the original string can be recovered.
The arguably awful code I currently use to achieve this:
login.onsubmit = function(){
loginFailMsg.style.display = 'none';
var inputs = login.getElementsByTagName('input');
var formdata =
'username='+inputs[0].value+'&password='+encode(inputs[1].value);
submit.src = formtarget+'/auth/bklt?'+formdata;
userinfo = undefined;
setTimeout(getUserinfo,300);
return false;
};
encodeURIComponent, PHP will decode it automatically when populating $_POST or $_GET
'&password='+encode(inputs[1].value)
Where's encode function coming from? Seems to me the quick answer to your question is using encodeURIComponent() instead, available since JavaScript 1.5. See also Comparing escape(), encodeURI(), and encodeURIComponent(); it does not encode everything either, but does encode all the server expects it to.
(As for cross-domain AJAX POST calls, I'd really have a look at "JSON with Padding". See JSONP with jQuery that I mentioned in the comments earlier. This will also prevent issues with the timeout you've randomly chosen, and jQuery will also help you, a lot, to get rid of inputs[0].value and the like. And, as you apparently already have a MD5 hash on the server, I'd really hash the password client side as well --see Karl's answer-- and compare those hashes instead. Respect your user's password and your own time, drop that no external libraries requirement!)
I don't think there's such a thing as a reversible hash function. There are plenty of javascript md5 libraries available, however.