Make --serve and --serve-port take an origin argument, in order to disallow random websites from accessing the local port

Fri, 28 Dec 2018 04:35:51 -0500

author
Waqas Hussain <waqas20@gmail.com>
date
Fri, 28 Dec 2018 04:35:51 -0500
changeset 157
b35dc87ebff0
parent 156
807dc9c0f140
child 158
f09fe6c16e10

Make --serve and --serve-port take an origin argument, in order to disallow random websites from accessing the local port

main.lua file | annotate | diff | comparison | revisions
scansion/serve.lua file | annotate | diff | comparison | revisions
--- a/main.lua	Mon Sep 17 22:07:19 2018 +0100
+++ b/main.lua	Fri Dec 28 04:35:51 2018 -0500
@@ -17,6 +17,7 @@
 local quiet = false;
 local force_summary = false;
 local serve_mode = false;
+local serve_origin = nil;
 local only_tags, skip_tags;
 
 local property_rules = {};
@@ -115,8 +116,10 @@
 			force_summary = true;
 		elseif opt == "--serve" then
 			serve_mode = 8007;
+			serve_origin = assert(get_value(), "origin expected for '--serve'");
 		elseif opt == "--serve-port" then
 			serve_mode = assert(tonumber(get_value()), "expected port number");
+			serve_origin = assert(get_value(), "origin expected for '--serve-port'");
 		else
 			error("Unhandled command-line option: "..opt);
 		end
@@ -349,7 +352,7 @@
 		-- This function handles scansion errors,
 		-- but they shouldn't reach here anyway
 	end);
-	serve.run({ port = serve_mode }, run_test_script);
+	serve.run({ port = serve_mode, origin = serve_origin }, run_test_script);
 	os.exit(0);
 end
 
--- a/scansion/serve.lua	Mon Sep 17 22:07:19 2018 +0100
+++ b/scansion/serve.lua	Fri Dec 28 04:35:51 2018 -0500
@@ -19,7 +19,17 @@
 			local chunk = json.encode(entry) .. "\r\n";
 			response.conn:write(("%x\r\n%s\r\n"):format(#chunk, chunk));
 		end
-	
+
+		-- SECURITY NOTE: We MUST validate Origin before running the Scansion script,
+		-- since we don't want arbitrary websites to have local RCEs (CORS does not
+		-- protect us here, it at best keeps the script from seeing the response)
+		if request.headers.origin ~= config.origin and config.origin ~= "*" then
+			verse.log("warn", "Rejecting origin: %s", request.headers.origin);
+			response.status_code = 403; -- spec suggested response when we don't like the origin
+			response.headers.connection = "close";
+			return "";
+		end
+
 		response.status_code = 201;
 		response.headers.connection = "close";
 		response.headers.transfer_encoding = "chunked";

mercurial