#32 Implement CSRF protection

병합
sindre csrf 에서 master 로 1 commits 를 머지했습니다 5 년 전
  1. +1
    -0
      src/app/templates/apply.html
  2. +1
    -0
      src/app/templates/login.html
  3. +1
    -0
      src/app/templates/new_project.html
  4. +1
    -0
      src/app/templates/project.html
  5. +1
    -0
      src/app/templates/register.html
  6. +4
    -3
      src/app/views/app.py
  7. +2
    -3
      src/app/views/apply.py
  8. +2
    -1
      src/app/views/login.py
  9. +2
    -2
      src/app/views/new_project.py
  10. +2
    -2
      src/app/views/project.py
  11. +2
    -2
      src/app/views/register.py
  12. +40
    -0
      src/app/views/utils.py

+ 1
- 0
src/app/templates/apply.html 파일 보기

@@ -21,6 +21,7 @@ $def with (nav, apply_form, get_apply_permission_form, project, applicants, perm
</div>

<form method="POST">
$:csrf_field()
<h4>Add Users</h4>
$:apply_form.render()
<h4>Users to apply:</h4>


+ 1
- 0
src/app/templates/login.html 파일 보기

@@ -15,6 +15,7 @@ $def with (nav, login_form, message)
$if not session.username:
<h3>Log In</h3>
<form method="POST">
$:csrf_field()
$:login_form.render()
</form>



+ 1
- 0
src/app/templates/new_project.html 파일 보기

@@ -14,6 +14,7 @@ $def with (nav, project_form, project_buttons, messasge)

<h2>Add project!</h2>
<form method="POST">
$:csrf_field()
<div>
$:project_form.render()
</div>


+ 1
- 0
src/app/templates/project.html 파일 보기

@@ -37,6 +37,7 @@ $def with (nav, project_form, project, tasks, permissions, categories)
<a href="$filename[0]" download>$filename[0].split("/")[-1]</a>
<br>
<form method="POST" enctype="multipart/form-data" action="">
$:csrf_field()
$project_form.taskid.set_value(task[0])
$:project_form.taskid.render()
$if (task[5] == "waiting for delivery" or task[5] == "declined"):


+ 1
- 0
src/app/templates/register.html 파일 보기

@@ -15,6 +15,7 @@ $def with (nav, register_form, message)
<h2>Register user!</h2>

<form method="POST">
$:csrf_field()
$:register_form.render()
</form>



+ 4
- 3
src/app/views/app.py 파일 보기

@@ -1,6 +1,6 @@
import os
import web
from views.utils import get_nav_bar
from views.utils import get_nav_bar, csrf_field
from views.login import Login
from views.logout import Logout
from views.register import Register
@@ -42,6 +42,9 @@ else:
# Add session to global variables
render._add_global(session, 'session')

# Add CSRF field to global variables
web.template.Template.globals['csrf_field'] = csrf_field

# Make the session available cross modules through webctx
def session_hook():
web.ctx.session = session
@@ -50,5 +53,3 @@ def session_hook():
app.add_processor(web.loadhook(session_hook))

app = app.wsgifunc()



+ 2
- 3
src/app/views/apply.py 파일 보기

@@ -1,7 +1,7 @@
import web
import models.project
from models.user import get_user_name_by_id
from views.utils import get_nav_bar, get_element_count
from views.utils import get_nav_bar, get_element_count, csrf_protected
from views.forms import get_apply_form, get_apply_permissions_form

# Get html templates
@@ -34,6 +34,7 @@ class Apply:

return render.apply(nav, apply_form, get_apply_permissions_form, project, applicants, permissions)

@csrf_protected
def POST(self):
"""
Post an application to the view, adding selected users to a project
@@ -123,5 +124,3 @@ class Apply:
permissions.append(["TRUE", "FALSE", "FALSE"])

return applicants, permissions


+ 2
- 1
src/app/views/login.py 파일 보기

@@ -1,8 +1,8 @@
import web
from views.forms import login_form
from views.utils import get_nav_bar, csrf_protected
import models.session
import models.user
from views.utils import get_nav_bar
import random
import string
import hashlib
@@ -34,6 +34,7 @@ class Login():

return render.login(nav, login_form, "")

@csrf_protected
def POST(self):
"""
Log in to the web application and register the session


+ 2
- 2
src/app/views/new_project.py 파일 보기

@@ -1,9 +1,9 @@
import web
from web import form
from views.forms import get_task_form_elements, get_project_form_elements, get_user_form_elements, project_buttons
from views.utils import get_nav_bar, get_element_count, csrf_protected
import models.project
import models.user
from views.utils import get_nav_bar, get_element_count

# Get html templates
render = web.template.render('templates/')
@@ -26,6 +26,7 @@ class New_project:
project_form = form.Form(*(project_form_elements + task_form_elements + user_form_elements))
return render.new_project(nav, project_form, project_buttons, "")

@csrf_protected
def POST(self):
"""
Create a new project
@@ -176,4 +177,3 @@ class New_project:

project_form = form.Form(*(project_form_elements + task_form_elements + user_form_elements))
return project_form

+ 2
- 2
src/app/views/project.py 파일 보기

@@ -1,6 +1,6 @@
import web
import models.project
from views.utils import get_nav_bar
from views.utils import get_nav_bar, csrf_protected
from views.forms import project_form
import os
from time import sleep
@@ -41,6 +41,7 @@ class Project:
render = web.template.render('templates/', globals={'get_task_files':models.project.get_task_files, 'session':session})
return render.project(nav, project_form, project, tasks,permissions, categories)

@csrf_protected
def POST(self):
# Get session
session = web.ctx.session
@@ -109,4 +110,3 @@ class Project:
models.project.update_task_status(data.taskid, "declined")

raise web.seeother(('/project?projectid=' + data.projectid))


+ 2
- 2
src/app/views/register.py 파일 보기

@@ -1,8 +1,8 @@
import web
from views.forms import register_form
from views.utils import get_nav_bar, csrf_protected
import models.register
import models.user
from views.utils import get_nav_bar
import hashlib
import re

@@ -22,6 +22,7 @@ class Register:
nav = get_nav_bar(session)
return render.register(nav, register_form, "")

@csrf_protected
def POST(self):
"""
Handle input data and register new user in database
@@ -46,4 +47,3 @@ class Register:
data.city, data.state, data.postal_code, data.country)

return render.register(nav, register_form, "User registered!")


+ 40
- 0
src/app/views/utils.py 파일 보기

@@ -1,3 +1,6 @@
import web
from uuid import uuid4


def get_nav_bar(session):
"""
@@ -38,3 +41,40 @@ def get_element_count(data, element):
except:
break
return task_count


def csrf_token():
"""
Get the CSRF token for the session
"""
session = web.ctx.session

if 'csrf_token' not in session:
session.csrf_token = uuid4().hex

return session.csrf_token


def csrf_field():
"""
Return a HTML form field for the CSRF token
"""
return f'<input type="hidden" name="csrf_token" value="{csrf_token()}" />'


def csrf_protected(f):
"""
Decorate a function to do a CSRF check.
"""
def decorated(*args, **kwargs):
session = web.ctx.session
inp = web.input()
if not ('csrf_token' in inp and inp.csrf_token == session.pop('csrf_token', None)):
raise web.HTTPError(
'400 Bad request',
{'content-type': 'text/html'},
'Cross-site request forgery attempt',
)
return f(*args, **kwargs)

return decorated

불러오는 중...
취소
저장