aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2012-03-09 01:58:19 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2012-03-09 02:33:11 +0100
commit3f6797c21bb4c967266ca2227111409e8f069692 (patch)
tree9f4c486a31a73f82b8a52fc08391fc0f4e3eb460
downloadsecure.js-3f6797c21bb4c967266ca2227111409e8f069692.tar.xz
secure.js-3f6797c21bb4c967266ca2227111409e8f069692.zip
Initial commit.HEADmaster
-rw-r--r--README.txt25
-rw-r--r--secure.js60
-rw-r--r--test.html17
3 files changed, 102 insertions, 0 deletions
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..9450028
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,25 @@
+=============================
+= secure.js =
+= =
+= by zx2c4 =
+= Jason Donenfeld =
+= Jason@zx2c4.com =
+=============================
+
+Sometimes you want to provide a javascript service to somebody,
+but you only want it to run in an HTTPS context, because the
+information that your script will help gather from the page is
+somewhat sensitive.
+
+One way of enforcing HTTPS is to check that location.protocol is
+"https:", but this is extremely limited becuase it does not
+account for the possibility that your script may be included
+along side other scripts from other servers that are not loaded
+over HTTPS. When this happens, the security of your site is
+defeated, and man-in-the-middle attacks become practical.
+
+secure.js solves this issue by monitoring the DOM for changes and
+continiously checking whether or not any external resources have
+been added that are non-HTTPS.
+
+Suggestions and improvements are welcome.
diff --git a/secure.js b/secure.js
new file mode 100644
index 0000000..c420811
--- /dev/null
+++ b/secure.js
@@ -0,0 +1,60 @@
+(function() {
+ var secureJS = {
+ destroyPage: function() {
+ this.checkAndDestroy = function() {};
+ if (window.stop)
+ window.stop();
+ //TODO: Figure out how to halt all existing concurrent and async scripts, and clear all timers.
+ alert("This is a nasty alert box. Aren't JavaScript alerts so 1995? Yes, and so is plaintext HTTP.\n\nYou screwed up; your page isn't secure. Get it together. Fix things.");
+ window.location = "https://en.wikipedia.org/wiki/HTTP_Secure";
+ throw "Insecure site.";
+ },
+ checkPageProtocol: function() {
+ return window.location.protocol == "https:";
+ },
+ checkCollectionProtocol: function(collection, attribute) {
+ for (var i = 0; i < collection.length; ++i) {
+ var location = collection[i].getAttribute(attribute);
+ if (location == null)
+ continue;
+ // I actually have never read the URI RFC, so I'm sure there are special
+ // cases that really should be taken into account that I neglect here.
+ //TODO: Don't be a fool; do this properly.
+ var firstSlash = location.indexOf("/");
+ var firstDot = location.indexOf("/");
+ var protocolDelim = location.indexOf("://");
+ if (protocolDelim != -1 &&
+ (firstSlash == -1 || protocolDelim < firstSlash) &&
+ (firstDot == -1 || protocolDelim < firstDot) &&
+ location.indexOf("https") != 0)
+ return false;
+ }
+ return true;
+ },
+ isPageSecure: function() {
+ return this.checkPageProtocol() &&
+ this.checkCollectionProtocol(document.getElementsByTagName("script"), "src") &&
+ this.checkCollectionProtocol(document.getElementsByTagName("link"), "rel");
+ //TODO: What else is missing here? Embeds, objects, applets, probably a bunch of other info leaks.
+ // It might be nice to check that document.cookie is empty too, to check enforcement of httpOnly flag.
+ },
+ checkAndDestroy: function() {
+ if (!this.isPageSecure())
+ this.destroyPage();
+ }
+ };
+
+ document.addEventListener("DOMContentLoaded", function() { secureJS.checkAndDestroy(); }, true);
+ document.addEventListener("DOMNodeInserted", function() { secureJS.checkAndDestroy(); }, true);
+ document.addEventListener("DOMNodeInsertedIntoDocument", function() { secureJS.checkAndDestroy(); }, true);
+ document.addEventListener("DOMAttrModified", function() { secureJS.checkAndDestroy(); }, true);
+ document.addEventListener("DOMElementNameChanged", function() { secureJS.checkAndDestroy(); }, true);
+ document.addEventListener("DOMContentLoaded", function() { secureJS.checkAndDestroy(); }, true);
+ var timer = function() {
+ secureJS.checkAndDestroy();
+ //TODO: 500ms? Good? Bad? Polling this much or even at all isn't strictly neccessary,
+ // because of DOMNodeInserted, but just to be safe... What do you think?
+ window.setTimeout(timer, 500);
+ };
+ timer();
+})();
diff --git a/test.html b/test.html
new file mode 100644
index 0000000..0216f53
--- /dev/null
+++ b/test.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<script src="secure.js"></script>
+<script>
+setTimeout(function() {
+ alert("bout to insert");
+ var script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = 'http://www.zx2c4.com/somescript.js';
+ document.getElementsByTagName("head")[0].appendChild(script)
+}, 3000);
+</script>
+</head>
+<body>
+Will you see this text?
+</body>
+</html>