I've question about dangerouslySetInnerHTML, is it dangerous to use it, when the html comes from my api or there is no difference and maybe attacked anyway? Thanks
When the HTML comes from any API is when it's most dangerous to use dangerouslySetInnerHTML.
This is covered in the docs:
In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.
Essentially, the issue is that if your server doesn't properly sanitise user input, you open your site up to attacks that React protects you from by default. For example, lets say you allow users to write comments on your website, and your API sends back those comments in HTML. If a user writes a comment like e.g.
my comment <img src="./404" onerror="alert('test')" />
then e.g. that JavaScript code might be executed whenever someone else views that comment, unless you remember to protect against that when processing the comments.
I'd recommend returning your data from your API in a different format (e.g. JSON), and then processing it into React elements on the frontend.
DangerouslySetInnerHTML
Yes, there's potential concern. Although, you'll gain some extra performance, since react doesn't compare the dangerouslySetInnerHTML field with Virtual DOM.
HOW EXACTLTY IT'S DANGEROUS?
If user add some malicious code into the comments / other inputs and this data renders on the dangerouslySetInnerHTML field via API, your application deal with XSS Attack ([https://owasp.org/www-community/attacks/xss/][1]).
HOW CAN POTENTIAL XSS BE PREVENTED?
Based on the best practices, it's best to sanitize the dangerouslySetInnerHTML element with some external modules like: DOMPurify (https://github.com/cure53/DOMPurify). It will remove/filter out the potentially malicious code from the HTML and prevent XSS.
Related
There is a replacement for innerHtml in react: dangerouslySetInnerHTML.
Its name scares me.
In the React documents I read that:
In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.
But I sanitized my html with dompurify.
Does this completely protect me from XSS attacks?
But I sanitized my html with dompurify. Does this completely protect me from XSS attacks?
Likely yes, but it's not 100% guaranteed. If DOMPurify doesn't have bugs that will let XSS through, setting innerHTML or dangerouslySetInnerHTML with its results will be safe. DOMPurify is open-source and relatively popular, so if it did have such vulnerabilities, they would probably have been seen by now.
But, like with everything humans do, mistakes and coincidences that result in vulnerabilities not being seen are still possible.
Its name scares me.
It's supposed to. :-)
But I sanitized my html with dompurify. Does this completely protect me from XSS attacks?
It claims to:
DOMPurify sanitizes HTML and prevents XSS attacks. You can feed DOMPurify with string full of dirty HTML and it will return a string (unless configured otherwise) with clean HTML. DOMPurify will strip out everything that contains dangerous HTML and thereby prevent XSS attacks and other nastiness.
Whether you believe the claim is really your call to make. That said, sanitizing HTML is a well-studied problem so it's certainly possible to do. I make no claims for that particular library, which I haven't used or audited.
I've been thinking, how is the onClick tag secure (as well as other tags)? I mean, Anyone can put whatever javascript they want to execute when they trigger the onClick, what prevents someone from injecting malicious code?
The browser client is inherently insecure. It is a completely insecure execution environment and you cannot really secure it in any way.
The way to think about this is that you do NOT control what happens in the browser. All sorts of code can be injected, modified or run in any browser (via bookmarklets, console, direct DOM manipulation including adding arbitrary onclick handlers, proxy modification, debugging tools, etc...). So, your client is inherently insecure. Once you accept that the browser is fundamentally insecure, it's easier to understand what you need to do on your server.
That's why YOU have to validate and sanitize any results that arrive at your server from a client. You must do this on the server in order to prevent bad data from getting into your server. You must not trust that any data being sent to you is correct or valid. Instead, you must validate it completely on the server before using it.
You can almost think of it like any form submission or Ajax call or a URL with query arguments or a structured URL that your server accepts is an API call to your server and you have no idea who is using that API and whether they are using it correctly or not. Thus, you must assume nothing about the validity of the data or request as it arrives until you've checked it yourself on the server to see if everything is valid.
FYI, there are various techniques such as "data or function hiding in closures", code obscuration, etc... that make it more difficult for someone to mess with certain parts of your Javascript. But, it is important to understand that these are only temporary roadblocks to the determined or skilled hacker and do not offer actual security and should not be relied upon for security. The skilled hacker can literally replace your entire Javascript with their own modified version which pretty much means there's nothing you can do in your client-side Javascript to protect it.
Absolutely nothing prevents a client from running malicious javascript or using other developer tools. (e.g., adding form elements)
That's why it's up to you to keep your server-side scripts secure. (Sanitizing user input, etc.)
The problem is not usually whether or not a single user can run any JS in their own browser on their own computer.
The problem is when you are allowed to save that script to the database without sanitising it first and it then gets rendered on the page for everyone else to see and execute. Then, suddenly, they can execute code on other people's machines, steal their details, etc.
In other words, if you allow users to specify HTML markup in their comments, for example, and you don't search that markup for <script> tags, onclick attributes, etc and remove them before you save it to the database, then you have a potential problem. It becomes an actual problem when you fetch that saved markup from the DB and display it on the page somewhere without removing any JS-related functionality.
There is no protection. From the developer console/inspect element, you can modify the code in the tag. However, only you can see the modifications that you make in the inspect element, they aren't saved permanently. So other users who visit the site cannot see the code you entered inside of the developer console.
What prevents the people who make the page from putting malicious code into the onclick? Well, it's impossible to have truly dangerous code in javascript, the worst a website can do to a computer is crash the browser. So javascript is pretty safe.
Are all known javascript framekillers vulnerable to XSS?
If yes, whould it be enough to sanitize window.location before breaking out of an iframe?
What would be the best way to do it?
Could you please give an example of possible XSS attack?
Thanks!
UPD: The reason I'm asking is because I got a vulnerability scan alert saying that JS framekiller code containing top.location.replace(document.location) is XSS vulnerable as document.location is controlled by the user.
What was right in their description: variables like 'document.location', 'window.location', 'self.location' are (partially) controlled by non-trusted user. This is because the choice of (sub)string in non-trusted domain and page location ('http://non.trusted.domain.com/mypage') and non-trusted request string ('http://my.domain.com/?myrequest') are formed according to user's intention that may not always be good for you.
What was wrong: this user-dependency is not necessarily XSS vulnerability. In fact, to form XSS you would need to have some code that effectively uses the content controlled by non-trusted user somewhere in your output stream for your page. In the example of simple framekiller like top.location.replace(window.location) there's no danger of XSS.
One example where we could talk about XSS would be code like
document.write('Click here')
Constructing URI like http://test.com/?dummy"<script>alert("Test")</script>"dummy and substituting instead of document.location by you code will trigger non-trusted script in trusted webpage's context. As constructing such URI and passing it unescaped is a challenge, real XSS would work in some more complex scenarios involving inserting non-trusted variables verbatim into flow of language directives, be it HTML, CSS, JS, PHP, etc.
Another well-known example of XSS-unaware development was history of inventing JSON. While JSON has got strong popularity (having me among its proponents too), initially it was intended as "quick-n-dirty" way of storing JS data as pieces of plain JS-formatted data structures. In order to "parse" JSON blocks, it was enough just to eval() them. Fortunately, people quickly recognised how flawed was this whole idea, so nowadays any knowledgeable developer in sane mind will always use proper safe JSON parser instead.
A persistent follow-up of an admittedly similar question I had asked: What security restrictions should be implemented in allowing a user to upload a Javascript file that directs canvas animation?
I like to think I know JS decent enough, and I see common characters in all the XSS examples I've come accoss, which I am somewhat familiar with. I am lacking good XSS examples that could bypass a securely sound, rationally programmed system. I want people to upload html5 canvas creations onto my site. Any sites like this yet? People get scared about this all the time it seems, but what if you just wanted to do it for fun for yourself and if something happens to the server then oh well it's just an animation site and information is spread around like wildfire anyway so if anyone cares then i'll tell them not to sign up.
If I allow a single textarea form field to act as an IDE using JS for my programming language written in JS, and do string replacing, filtering, and validation of the user's syntax before finally compiling it into JS to be echoed by PHP, how bad could it get for me to host that content? Please show me how you could bypass all of my combined considerations, with also taking into account the server-side as well:
If JavaScript is disabled, preventing any POST from getting through, keeping constant track of user session.
Namespacing the Class, so they can only prefix their functions and methods with EXAMPLE.
Making instance
Storing my JS Framework in an external (immutable in the browser?) JS file, which needs to be at the top of the page for the single textarea field in the form to be accepted, as well as a server-generated key which must follow it. On the page that hosts the compiled user-uploaded canvas game/animation (1 per page ONLY), the server will verify the correct JS filename string before echoing the rest out.
No external script calls! String replacing on client and server.
Allowing ONLY alphanumeric characters, dashes and astericks.
Removing alert, eval, window, XMLHttpRequest, prototyping, cookie, obvious stuff. No native JS reserved words or syntax.
Obfuscating and minifying another external JS file that helps to serve the IDE and recognize the programming language's uniquely named Canvas API methods.
When Window unloads, store the external JS code in to two dynamically generated form fields to be checked by the server in POST. All the original code will be cataloged in the DB thoroughly for filtering purposes.
Strict variable naming conventions ('example-square1-lengthPROPERTY', 'example-circle-spinMETHOD')
Copy/Paste Disabled, setInterval to constantly check if enabled by the user. If so, then trigger a block to the database, change window.location immediately and check the session ID through POST to confirm in case JS becomes disabled between that timeframe.
I mean, can I do it then? How can one do harm if they can't use HEX or ASCII and stuff like that?
I think there are a few other options.
Good places to go for real-life XSS tests, by the way, are the XSS Cheat Sheet and HTML5 Security Cheetsheet (newer). The problem with that, however, is that you want to allow Javascript but disallow bad Javascript. This is a different, and more complex, goal than the usual way of preventing XSS, by preventing all scripts.
Hosting on a separate domain
I've seen this referred to as an "iframe jail".
The goal with XSS attacks is to be able to run code in the same context as your site - that is, on the same domain. This is because the code will be able to read and set cookies for that domain, intiate user actions or redress your design, redirect, and so forth.
If, however, you have two separate domains - one for your site, and another which only hosts the untrusted, user-uploaded content, then that content will be isolated from your main site. You could include it in an iframe, and yet it would have no access to the cookies from your site, no access to redress or alter the design or links outside its iframe, and no access to the scripting variables of your main window (since it is on a different domain).
It could, of course, set cookies as much as it likes, and even read back the ones that it set. But these would still be isolated from the cookies for your site. It would not be able to affect or read your main site's cookies. It could also include other code which could annoy/harrass the user, such as pop-up windows, or could attempt to phish (you'd need to make it visually clear in your out-of-iframe UI that the content served is not part of your site). However, this is still sandboxed from your main site, where you own personal payload - your session cookies and the integrity of your overarching page design and scripts, is preserved. It would carry no less but no more risk than any site on the internet that you could embed in an iframe.
Using a subset of Javascript
Subsets of Javascript have been proposed, which provide compartmentalisation for scripts - the ability to load untrusted code and have it not able to alter or access other code if you don't give it the scope to do so.
Look into things like Google CAJA - whose aim is to enable exactly the type of service that you've described:
Caja allows websites to safely embed DHTML web applications from third parties, and enables rich interaction between the embedding page and the embedded applications. It uses an object-capability security model to allow for a wide range of flexible security policies, so that the containing page can effectively control the embedded applications' use of user data and to allow gadgets to prevent interference between gadgets' UI elements.
One issue here is that people submitting code would have to program it using the CAJA API. It's still valid Javascript, but it won't have access to the browser DOM, as CAJA's API mediates access. This would make it difficult for your users to port some existing code. There is also a compilation phase. Since Javascript is not a secure language, there is no way to ensure code cannot access your DOM or other global variables without running it through a parser, so that's what CAJA does - it compiles it from Javascript input to Javascript output, enforcing its security model.
htmlprufier consists of thousands of regular expressions that attempt "purify" html into a safe subset that is immune to xss. This project is bypassesed very few months, because it isn't nearly complex enough to address the problem of XSS.
Do you understand the complexity of XSS?
Do you know that javascript can exist without letters or numbers?
Okay, they very first thing I would try is inserting a meta tag that changes the encoding to I don't know lets say UTF-7 which is rendered by IE. Within this utf-7 enocded html it will contain javascript. Did you think of that? Well guess what there is somewhere between a hundred thousand and a a few million other vectors I didn't think of.
The XSS cheat sheet is so old my grandparents are immune to it. Here is a more up to date version.
(Oah and by the way you will be hacked because what you are trying to do fundamentally insecure.)
I want to allow user contributed Javascript in areas of my website.
Is this completely insane?
Are there any Javascript sanitizer scripts or good regex patterns out there to scan for alerts, iframes, remote script includes and other malicious Javascript?
Should this process be manually authorized (by a human checking the Javascript)?
Would it be more sensible to allow users to only use a framework (like jQuery) rather than giving them access to actual Javascript? This way it might be easier to monitor.
Thanks
I think the correct answer is 1.
As soon as you allow Javascript, you open yourself and your users to all kinds of issues. There is no perfect way to clean Javascript, and people like the Troll Army will take it as their personal mission to mess you up.
1. Is this completely insane?
Don't think so, but near. Let's see.
2. Are there any Javascript sanitizer scripts or good regex patterns out there to scan for alerts, iframes, remote script includes and other malicious Javascript?
Yeah, at least there are Google Caja and ADSafe to sanitize the code, allowing it to be sandboxed. I don't know up to what degree of trustworthiest they provide, though.
3. Should this process be manually authorized (by a human checking the Javascript)?
It may be possible that sandbox fails, so it would be a sensible solution, depending on the risk and the trade-off of being attacked by malicious (or faulty) code.
4. Would it be more sensible to allow users to only use a framework (like jQuery) rather than giving them access to actual Javascript? This way it might be easier to monitor.
JQuery is just plain Javascript, so if you're trying to protect from attacks, it won't help at all.
If it is crucial to prevent these kind of attacks, you can implement a custom language, parse it in the backend and produce the controlled, safe javascript; or you may consider another strategy, like providing an API and accessing it from a third-party component of your app.
Take a look at Google Caja:
Caja allows websites to safely embed DHTML web applications from third parties, and enables rich interaction between the embedding page and the embedded applications. It uses an object-capability security model to allow for a wide range of flexible security policies, so that the containing page can effectively control the embedded applications' use of user data and to allow gadgets to prevent interference between gadgets' UI elements.
Instead of checking for evil things like script includes, I would go for regex-based whitelisting of the few commands you expect to be used. Then involve a human to authorize and add new acceptable commands to the whitelist.
Think about all of the things YOU can do with javascript. Then think about the things you would do if you could do it on someone elses site. These are things that people will do just because they can, or to find out if they can. I don't think it is a good idea at all.
It might be safer to design/implement your own restricted scripting language, which can be very similar to JavaScript, but which is under the control of your own interpreter.
Probably. The scope for doing bad things is going to be much greater than it is when you simply allow HTML but try to avoid alloing JavaScript.I do not know.Well, two things: do you really want to spend your time doing this, and if you do this you had better make sure they see the javascript code rather than actual live JavaScript!I can't see why this would make any difference, unless you do have someone approving posts and that person happens to be more at home with jQuery than plain JavaScript.
Host it on a different domain. Same-origin security policy in browsers will then prevent user-submitted JS from attacking your site.
It's not enough to host it on a different subdomain, because subdomains can set cookies on higher-level domain, and this could be used for session fixation attacks.