What makes an unsafe script "unsafe"? - javascript

I'm new to chrome extensions. I'm writing a little plug-in that zooms in a page when the user presses a button (very new). However, it won't run unless I allow unsafe scripts and it won't carry over to new pages, ostensibly because of the unsafe scripts. All I'm doing is zooming.
What I really want to know is, if it is not asking for information or directly accessing their computer, what makes a script unsafe?

There are three things making a script unsafe for Google extensions:
Inline JavaScript
It's a common beginer mistake (I have made it). You can't put inline JavaScript statements. For example, you can't handle event this way:
<img src="myImage.jpg" onclick="doSomething()">
The correct way to do this is to do define an Id for your DOM element, the image in my example, and to set the event handler in a separate JavaScript file:
page.html:
<img src="myImage.jpg" id="myImage">
<script src="script.js"></script>
script.js:
//In vanilla Javascript :
document.getElementById("myImage").onClick(doSomething);
//In JQuery
$("#myImage").on("click", doSomething);
Eval and related functions
All functions that can evaluate String as JavaScript in the fly are unsafe.
So the eval function is not allowed, such as new Function("return something.value");
Remote scripts
Only local scripts are safe. If you are using for example jQuery, you have to include the library in your extension. Loading external library via CDN links is considered as unsafe.
It's a quick overview, you can read more about this and have the explanations of this restrictions on Google Chrome extension Content Security Policy

Another thing to consider is how you're sourcing your files.
For example, if you source a file using http://, but access the site using https://, you will get an unsafe scripts error.

Related

HTML: disable dynamically added <script> tags?

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'

How to load error trackers from script tag?

I'm working on small .js which is going to be embedded on multiple websites, it will be loaded in a classic way - via script tag: <script src="myscript.js"></script> in sites body tag. I cannot add any more scripts to those sites.
I would like to track errors with error tracker such as Sentry, Rollup or HoneyBadger. However, all of them require being loaded with another script tag, most preferred before everything else.
Note: Those services need to load before everything else to catch errors property.
As I cannot add another script tag in the site's code, I need to execute their code inside my script, but before my actual script code.
I tried taking the content of HoneyBadger javascript library and putting it directly inside my file - it worked, however, I feel like it's terrible practice, as their code is written with modern browsers in mind, and mine supports older ones.
Is there any good way in my situation to load their .js externally?
I don't think that would work because of the way honeybadger.js v0.5 parses the script tag to get those attributes--it looks for the script tag in the dom when it's loaded.
Also, we've moved away from using the data- attributes in honeybadger.js v1.0, which was just released. In that version, you must use Honeybadger.configure to set your API key. Take a look at the new docs here:
https://docs.honeybadger.io/lib/javascript/integration/browser.html
I'd recommend going with v1.0, and using Honeybadger.configure for the configuration.

Is there a danger to creating a js file that simply uses document.write() to bundle js and css files?

I am building a front-end UI framework for developers in my firm to use to build internal web apps. It consists of customized Bootstrap, jQuery, other open-source libraries, internal modules and stylesheets. The user environment is entirely IE9 and my server is .NET 3.5. I am hosting the shared files. Dev teams in the firm will place the links in their project pages and apply the framework to their pages.
I want to offer them the simplest method of implementing this which would be one line of code to paste that builds the library for them. Cutting and pasting 30 lines of code is stale the moment Ctrl + V is pressed, it leaves me no control and is simply inelegant.
Failed Experiments
I tried using Head.js and LazyLoad both of which use best practices for inserting scripts. But each of them has caused either content to display before styled or conditions where methods are called before scripts load. I am giving up on this approach.
It's too volatile.
A simple document.write() solution
Over the weekend, I thought: Why don't I just make a js file named "framework,js", add the script and link files in order with a stack of document.write() lines. Tell developers to put it in the head and that's it. Heck I could add the necessary metatags for IE9 and mobile too for that matter. It's so nasty and simple... but it just might work!
The user base is on an internal network and of limited size. Bandwidth is not a problem. I'll test performance before I choose this. I can direct the developer teams on where to place the link.
Knowing this and providing it actually works, is there any reason why I shouldn't do this?
My only other option to explore is bundling on the server. I am hoping not to have to resort to this since I don't own the server myself and I am not a .NET developer.
Your proposed approach is an excellent one for your situation. It has several advantages over the more sophisticated solutions, including utter simplicity, completely predictable order of execution, and full compatibility with scripts that may not lend themselves to asynchronous loading. I have used it many times in production applications, as have many other developers.
Of course the other solutions have their advantages too, but for what you're doing there is nothing wrong with good old document.write().
It sounds like you have a number of scripts and stylesheets and are probably loading them from a common directory (or a common root directory). To reduce repetition in your framework.js file, you might want to define two functions, one to write a <link> tag for CSS and another to write a <script> tag for JavaScript. So a skeleton framework.js file might look something like this:
(function() {
var scriptBase = 'js/';
var styleBase = 'css/';
function writeStyle( name ) {
document.write(
'<link rel="stylesheet" href="', styleBase, name, '">',
'</link>'
);
}
function writeScript( name ) {
document.write(
'<script src="', scriptBase, name, '">',
'</script>'
);
}
writeStyle( 'one.css' );
writeStyle( 'two.css' );
writeScript( 'one.js' );
writeScript( 'two.js' );
})();
Note that you don't have to do any special escaping of the </script> text as you may see in code that uses document.write(). That's only necessary when you're putting this code directly inside a <script> tag within the HTML file. The purpose of that escaping is to prevent the enclosing <script> tag from being closed by the </script> text inside the document.write() call. Since your code is in an external .js file this is not an issue: the presence of the </script> text inside this file won't terminate the .js file.
Another point to keep in mind is that all of the document.write() calls you make inside a .js file are inserted into the document after the .js file that writes them. So don't expect to be able to do a document.write() inside framework.js and then have other code inside framework.js that depends on the .js file you just wrote. All of those .js files (and .css) are loaded after framework.js, not interleaved with it.
One more consideration, of course, is load time. Your page could load faster if you combine and minify your CSS and JS files. But if these are internal web apps, page load time may be the least of your worries: reliability and maintainability may be more important. And in any case you can always use the document.write() solution to get up and running right now, and later optimize this only in the unlikely event that you need to.

Minimum characters to include JavaScript using HTML5 <script> tag

Now that the type attribute of the <script> tag can be omitted in HTML5, is this the fewest number of characters required to include external JavaScript on a page?
<script src="URL"></script>
Can anyone optimise it any more than this - what about if a framework such as jQuery was already loaded, is there an even shorter way?
You could omit the quotes for the attribute:
<script src=URL></script>
As well, with XHTML5 the following should work:
<script src="URL" />
If you don't care about the JavaScript being able to reach out and access page content, then
<img src="URL.svg">
where the URL points to an SVG image that uses SVG scripting would allow you to load a script and you could call functions defined in it by sending events to the SVG image to trigger event handlers.
You may be able to get around that restriction by using an SVG served from the same origin but I believe the security consequences of same-origin access for SVG are poorly understood so spec and browser writers are treading cautiously.
Since you asked about jQuery, you can use $.getScript():
$.getScript("f.js");
Of course this assumes your code has already been wrapped, or loaded in via in <script> tags. To be honest, there really isn't much benefit in trying to shave off a few more bytes in this area. It's not like referencing scripts requires a great deal of verbosity anyway.
Keep your code readable, and don't deviate too far from standards and accepted conventions.
[from my comments]
Supposing you already handled script aggregation using for example the excellent Google Closure Compiler and you don't want to use the heavy js loading libraries, a simple optimization is this :
<script src=a></script>
(no quote, no ".js", yes that's silly)
Of course, you can also remove spaces and CR before and after this part.

Loading an external script from within firefox extension

I am currently rewriting a firefox extension to be used only internally at my company. I started out by moving most of the logic into an external js file loaded via a script tag within the xul overlay. (We've found it hard to get our employees to consistently upgrade so I thought I could get around that). It worked fine like this:
<overlay id="my-overlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<script type="application/x-javascript" src="https://my.company.com/path/to/jquery.min.js/>
<script type="application/x-javascript" src="https://my.company.com/path/to/toolbar/main.js"/>
<toolbox id="navigator-toolbox">
<!-- some stuff here -->
</toolbox>
But then I had the crazy idea of loading the script file dynamically so that I could use preferences to determine whether it would load from the production servers or alpha/beta servers. And that's when I failed miserably.
I've tried the following unsuccessfully:
$.ajax({ dataType: 'script', ... }) // appears to do absolutely nothing
$('overlay').appendChild('', { src: ... }) // script tag is added but not executed
document.createElementNS, etc // script tag is is added but not executed
Components.utils.import // does not accept http protocol
mozIJSSubScriptLoader // does not accept http protocol
I haven't attempted Components.utils.evalInSandbox but given its restrictions, I'm afraid it would require significant other code changes that would not be worth the slight simplification of the development cycle.
From reading thru much more mozilla documentation and bugs it appears that basically what I'm attempting to do is breaking various security concerns (I understand in principle but of course in my case, I have full control of both ends).
The thing that bothers me is that it appears to work fine as long as I hard code the script tag but only fails once I try to dynamically generate it. Should I just toss in the towel or does someone know a way to make this work?
Have you tried the brute-force approach of reading in the file using XMLHttpRequest and then just calling eval() to run it? On the face of it this seems scary from a security perspective but, as you say, using a script tag with an HTTP source URL is basically the same thing.

Categories