luci-base: add support for POST-only actions with CSRF token check

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>
This commit is contained in:
Jo-Philipp Wich 2015-10-06 15:53:35 +02:00
parent d0f15d9804
commit 5a6382171d
2 changed files with 50 additions and 0 deletions

View 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)

View file

@ -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%>