added CSRF check

This commit is contained in:
Michael Zhang 2016-01-07 21:25:50 -06:00
parent f4a3f4513c
commit b7f4e75350
7 changed files with 100 additions and 71 deletions

View file

@ -1,31 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: package api</title>
<meta charset="utf-8">
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong>api</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/vagrant/server/api/__init__.py">/home/vagrant/server/api/__init__.py</a></font></td></tr></table>
<p></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Package Contents</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="api.admin.html">admin</a><br>
<a href="api.api.html">api</a><br>
<a href="api.decorators.html">decorators</a><br>
</td><td width="25%" valign=top><a href="api.logger.html">logger</a><br>
<a href="api.models.html">models</a><br>
<a href="api.problem.html">problem</a><br>
</td><td width="25%" valign=top><a href="api.schemas.html">schemas</a><br>
<a href="api.user.html">user</a><br>
<a href="api.utils.html">utils</a><br>
</td><td width="25%" valign=top></td></tr></table></td></tr></table>
</body></html>

View file

@ -1,42 +1,59 @@
from functools import wraps
from flask import abort, request, session, make_response
import json
import traceback
from functools import wraps
from flask import session
import utils
class WebException(Exception): pass
response_header = { "Content-Type": "application/json; charset=utf-8" }
def api_wrapper(f):
@wraps(f)
def wrapper(*args, **kwds):
web_result = {}
response = 200
try:
web_result = f(*args, **kwds)
except WebException as error:
response = 200
web_result = { "success": 0, "message": str(error) }
except Exception as error:
response = 200
traceback.print_exc()
web_result = { "success": 0, "message": "Something went wrong! Please notify us about this immediately.", "error": [ str(error), traceback.format_exc() ] }
return json.dumps(web_result), response, { "Content-Type": "application/json; charset=utf-8" }
return wrapper
@wraps(f)
def wrapper(*args, **kwds):
if request.method == "POST":
token = session.pop("csrf_token")
if not token or token != request.form.get("csrf_token"):
return make_response(json.dumps({ "success": 0, "message": "Token has been tampered with." }), 403, response_header)
web_result = {}
response = 200
try:
web_result = f(*args, **kwds)
except WebException as error:
response = 200
web_result = { "success": 0, "message": str(error) }
except Exception as error:
response = 200
traceback.print_exc()
web_result = { "success": 0, "message": "Something went wrong! Please notify us about this immediately.", "error": [ str(error), traceback.format_exc() ] }
result = (json.dumps(web_result), response, response_header)
# Setting CSRF token
if "token" not in session:
token = utils.generate_string()
response = make_response(result)
response.set_cookie("csrf_token", token)
session["csrf_token"] = token
return response
return wrapper
import user # Must go below api_wrapper to prevent import loops
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not user.is_logged_in():
return { "success": 0, "message": "Not logged in." }
return f(*args, **kwargs)
return decorated_function
@wraps(f)
def decorated_function(*args, **kwargs):
if not user.is_logged_in():
return { "success": 0, "message": "Not logged in." }
return f(*args, **kwargs)
return decorated_function
def admins_only(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not user.is_admin():
return { "success": 0, "message": "Not authorized." }
return f(*args, **kwargs)
return decorated_function
@wraps(f)
def decorated_function(*args, **kwargs):
if not user.is_admin():
return { "success": 0, "message": "Not authorized." }
return f(*args, **kwargs)
return decorated_function

View file

@ -1,4 +1,4 @@
from flask import Blueprint, session, request, redirect, url_for
from flask import Blueprint, make_response, session, request, redirect, url_for
from flask import current_app as app
from voluptuous import Schema, Length, Required
@ -44,7 +44,7 @@ def user_register():
return { "success": 1, "message": "Success!" }
@blueprint.route("/logout", methods=["POST"])
@blueprint.route("/logout", methods=["GET"])
@api_wrapper
def user_logout():
sid = session["sid"]
@ -69,7 +69,7 @@ def user_login():
return { "success": 1, "message": "Success!" }
@blueprint.route("/status", methods=["POST"])
@blueprint.route("/status", methods=["GET"])
@api_wrapper
def user_status():
logged_in = is_logged_in()
@ -79,9 +79,10 @@ def user_status():
"admin": is_admin(),
"username": session["username"] if logged_in else "",
}
return result
@blueprint.route("/info", methods=["POST"])
@blueprint.route("/info", methods=["GET"])
@api_wrapper
def user_info():
logged_in = is_logged_in()

View file

