Skip to content

Instantly share code, notes, and snippets.

@kmaglione
Created December 16, 2011 03:23
Show Gist options
  • Save kmaglione/1484292 to your computer and use it in GitHub Desktop.
Save kmaglione/1484292 to your computer and use it in GitHub Desktop.
LibreJS
Copyright (C) 2011 Loic J. Duros
Released under the GPL v3
Current Version: 2.3.0 -- 11/26/2011
Overview
========
LibreJS is an add-on for Mozilla Firefox (Abrowser, Iceweasel, ...) that
prevents the execution of nonfree nontrivial JavaScript as described
in "The Javascript Trap":
http://www.gnu.org/philosophy/javascript-trap.html
It has been tested for Firefox 7. Please see the Known issues section
in this document before using LibreJS.
Disclaimer
==========
- LibreJS is not a security tool and while its goal is to detect nonfree
nontrivial JavaScript, it does not detect whether free or trivial
code is malicious or not. You can use NoScript (or YesScript) in
conjunction with LibreJS to ensure security of the JavaScript being
loaded.
- Because LibreJS intercepts http responses to analyze and remove
JavaScript from a page, it will not analyze and block JavaScript if
it is loaded locally as a file within the user's filesystem, for
instance with file:///home/someone/test.html -- a request
http://localhost, however, would be caught and analyzed by the
add-on.
- LibreJS is always a work in progress. If you find a bug, please
report it to lduros@member.fsf.org
Changes from version 2.2.4 to version 2.2.5
===========================================
See changelog.
Changes from version 1.x to version 2
=====================================
1) The @licstart @licend stylized comments are now obligatory rather
than optional. We want to make sure an entire page is explicitely free
before considering it as free.
2) In version 1, all scripts that defined a function or method were
flagged as nontrivial. In version 2, as described in The JavaScript
Trap, it will only consider the JavaScript program as nontrivial if
the scripts define a function or a method and load external scripts
using the html <script> tag, or if an external script defines a method
or a function.
3) In the version 1, scripts on page and remote were analyzed individually.
In version 2 (current version):
- all scripts that are directly embedded in an html page are
analyzed as one to see whether they are trivial or free.
- If the on-page JavaScript is nonfree and nontrivial, all
JavaScript is removed and none of the external files are
analyzed.
- If the on-page JavaScript is free or trivial, the external
scripts are then fetched and analyzed to find whether they are
free or trivial individually.
- If any script, on-page or external, is found to be nontrivial,
all JavaScript is removed from the page (inline scripts,
intrinsec events in html attributes, external scripts, ...)
- If any free script is found to perform an AJAX request or embed
another script dynamically, or any construct that is flagged as
"suspicious", then any trivial code becomes "nontrivial", and
all JavaScript is then removed.
- When all the code is free but loads JavaScript dynamically, all
http responses of mime type javascript are checked to see
whether they are free/trivial at request time, and rejected if
they are nonfree nontrivial.
4) In version 1, a pure JavaScript HTML partial parser was used to
find <script> tags and other JavaScript elements on page. In
version 2, we are using a heavily modified third-party script to
load the http response intercepted into a hidden iframe with a data
uri (the hidden iframe has JavaScript off, as well as plugins off,
following the instructions in
https://developer.mozilla.org/En/Displaying_web_content_in_an_extension_without_security_issues).
We are then using JavaScript DOM methods to fetch and remove
scripts. This new method is a lot more secure and less prone to
forgetting some of the JavaScript or not finding weird
constructs. It also removes parts of the issue with the freezing
UI.
5) We are now using the url module from the Node.js project
(http://nodejs.org/) to convert relative path into absolute urls
when the DOM is loaded with a data uri.
Screenshots
===========
- The panel that shows the blocked JavaScript:
http://lduros.net/assets/librejs/v1/screenshots/librejs-v1-blockedscript-panel.jpg
- The preferences panel:
http://lduros.net/assets/librejs/v1/screenshots/librejs-v1-preferences.jpg
License
=======
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http: www.gnu.org="" licenses=""/>.
How to use
==========
After installing the add-on, you will see the LibreJS widget in the
add-on bar at the bottom of the browser window. After loading a page,
left-click on the widget to view the list of JavaScript removed from
the page (both on page and external). Up to 1000 characters are
displayed per Javascript piece, since some files are so large it
becomes impractical to display them in their entirety. See screenshot
here:
http://lduros.net/assets/librejs/v1/screenshots/librejs-v1-blockedscript-panel.jpg
You can also take a look at the JS removed by looking at the
page source: CTRL + U.
LibreJS intercepts http responses and rewrites them after analyzing
JavaScript within them. While it uses mime types to a certain extent,
it does not rely only on them and attempts to analyze any file for
javascript content (a content sniffer of some sort is on the way for a
future release).
The add-on offers a few options (and more to come). You can access
these options by right-clicking the widget. Please ignore the add-on
context menu that will appear (this is a bug with Firefox and the
add-on sdk).
A panel should appear in the middle of the page, with two checkboxes
available:
http://lduros.net/assets/librejs/v1/screenshots/librejs-v1-preferences.jpg
Currently, LibreJS searches for license mentions in two
ways, a short and a lazy way (the latter is optional). One uses
excerpts from the short notices usually provided by many licenses for
inclusion within source files, e.g. for the GPLv2:
<thisprogram> is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later
version.
When it finds a match, it flags the piece of JS as free. This is
called short definition. Another type of notice we call "lazy", here
is a popular example:
Dual licensed under the MIT or GPL Version 3 licenses
When the "Do not tolerate lazy license mentions" checkbox is checked,
the latter type of license mention is not used.
Tests
=====
In order to better understand how LibreJS works, you can try to visit
these pages with LibreJS installed and enabled and see how they are
being processed:
1) http://lduros.net/assets/librejs/tests/trivial-inline-trivial-external/
This page contains trivial on-page JavaScript code, and an external
script that contains trivial JavaScript code.
Therefore, all JavaScript is being executed.
2) http://lduros.net/assets/librejs/tests/trivial-inline-nontrivial-external/
This page contains trivial on-page JavaScript code, but loads an
external script that defines a function (nontrivial) and is not
free.
Therefore, all JavaScript is REMOVED from the page.
3) http://lduros.net/assets/librejs/tests/nontrivial-inline-trivial-external/
This page contains nontrivial code on page, and trivial code in its
external page.
All JavaScript is REMOVED from the page.
4) http://lduros.net/assets/librejs/tests/free-inline-free-external/
This page contains free on-page (GPL 3) JavaScript, and free
external Javascript. Therefore all JavaScript is being executed.
5) http://lduros.net/assets/librejs/tests/free-inline-nonfree-nontrivial-external/
This page contains free on-page JavaScript, but contains nonfree
nontrivial JavaScript in its external file (ajax request).
All JavaScript is REMOVED from the page.
6) http://lduros.net/assets/librejs/tests/intrinsec-event/
This page contains trivial on-page code, with an intrinsec event in
an html attribute (onload).
All JavaScript is being executed.
7) http://lduros.net/assets/librejs/tests/trivial-inline-free-external-defines-function/
This page contains on-page trivial JavaScript (only makes a window
alert and loads an external script using the html <script> tag with the
src attribute. The external script is free (GPL v3), and since it
is only nontrivial because it defines a function, the on-page
trivial code is allowed to use it.
All JavaScript is being executed.
8) http://lduros.net/assets/librejs/tests/trivial-inline-free-external-writes-script/
This page contains trivial on-page JavaScript code, and loads an
external script that is free.
HOWEVER, this free external script loads a script
dynamically. Therefore, since trivial code might be using it, no
trivial code is allowed.
Since the on-page trivial code is now nontrivial,
all Javascript is REMOVED from the page.
9) http://lduros.net/assets/librejs/tests/shelltypist/demo/real-life-example-with-jquery-free.html
This is a real-life example of a small jQuery plugin. The on-page
JavaScript code has a free license. The jQuery external file has a
free (but lazily defined) licensed. The shelltypist.js file has a
free license as well. All licenses are defined between @licstart
and @licend. If the "Do not consider lazy license mentions as free"
option is not checked (default), the JavaScript is executed,
despite the fact that the jQuery license mentions is:
Dual licensed under the MIT or GPL Version 2 licenses.
If you check the "Do not consider lazy license mentions as free"
option, then ALL JavaScript will be removed from the page after
reload.
10) http://lduros.net/assets/librejs/tests/shelltypist/demo/same-page-without-free-license.html
This is the same page than 9) but does not have a free license for
the main HTML page on-page script. While the actual code there is
trivial, since jQuery defines methods that make use of AJAX,
trivial code is not allowed, and no JavaScript is executed.
Options
=======
- Do not tolerate lazy license mentions (e.g.: dual-licensed under
...)
When checked, this option disallows the use of very brief
mentions of a license. ("Released under the MIT license", ...)
How LibreJS detects nontrivial JavaScript
=========================================
LibreJS uses Narcissus lexer/parser
(https://github.com/mozilla/narcissus) to perform a static check for a
few criteria:
- If the program defines a method or a function and loads external
scripts (using the <script> element and src attribute).
- If the program has an external script and defines a function or a
method.
- If it makes an AJAX request using XMLHttpRequest or ActiveXObject.
- If it loads an external script (creates a script tag somewhere in the
dom).
Because the code isn't interpreted (static analysis only) and we don't
keep track of scope and what variables contain, we have to discard a
few constructs:
- if eval() is used.
- if methods are invoked using the bracket suffix, such as:
t['meth'+'od'](arg);
- if it using document.write() with a concatenation or a function
call.
Free Licenses
=============
Currently LibreJS checks for the following licenses:
- GNU General Public License version 2
- GNU General Public License version 3
- GNU All-Permissive License
- Apache License, Version 2.0
- GNU Affero General Public License version 3
- Boost Software License
- BSD 2-Clause License
- BSD 3-Clause License
- Mozilla Public License Version 1.1
- Expat License
More licenses are on the way for the upcoming versions.
Known issues of LibreJS version 2
=================================
- LibreJS currently analyzes the JavaScript on page and in the
Javascript file using the same thread as the Mozilla Firefox
browser. Depending on hardware, this causes the UI to freeze for a
second or two when a large javascript file is being analyzed. I am
planning on using a chrome worker for Narcissus in the near future
(version 2), so that it can run in its own thread. This way large
complex files won't freeze the UI. 11/14/2011 UPDATE: This has been
partly addressed with the replacement of the recursive walkTree
function with the iterative one.
- It does not make good use of the caching system. Instead it dooms
the cache entry when the response is of type text/html or
javascript.
Fixed in version 2.2:
- FIXED: Currently there is no option to interpret javascript in the current
page or javascript file. In order to enable all Javascript back, you
must disable the add-on, but it does not require a Firefox
restart. A button is planned for the future release.
- FIXED: Clicking on an anchor link in the page currently loaded in the tab,
or appending a #[anything] to the location bar will prevent the
widget panel from displaying the removed Javascript. This is due to
the fact that it tracks JS according to the url, and so the # is
considered a new entry. However, the JavaScript is **still** being
blocked properly. (Check source for that.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment