Using $sce in AngularJS - javascript

I'm having trouble getting my head around showing iFrames in my Angular app. My users are allowed to enter a YouTube URL and my app will convert this straight to a video.
Of course, Angular won't allow this directly so you have to explicitly "trust" the contents so I use this to get it to show the iframe:
$sce.trustAsResourceUrl(url_of_video)
However, how do I get back? I want to be able to send the URL to my back-end but in this sanitized form it's no longer the original url string.
UPDATE:
Experimenting with this and came up with this code:
angular.forEach($scope.task.items, function(item) {
item.data = $sce.getTrustedResourceUrl(item.data); //this gets rejected by $sce
item.data2 = $sce.getTrustedResourceUrl(item.data); //this is accepted and I'm free to POST the url
});
I've noticed that I can create a new name/value pair in the array and assign it the original url but if I try to assign the item.data with the trusted form of the sanitized data then it rejects it! Hmmmmm! Why is this?
Any ideas?
UPDATE 2
I decided to create two versions of the data, one for the front end (which I "trusted" with $sce) and one for the back. This appears to have solved my issue for the moment.

Take a look at this answers (which contains links to yet more answers and resources).
You should understand the implications of trusting content entered by a user and what $sce is there for.
If you want to allow YouTube URLs, it might be a better idea to "white-list" those URLs only (instead of trusting any URL entered by the user).
(Don't forget that SCE is not there to make your app bullet-proof, but it is a tool to help you make it safer and help you audit it easier/more reliably.)
That said, here is how you could configure Angular's SCE to allow URLs from www.youtube.com:
.config(function ($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self', // trust all resources from the same origin
'*://www.youtube.com/**' // trust all resources from `www.youtube.com`
]);
});
See, also, this short demo from the other answer (that does what you want).

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.

How to obtain the full url of an Angular view in Global.asax

In an ASP.NET MVC application, there is Request.Url to access the url in Global.asax.
But for an Angular application where an url is like http://domain/#/home. The Request.Url we obtained from Application_BeginRequest or Application_EndRequest are http://domain/. The Angular routes are not included.
It is reasonable because those routes are added at the client side. But is it possible to get the value of the true url in the MVC server side?
Update:
Just picked Matteo's answer as the correct one. Let me clarify a bit.
I have been trying this for one purpose: rewrite my url.
In the past, I used to check Request.ApplicationPath and manipulate url with string functions or built-in tools like VirtualPathUtility.
The need for the hash part is valid because the query string parameters are appended there. For example, I have a url like this:
http://[domain]/#/pay/cancel?paymentId=[some guid]
The conventional wisdom brought me to Global.asax to access those query parameters. I find none. Everything behind the hash tag is conveniently ignored.
So the correct way is to handle that part of url in the client side code. I am using ui-router. So for url rewrite/redirect, use stateProvider.when(oldUrl, newUrl);. To access query parameters, use $state.params.
Lesson learned: think clearly and approach different problem with different mindset.
There is no way, as the "hash" part of an url is not really part of the url. Have you ever used anchors in a page to create an index? The concept is the same.
Anyway I can't possibly imagine how the hash part could be useful server side. My guess is that you think it's useful because you're approaching a problem the wrong way.
If you complement your question with more details, like what you're trying to achieve, it's very possible we can provide you with an appropriate solution.

Posting articles on Reddit with same root URL but has significant fragment identifier

I'm trying to post a link to various articles from my website to Reddit, but they all of the same root URL, but are differentiated by using the hashbang (#) to go to different articles. I wrote my front end in with a single page application framework (Ember.js), which defaults to using hashbangs to designate different pages. Thus, here are some examples of different blog posts:
http://noobjs.org/#/posts/15
http://noobjs.org/#/posts/16
They are different pages and different articles, but Reddit tells me that the link was already submitted since it must not view the hashbang as significant. Does anyone know if there is a way around this? The answer may be that I change my site so that it no longer uses the hashbang, but I'd rather avoid that so I don't break any other links I sent out.
Any ideas?
Reddit recognizes different query strings as being different pages. So, you can add a query string to the end that is the same as the hash.
http://noobjs.org/#/posts/15
http://noobjs.org/#/posts/16
become
http://noobjs.org/#/posts/15?/posts/15
http://noobjs.org/#/posts/16?/posts/16
It's not the prettiest, but it will work fine. Alternatively, you could write a check on page load against the URL to change ? into #.
window.location = window.location.href.replace("?", "#");
and post query string versions to reddit:
http://noobjs.org/?/posts/15
http://noobjs.org/?/posts/16
EDIT:
Currently, Ember does not have strong support for query parameters, but in this situation, a slight variation worked:
http://noobjs.org/?/#/posts/15
http://noobjs.org/?/#/posts/16

Efficient way to pass arrays in url

