Open Redirect vulnerability fix in Javascript [duplicate] - javascript

I'm getting Client DOM Open Redirect security issue on scan for the following piece of code.
The issue shows up where I'm initializing the variables 'myPath' and 'myHost'.
I'm not able to understand how is that open to phising attack and how do I fix it.
Could anyone please help?
var query = this.value;
var myPath = window.location.href.substring(window.location.href.indexOf("/myapp"), window.location.href.indexOf(".html"));
var myHost = window.location.href.substring(0, window.location.href.indexOf("/myapp"));
query = encodeURIComponent(query);
if(myPath!==null){
query = query + "mysite:" + myHost + myPath;
}

The problem is that you are taking user input (values from the url bar) and you redirect to it. This may or may not be exploitable in any meaningful attack, but static scanners don't understand your application logic - for a static scanner it's just user input that will directly be used in a redirect.
Based on the info in the question, I can't think of a valid attack, because I think it just makes the same url that the user already visited, without .html in the end, and also without the # part if there was any. So I think the user will be redirected to a page that he visited already. However, that doesn't at all mean there is no vulnerability, and it also depends on other related code. What happens when the user can access a page with this code without any .html in the url bar would for example affect the outcome, so would another vulnerability that allows (partial) control of the url bar, a possible scenario for something like an SPA. So there is not enough info in the question to decide whether it's actually secure or not.
As for the fix, make sure you only redirect where you want to, and not to any user input. For example the host part (maybe even the path) could be written in the page by the server, but I understand that would not be the case for something like an SPA. You could implement whitelist validation to ensure no rogue redirects happen. Maybe it's already good, in which case you can set this finding to mitigated in the scanner you used, but think about edge cases, and how this can be abused by an attacker. Can he trick this with # in the path? Can he load a page with this code from an url that doesn't have .html? Or has it multiple times? What if he registers a domain like someattack.html.hisdomain.com and has a valid user visit it? :)
The url bar is a tricky thing, because it's user input, but the attacker doesn't have full control - he must hit an application page, otherwise this javascript won't be loaded. Still the reason this is flagged by a static scanner is because an attacker may have some control, and in case of javascript-heavy single page applications, probably a bit more because of all the url bar manipulation going on.

Related

Javascript redirect vulnerability

Say I store the url path in a query parameter like /?return_back_to=/foo/bar
Then pass this to some external auth service like Microsoft, which does the login and returns to the same url with my query parameter.
At this point, is it safe to get the value from the query parameter and redirect using React navigate() to this url? Or is this considered an "open redirect vulnerability" ?
On the surface, as long as you follow a bunch of best practices and validate the query parameter, it should be save to use it, and would not be "open redirect vulnerability".
You mentioned using Microsoft auth service, which i personally don't have that much experience with, but I have used firebase and google auth a lot and I know that they automatically check and if the redirect URL is not whitelisted it will not work. firebase automatically adds localhost and your app domain to whitelist and you can add more if you have external links that you would like your users to be redirected to.
source 1: https://support.google.com/firebase/answer/6400741?hl=en
source 2: https://support.google.com/firebase/answer/9021429?hl=en
in terms of it being safe to use react navigate() when users are actually back to your app, you should make sure to either check the URL against a local whitelist or just add your app domain to the URL before redirecting the users.
navigate({safeDomain} + {query parameter})
Although I should mention that if by navigate() you are refering to useNavigate() hook, I dont think you can use it for that, and you need to use redirect() .
some more useful information for mitigating against open redirect vulnerability
I hope this was helpful!
It depends on who is calling that endpoint. Well known identity providers will require you to set allowed redirect urls, and will only send back the authorized ones (the ones you set up). So they will only call the callback if it's ok, so you can redirect securely.
However, anybody else might use this url (link to it) with a different parameter, to which you don't want to naviigate, that would be an open redirect. So you need to make sure that the request actually originates from a trusted source, ie. from Azure AD. Depending on what flow you are implementing, you can either validate a token you received to make sure it is a valid request, or at the very least you can check an Origin / Referer header to see who the caller is (it's not possible to alter Origin or Referer in Javascript, so an attacker cannot have a legitimate user visit a link with a malicious redirect, with an Origin from Microsoft).
Also if you only redirect in your own origin (domain), you can and should add validation that the redirect path (return_back_to) is internal, like for example starts with a / and/or does not contain ://.
I don't completely agree with what has been said in the other answers.
Indeed, the return URL that may contain any information using this mechanism will expose this data to all kinds of attacks.
Let's take an example, if the return url is for example the user's dashboard, the url could be of the type /users/<id or name of the user>
Moreover, all this also depends on the checks that are implemented on your side.
Let's say an attacker tries to use your url to override the url legitimately returned by your authentication service: http://callback.url/?return_back_to=http://malicious.example.com
If you do not handle the data received correctly, this will lead to potential security breaches.
For all of these reasons (and many others) i f think you should avoid passing and using directly web (or filesystem) paths directly in a GET or POST var.
Instead, you can evaluate the possibility of passing only the information you need to identify the target and the construct the url in your callback script before passing it to navigate().
Also, i don't know if you do that, avoid passing any numerical ID in POST and GET vars. Instead generate an alphanumeric unique ID to avoid ID predicting from attaquers.
For having more information about Web security i recommande learning the OWASP Top Ten rules : https://owasp.org/www-project-top-ten/
This is a good entry point to building secured web apps.

