luci-base: add support for POST-only actions with CSRF token check
authorJo-Philipp Wich <jow@openwrt.org>
Tue, 6 Oct 2015 13:53:35 +0000 (15:53 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Tue, 6 Oct 2015 13:56:35 +0000 (15:56 +0200)
Add the dispatcher infrastructure to restrict certain routes to POST
requests only in conjunction with verification of CSRF tokens.

This is the first step to get rid of the CSRF token in the url in favor
to tokens embedded in forms.

Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
modules/luci-base/luasrc/dispatcher.lua
modules/luci-base/luasrc/view/csrftoken.htm [new file with mode: 0644]

index 8b8d1fa3499cf03ce6c2542b67844bf39527bfff..798e3e6ce64d1aac4edeb6edbbe347756c02d39b 100644 (file)
@@ -1,4 +1,5 @@
 -- Copyright 2008 Steven Barth <steven@midlink.org>
+-- Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
 -- Licensed to the public under the Apache License 2.0.
 
 local fs = require "nixio.fs"
@@ -284,6 +285,7 @@ function dispatch(request)
                   resource    = luci.config.main.resourcebase;
                   ifattr      = function(...) return _ifattr(...) end;
                   attr        = function(...) return _ifattr(true, ...) end;
+                  token       = ctx.urltoken.stok;
                }, {__index=function(table, key)
                        if key == "controller" then
                                return build_url()
@@ -378,6 +380,20 @@ function dispatch(request)
                end
        end
 
+       if c and type(c.target) == "table" and c.target.post == true then
+               if http.getenv("REQUEST_METHOD") ~= "POST" then
+                       http.status(405, "Method Not Allowed")
+                       http.header("Allow", "POST")
+                       return
+               end
+
+               if http.formvalue("token") ~= ctx.urltoken.stok then
+                       http.status(403, "Forbidden")
+                       luci.template.render("csrftoken")
+                       return
+               end
+       end
+
        if track.setgroup then
                sys.process.setgroup(track.setgroup)
        end
@@ -703,6 +719,16 @@ function call(name, ...)
        return {type = "call", argv = {...}, name = name, target = _call}
 end
 
+function post(name, ...)
+       return {
+               type = "call",
+               post = true,
+               argv = { ... },
+               name = name,
+               target = _call
+       }
+end
+
 
 local _template = function(self, ...)
        require "luci.template".render(self.view)
diff --git a/modules/luci-base/luasrc/view/csrftoken.htm b/modules/luci-base/luasrc/view/csrftoken.htm
new file mode 100644 (file)
index 0000000..57ac03f
--- /dev/null
@@ -0,0 +1,24 @@
+<%#
+ Copyright 2015 Jo-Philipp Wich <jow@openwrt.org>
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
+<h2 name="content"><%:Form token mismatch%></h2>
+<br />
+
+<p class="alert-message"><%:The submitted security token is invalid or already expired!%></p>
+
+<p><%:
+       In order to prevent unauthorized access to the system, your request has
+       been blocked. Click "Continue »" below to return to the previous page.
+%></p>
+
+<hr />
+
+<p class="right">
+       <strong><a href="#" onclick="window.history.back();">Continue »</a></strong>
+</p>
+
+<%+footer%>