I am building a webapp and have a few arrays that I would like to pass through the URL in order to make the results of my application easily sharable.
Is there an efficient way to do this? I know a lot of websites (like youtube) use some sort of encoding to make their URLs shorter, would that be an option here?
Thanks in advance!
What I suspect you're asking is you have some page where the user can alter information, etc, and you want a way to create a URL on the fly with that information so it can easily be accessed again. I've listed two approaches here:
Use the query string. On your page you can have a button saying "save" that produces a URL with info about what the user did. For example, if I have a webpage where all I do is put my name in and select a color, I can encode that as http://my-website.com/page?name=John_Doe&color=red. Then, if I visit that link, your page could access the query object in JavaScript and load a page with the name and color field already set.
An approach for the "YouTube-style" URLs would be to create a hash of the relevant information corresponding to the page. For example, if I were creating a service for users to store plaintext files. These files are to have the following attributes: title, date, name, and body. We can create a hash of the string hash_string = someHashFunction(title+date+name).
Of course, this is a very naive hashing scheme, but something like this may be what you are looking for. Following this, your URL would be something like http://my-website.com/hash_string. The key here is not only creating these URLs, but having a means to route requests on the server side to the page corresponding to the hash_string.

How to prevent direct access to my JSON service?

I have a JSON web service to return home markers to be displayed on my Google Map.
Essentially, http://example.com calls the web service to find out the location of all map markers to display like so:
http://example.com/json/?zipcode=12345
And it returns a JSON string such as:
{"address": "321 Main St, Mountain View, CA, USA", ...}
So on my index.html page, I take that JSON string and place the map markers.
However, what I don't want to have happen is people calling out to my JSON web service directly.
I only want http://example.com/index.html to be able to call my http://example.com/json/ web service ... and not some random dude calling the /json/ directly.
Quesiton: how do I prevent direct calling/access to my http://example.com/json/ web service?
UPDATE:
To give more clarity, http://example.com/index.html call http://example.com/json/?zipcode=12345 ... and the JSON service
- returns semi-sensitive data,
- returns a JSON array,
- responds to GET requests,
- the browser making the request has JavaScript enabled
Again, what I don't want to have happen is people simply look at my index.html source code and then call the JSON service directly.
There are a few good ways to authenticate clients.
By IP address. In Apache, use the Allow / Deny directives.
By HTTP auth: basic or digest. This is nice and standardized, and uses usernames/passwords to authenticate.
By cookie. You'll have to come up with the cookie.
By a custom HTTP header that you invent.
Edit:
I didn't catch at first that your web service is being called by client-side code. It is literally NOT POSSIBLE to prevent people from calling your web service directly, if you let client-side Javascript do it. Someone could just read the source code.
Some more specific answers here, but I'd like to make the following general point:
Anything done over AJAX is being loaded by the user's browser. You could make a hacker's life hard if you wanted to, but, ultimately, there is no way of stopping me from getting data that you already freely make available to me. Any service that is publicly available is publicly available, plain and simple.
If you are using Apache you can set allow/deny on locations.
http://www.apachesecurity.net/
or here is a link to the apache docs on the Deny directive
http://httpd.apache.org/docs/2.0/mod/mod_access.html#deny
EDITS (responding to the new info).
The Deny directive also works with environment variables. You can restrict access based on browser string (not really secure, but discourages casual browsing) which would still allow XHR calls.
I would suggest the best way to accomplish this is to have a token of some kind that validates the request is a 'good' request. You can do that with a cookie, a session store of some kind, or a parameter (or some combination).
What I would suggest for something like this is to generate a unique url for the service that expires after a short period of time. You could do something like this pretty easily with Memcache. This strategy could also be used to obfuscate the service url (which would not provide any actual security, but would raise the bar for someone wanting to make direct calls).
Lastly, you could also use public key crypto to do this, but that would be very heavy. You would need to generate a new pub/priv key pair for each request and return the pubkey to the js client (here is a link to an implementation in javascript) http://www.cs.pitt.edu/~kirk/cs1501/notes/rsademo/
You can add a random number as a flag to determine whether the request are coming from the page just sent:
1) When generates index.html, add a random number to the JSON request URL:
Old: http://example.com/json/?zipcode=12345
New: http://example.com/json/?zipcode=12345&f=234234234234234234
Add this number to the Session Context as well.
2) The client browser renders the index.html and request JSON data by the new URL.
3) Your server gets the json request and checks the flag number with Session Context. If matched, response data. Otherwise, return an error message.
4) Clear Session Context by the end of response, or timeout triggered.
Accept only POST requests to the JSON-yielding URL. That won't prevent determined people from getting to it, but it will prevent casual browsing.
I know this is old but for anyone getting here later this is the easiest way to do this. You need to protect the AJAX subpage with a password that you can set on the container page before calling the include.
The easiest way to do this is to require HTTPS on the AJAX call and pass a POST variable. HTTPS + POST ensures the password is always encrypted.
So on the AJAX/sub-page do something like
if ($_POST["access"] == "makeupapassword")
{
...
}
else
{
echo "You can't access this directly";
}
When you call the AJAX make sure to include the POST variable and password in your payload. Since it is in POST it will be encrypted, and since it is random (hopefully) nobody will be able to guess it.
If you want to include or require the PHP directly on another page, just set the POST variable to the password before including it.
$_POST["access"] = "makeupapassword";
require("path/to/the/ajax/file.php");
This is a lot better than maintaining a global variable, session variable, or cookie because some of those are persistent across page loads so you have to make sure to reset the state after checking so users can't get accidental access.
Also I think it is better than page headers because it can't be sniffed since it is secured by HHTPS.
You'll probably have to have some kind of cookie-based authentication. In addition, Ignacio has a good point about using POST. This can help prevent JSON hijacking if you have untrusted scripts running on your domain. However, I don't think using POST is strictly necessary unless the outermost JSON type is an array. In your example it is an object.

Categories

Resources