@ -19,6 +19,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.9.3/js/bootstrap-select.min.js" integrity="sha384-1qZEXZBmj54fSiiWT8bZQGEpCumJWDrAoEqMdg6N5bTTLCkU5RXoNeUsKWekRYob" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.4.3/jquery.timeago.min.js" integrity="sha384-Bap3DetwPgo4GEFvaIDVSIrz5G0mUAUsfCUcEsi+JrrNu7dyj3gBmuAG4hDIGg/4" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/smooth-scroll/7.1.1/js/smooth-scroll.min.js" integrity="sha384-bznoxhRX5dRiE60JhQSru8t7g2RPG9lwqvyut8sjFFWmsAlp+R38e7DiATv1YyIu" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js" integrity="sha384-tSi+YsgNwyohDGfW/VhY51IK3RKAPYDcj1sNXJ16oRAyDP++K0NCzSCUW78EMFmf" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ckeditor/4.5.4/ckeditor.js" integrity="sha384-N2/iPbB6nrU8RupS9WXTBZ1d2TRMI9qixvmdYNC+cbc12q9+YRW0Kw99QZfmYQzq" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.2/ace.js" integrity="sha384-niN+bRlaXMBoq/f5L4zKOEYGxuD0YRGBocto9LP2fB1UiMfxrymATRN4GqjVUt6J" crossorigin="anonymous"></script>
<script src="/js/easyctf.js"></script>

View file

@ -57,7 +57,7 @@ app.config(function($routeProvider, $locationProvider) {
app.controller("mainController", ["$scope", "$http", function($scope, $http) {
$scope.config = { navbar: { } };
$.post("/api/user/status", function(result) {
$.get("/api/user/status", function(result) {
if (result["success"] == 1) {
$scope.config.navbar.logged_in = result["logged_in"];
$scope.config.navbar.username = result["username"];
@ -74,7 +74,7 @@ app.controller("mainController", ["$scope", "$http", function($scope, $http) {
}]);
app.controller("logoutController", function() {
$.post("/api/user/logout", function(result) {
$.get("/api/user/logout", function(result) {
location.href = "/";
});
});
@ -83,7 +83,7 @@ app.controller("profileController", ["$controller", "$scope", "$http", "$routePa
var data = { };
if ("username" in $routeParams) data["username"] = $routeParams["username"];
$controller("mainController", { $scope: $scope });
$.post("/api/user/info", data, function(result) {
$.get("/api/user/info", data, function(result) {
if (result["success"] == 1) {
$scope.user = result["user"];
}
@ -108,7 +108,7 @@ app.controller("adminController", ["$controller", "$scope", "$http", function($c
app.controller("adminProblemsController", ["$controller", "$scope", "$http", function($controller, $scope, $http) {
$controller("adminController", { $scope: $scope });
$.post("/api/admin/problems/list", function(result) {
$.get("/api/admin/problems/list", function(result) {
if (result["success"] == 1) {
$scope.problems = result["problems"];
}
@ -147,12 +147,16 @@ $.fn.serializeObject = function() {
var register_form = function() {
var input = "#register_form input";
var data = $("#register_form").serializeObject();
data["csrf_token"] = $.cookie("csrf_token");
$.post("/api/user/register", data, function(result) {
if (result["success"] == 1) {
location.href = "/profile";
} else {
display_message("register_msg", "danger", result["message"])
display_message("register_msg", "danger", result["message"]);
}
}).fail(function(jqXHR, status, error) {
var result = JSON.parse(jqXHR["responseText"]);
display_message("register_msg", "danger", "Error " + jqXHR["status"] + ": " + result["message"]);
});
};
@ -161,11 +165,15 @@ var register_form = function() {
var login_form = function() {
var input = "#login_form input";
var data = $("#login_form").serializeObject();
data["csrf_token"] = $.cookie("csrf_token");
$.post("/api/user/login", data, function(result) {
if (result["success"] == 1) {
location.href = "/profile";
} else {
display_message("login_msg", "danger", result["message"])
display_message("login_msg", "danger", result["message"]);
}
}).fail(function(jqXHR, status, error) {
var result = JSON.parse(jqXHR["responseText"]);
display_message("login_msg", "danger", "Error " + jqXHR["status"] + ": " + result["message"]);
});
};

View file

@ -31,6 +31,7 @@
<div class="row">
<div class="col-sm-12 form-group">
<center>
<input type="hidden" id="_csrf" value="{{ csrf_token }}" />
<input type="submit" class="btn btn-success btn-lg" value="Login" />
</center>
</div>

View file

@ -6,7 +6,7 @@
<img src="//www.gravatar.com/avatar/?size=512" id="avatar" style="max-width:100%;" />
<small style="display:block;text-align:right;" ng-show="user['me']==true"><a href="http://en.gravatar.com/emails/" target="_blank">Edit Picture</a></small>
<h2 style="margin:0px;font-weight:bold;font-size:2em;">{{ user.name }}</h2>
<small style="display:block;font-size:1.5em;">@{{ user.username }}</small>
<small style="display:block;font-size:1.5em;color:#999;">@{{ user.username }}</small>
<hr>
<div>
<i class="fa fa-fw fa-user"></i>
@ -34,6 +34,38 @@
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="profile">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Team Information</h4>
</div>
<div class="panel-body">
Hi.
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Statistics</h4>
</div>
<div class="panel-body">
Hi.
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Top Solves</h4>
</div>
<div class="panel-body">
Hi.
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">Achievements</h4>
</div>
<div class="panel-body">
Hi.
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="activity">
</div>