async def any_author_exists(self):
return bool(await self.query("SELECT * FROM authors LIMIT 1"))
+ def redirect_to_next(self):
+ next = self.get_argument("next", "/")
+ if next.startswith("//") or not next.startswith("/"):
+ # Absolute URLs are not allowed because this would be an open redirect
+ # vulnerability (https://cwe.mitre.org/data/definitions/601.html).
+ raise tornado.web.HTTPError(400)
+ self.redirect(next)
+
class HomeHandler(BaseHandler):
async def get(self):
tornado.escape.to_unicode(hashed_password),
)
self.set_signed_cookie("blogdemo_user", str(author.id))
- self.redirect(self.get_argument("next", "/"))
+ self.redirect_to_next()
class AuthLoginHandler(BaseHandler):
)
if password_equal:
self.set_signed_cookie("blogdemo_user", str(author.id))
- self.redirect(self.get_argument("next", "/"))
+ self.redirect_to_next()
else:
self.render("login.html", error="incorrect password")
class AuthLogoutHandler(BaseHandler):
def get(self):
self.clear_cookie("blogdemo_user")
- self.redirect(self.get_argument("next", "/"))
+ self.redirect_to_next()
class EntryModule(tornado.web.UIModule):
<!DOCTYPE html>
<html>
- <head>
- <meta charset="UTF-8">
- <title>{{ escape(handler.settings["blog_title"]) }}</title>
- <link rel="stylesheet" href="{{ static_url("blog.css") }}" type="text/css">
- <link rel="alternate" href="/feed" type="application/atom+xml" title="{{ escape(handler.settings["blog_title"]) }}">
- {% block head %}{% end %}
- </head>
- <body>
- <div id="body">
- <div id="header">
- <div style="float:right">
- {% if current_user %}
- <a href="/compose">{{ _("New post") }}</a> -
- <a href="/auth/logout?next={{ url_escape(request.uri) }}">{{ _("Sign out") }}</a>
- {% else %}
- {% raw _('<a href="%(url)s">Sign in</a> to compose/edit') % {"url": "/auth/login?next=" + url_escape(request.uri)} %}
- {% end %}
- </div>
- <h1><a href="/">{{ escape(handler.settings["blog_title"]) }}</a></h1>
+
+<head>
+ <meta charset="UTF-8">
+ <title>{{ escape(handler.settings["blog_title"]) }}</title>
+ <link rel="stylesheet" href="{{ static_url(" blog.css") }}" type="text/css">
+ <link rel="alternate" href="/feed" type="application/atom+xml" title="{{ escape(handler.settings[" blog_title"]) }}">
+ {% block head %}{% end %}
+</head>
+
+<body>
+ <div id="body">
+ <div id="header">
+ <div style="float:right">
+ {% if current_user %}
+ <a href="/compose">{{ _("New post") }}</a> -
+ <a href="/auth/logout?next={{ url_escape(request.path) }}">{{ _("Sign out") }}</a>
+ {% else %}
+ {% raw _('<a href="%(url)s">Sign in</a> to compose/edit') % {"url": "/auth/login?next=" +
+ url_escape(request.path)} %}
+ {% end %}
</div>
- <div id="content">{% block body %}{% end %}</div>
+ <h1><a href="/">{{ escape(handler.settings["blog_title"]) }}</a></h1>
</div>
- {% block bottom %}{% end %}
- </body>
-</html>
+ <div id="content">{% block body %}{% end %}</div>
+ </div>
+ {% block bottom %}{% end %}
+</body>
+
+</html>
\ No newline at end of file
message["html"] = tornado.escape.to_unicode(
self.render_string("message.html", message=message)
)
- if self.get_argument("next", None):
- self.redirect(self.get_argument("next"))
+ if next := self.get_argument("next", None):
+ if next.startswith("//") or not next.startswith("/"):
+ # Absolute URLs are not allowed because this would be an open redirect
+ # vulnerability (https://cwe.mitre.org/data/definitions/601.html).
+ raise tornado.web.HTTPError(400)
+ self.redirect(next)
else:
self.write(message)
global_message_buffer.add_message(message)
class AuthLoginHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
async def get(self):
- my_url = (
- self.request.protocol
- + "://"
- + self.request.host
- + "/auth/login?next="
- + tornado.escape.url_escape(self.get_argument("next", "/"))
- )
+ my_url = self.request.protocol + "://" + self.request.host + "/auth/login"
if self.get_argument("code", False):
user = await self.get_authenticated_user(
redirect_uri=my_url,
code=self.get_argument("code"),
)
self.set_signed_cookie("fbdemo_user", tornado.escape.json_encode(user))
- self.redirect(self.get_argument("next", "/"))
+ self.redirect("/")
return
self.authorize_redirect(
redirect_uri=my_url,
class AuthLogoutHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
def get(self):
self.clear_cookie("fbdemo_user")
- self.redirect(self.get_argument("next", "/"))
+ self.redirect("/")
class PostModule(tornado.web.UIModule):