Collecting a response without requiring log in - one time URL? Issues with false positives

Background and Problem
I have a system that has core users augmented by some minor contributors who only need to be able to provide approvals for certain things. To support this, the system reacts to database changes and emails those approvers with a single button in the body of the email. This button is just a link to a unique url - something like https://myapp/response/12345-abcdefg-6789.
That "response" page is listed in the web config as not requiring a log in. Thus, the approver should only have to click on the link in the email, and the system should detect that and mark their response.
In all of our testing, this works great. All we're doing is marking the response via the page's code behind, and then displaying a message on the page that the response was received. On the surface, this seems like about as easy of a task as you can dream up.
However, we're getting false positives in production. The approvers are telling us that things are being marked as approved when they never clicked the link. I assume this has something to do with their browsers checking the links for safety or something - and by performing that safety check, it's triggering the system to record the response. Unfortunately, i haven't been able to reproduce this - even when we have some of the approvers on the phone while we try it.
The question is - what is the best strategy to avoid a false positive with buttons in an email?
Lots of companies do this kind of thing - i'm looking right now at an invitation from a friend via evite. It has Yes, Maybe, and No which appear to have the same kind of setup i described above.
Is there something i should be doing with redirects after x seconds? Is there some other javascript i should be deploying on the page? Is there some other potential cause for this? The IIS logs seem to indicate that the "fake clicks" are coming from the target users computers. Which is a bit of a relief, since it's hard to imagine how some other external machine could end up at a GUID based url that is not represented by a physical file that could be crawled over in some way.
I would like to avoid having another button for the user to click, where they would click "Approve" in the email, and then when they get to the page they have click the same thing again.
Thanks!
From my understanding there are two ways to go about it. But both methods assume the current "response" page is just an intermediary.
Add another button on the page (#
https://myapp/response/12345-abcdefg-6789 for instance) that actually
submits the response (or redirects to the actual response page). It would add an extra step for your approvers but
it should work. (You can even add a captcha there if paranoid)
Once the page is loaded, redirect to the actual response page via
javascript. The idea being if the link is automatically opened by
some kind of bot it's unlikely it runs the script.

Is it secure to use window.location.href directly without validation

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

Jquery to pull the URL of a webpage

I am looking for a way to use Jquery (or any other open source script) to pull the URL of a particular webpage. I am working on a service that will pull the original URL of any webpage - consider a scenario where I load google.com but have entered yahoo.com in the address bar (without pressing enter key) - the script should be able to validate if the the URL on the address bar is the same as the actual URL or if it is different.
There is no way to do this. And there better not be any in the making. There is no reason to need such information, and it's a violation of user privacy.
No dear, Absolutely no way to do this.
and i agree with #bjb568 , its definitely violation of user privacy.
you can get the current page URL in your script.
But why you need this kind of functionality.?
i will advise you to find any alternative of your requirement,
You can get the current location of the page using regular Javascript, but I do not think you can get the currently typed address bar, although I do not see where you should ever need to.
In response to everyone on here saying it is a breach of user privacy: I don't think grabbing the URL or the typed address bar on the current page is a breach of privacy or security unless you are somehow able to change the address bar to make it seem like you are on a different site - like being on Google.com and it saying you are on Yahoo.com. But, from the OP's original question, it just seems like he wants to get the information; not change it.
Using Javascript, you can use var location = document.location.href
The closest you can get to change the addressbar is window.history.pushState(), but browsers have a security settings that do not allow domains outside of the current domain to be used.
My first question that comes to mind: "Why on earth does he want to do that???" If it was possible you would have to interact with each browser directly which is not possible.
jQuery is just a client-language that interprets with each browsers "engine" (that handles rendering of html, javascript etc) and not the browser itself (menus, settings etc). Secondly, if it would work: How often would you check? Each keypress? Every 10 seconds? It would not be doable in a proper way - even if it was possible.
I think you should rethink your issue and try to explain why you want to do this. It might be other (better) solutions that would handle your issue in a better way.

How to get javascript in an iframe to modify the parent document?

So I have two documents dA and dB hosted on two different servers sA and sB respectively.
Document dA has some JS which opens up an iframe src'ing document dB, with a form on it. when the form in document dB is submitted to a form-handler on server sB, I want the iframe on page dA to close.
I hope that was clear enough. Is there a way to do this?
Thanks!
-Mala
UPDATE: I have no control over dA or sA except via inserted javascript
This isn't supposed to be possible due to browser/JavaScript security sandbox policy. That being said, it is possible to step outside of those limitations with a bit of hackery. There are a variety of methods, some involving Flash.
I would recommend against doing this if possible, but if you must, I'd recommend the DNS approach referred to here:
http://www.alexpooley.com/2007/08/07/how-to-cross-domain-javascript/
Key Excerpt:
Say domain D wants to
connect to domain E. In a nutshell,
the trick is to use DNS to point a
sub-domain of D, D_s, to E’s server.
In doing so, D_s takes on the
characteristics of E, while also being
accessible to D.
Assume that I create page A, that lies withing a frame that covers the entire page.
Let A link to yourbank.com, and you click on that link. Now if I could use javascript that modifies the content of the frame (banking site), I would be able to quite easily read the password you are using and store it in a cookie, send it to my server, etc.
That is the reason you cannot modify the content in another frame, whose content is NOT from the same domain. However, if they ARE from the same domain, you should be able to modify it as you see fit (both pages must be on your server).
You should be able to access the iframe with this code:
window["iframe_name"].document.body
If you just want the top-level to close, you can just call something like this:
window.top.location = "http://www.example.com/dC.html";
This will close out dA and sent the user to dC.html instead. dC.html can have the JS you want to run (for example, to close the window) in the onload handler.
Other people explained security implications. But the question is legitimate, there are use cases for that, and it is possible in some scenarios to do what you want.
W3C defines a property on document called domain, which is used to check security permissions. This property can be manipulated cooperatively by both documents, so they can access each other in some cases.
The governing document is DOM Level 1 Spec. Look at the description of document. As you can see this property is defined there and … it is read-only. In reality all browsers allow to modify it:
Mozilla's document.domain description.
Microsoft's domain property description.
Modifications cannot be arbitrary. Usually only super-domains are allowed. It means that you can make two documents served by different server to access each other, as long as they have a common super-domain.
So if you want two pages to communicate, you need to add a small one-liner, which should be run on page load. Something like that should do the trick:
document.domain = "yourdomain.com";
Now you can serve them from different subdomains without losing their accessibility.
Obviously you should watch for timing issues. They can be avoided if you establish a notification protocol of some sort. For example, one page (the master) sets its domain, and loads another page (the server). When the server is operational, it changes its domain and accesses the master triggering some function.
A mechanism to do so would be capable of a cross-site scripting attack (since you could do more than just remove a benign bit of page content).
A safe approach would limit to just the iframe document emptying/hiding itself, but if the iframe containing it is fixed size, you will just end up with a blank spot on the page.
If you don't have control over dA or Sa this isn't possible because of browser security restrictions. Even the Flash methods require access to both servers.
This is a bit convoluted but may be more legitimate than a straight XSS solution:
You have no control over server A other than writing javascript to document A. But you are opening an iframe within document A, which suggests that you only have write-access to document A. This a bit confusing. Are you writing the js to document A or injecting it somehow?
Either way, here is what I dreamed up. It won't work if you have no access to the server which hosts the page which has the iframe.
The user hits submit on the form within the iframe. The form, once completed, most likely changes something on the server hosting that form. So you have an AJAX function on Document A which asks a server-side script to check if the form has been submitted yet. If it has, the script returns a "submitted" value to the AJAX function, which triggers another js function to close the iframe.
The above requires a few things:
The iframe needs to be on a page hosted on a server where you can write an additional server-side script (this avoids the cross-domain issue, since the AJAX is pointing to the same directory, in theory).
The server within the iframe must have some url that can be requested which will return some kind of confirmation that the form has been submitted.
The "check-for-submitted" script needs to know both the above-mentioned URL and what to look for upon loading said URL.
If you have all of the above, the ajax function calls the server-script, the server-script uses cURL to go the URL that reflects if the form is done, the server-script looks for the "form has been submitted" indicators, and, depending on what it finds, returns an answer of "not submitted" or "submitted" to the ajax function.
For example, maybe the form is for user registration. If your outer document knows what username will be entered into the form, the server-side script can go to http://example.org/username and if it comes up with "user not found" you know the form has yet to be submitted.
Anything that goes beyond what is possible in the above example is probably outside of what is safe and secure anyway. While it would be very convenient to have the iframe close automatically when the user has submitted it, consider the possibility that I have sent you an email saying your bank account needs looking at. The email has a link to a page I have made which has an iframe of your bank's site set to fill the entire viewable part of my page. You log in as normal, because you are very trusting. If I had access to the fact that you hit submit on the page, that would imply I also had access to what you submitted or at the very least the URL that the iframe redirected to (which could have a session ID in or all sorts of other data the bank shouldn't include in a URL).
I don't mean to sound preachy at all. You should just consider that in order to know about one event, you often are given access to other data that you ought not have.
I think a slightly less elegant solution to your problem would be to have a link above the iframe that says "Finished" or "Close" that kills the iframe when the user is done with the form. This would not only close the iframe when the user has submitted the form, but also give them a chance to to say "oops! I don't want to fill out this form anyway. Nevermind!" Right now with your desired automatic solution, there is no way to get rid of the iframe unless the user hits submit.
Thank you everybody for your answers. I found a solution that works:
On my server, I tell the form to redirect to the url that created the iframe.
On the site containing the iframe, I add a setInterval function to poll for the current location of the iframe.
Due to JS sandboxing, this poll does not work while the url is foreign (i.e. before my form is submitted). However, once the url is local (i.e. identical to that of the calling page), the url is readable, and the function closes the iframe. This works as soon as the iframe is redirected, I don't even need to wait for the additional pageload.
Thank you very much Greg for helping me :)

Categories

Resources