1

我正在使用bottle.py,Beaker为会话和一个自定义的 AAA 编写模块编写一个 Web 应用程序,因为我担心许多人担心安全性以及防止像我提到的那样的目标攻击的最佳方法。

例如,我有以下代码:

@route('/manage/adddomain',method='POST')
def adddomain():
    #This checks if user has enough power to create a domain
    aaa.require(50,'/forbidden') 

    user = aaa.getusername() # This is retrieved from a server side session
    domainname = request.forms.get('domain')
    description = request.forms.get('description')

    # Additional checks are performed in the sql module 
    # to protect against forged requests with valid login
    return sql.createdomain(user,domainname,description)

您会执行哪些额外检查来保护您的 Web 应用程序?

4

3 回答 3

4

Blender几乎涵盖了您需要的内容,但我想添加另一种方法。您可以添加一个包装器,而不是检查每个 POST:

def wrap_requires_csrf(*methods):
    def wrapper(fn):
        @wraps(fn)
        def wrapped(*args, **kwargs):
            if request.method in methods:
                if request.method == 'POST':
                    csrf = request.form.get('csrf')
                elif request.method == 'GET':
                    csrf = request.args.get('csrf')
                if not csrf or csrf != session.get('csrf'):
                    abort(400)
                session['csrf'] = generate_csrf_token()
            return fn(*args, **kwargs)
        return wrapped
    return wrapper

@app.route('/some/page', methods=['GET','POST'])
@wrap_requires_csrf('POST')
def some_page():
    ...

然后,在您的模板中,您将提供隐藏字段

<input name="csrf" type="hidden" name="{{session.csrf}}" />
于 2013-04-16T05:14:09.637 回答
2

您需要在每个重要的表单字段中包含一个 CSRF 令牌,并使用您的模板引擎清理所有输出。

这是一个Flask 片段,您可以将其调整为您的 Bottle 应用程序:

针对CSRF攻击的一种常用技术是向会话中添加一个随机字符串,并根据 POST 中的隐藏字段检查该字符串。

@app.before_request
def csrf_protect():
    if request.method == "POST":
        token = session.pop('_csrf_token', None)
        if not token or token != request.form.get('_csrf_token'):
            abort(403)

def generate_csrf_token():
    if '_csrf_token' not in session:
        session['_csrf_token'] = some_random_string()
    return session['_csrf_token']

app.jinja_env.globals['csrf_token'] = generate_csrf_token    

然后在您的模板中:

<form method=post action="">
    <input name=_csrf_token type=hidden value="{{ csrf_token() }}">

至于清理,这取决于您的模板引擎。Jinja2 有eorescape过滤器:

<h2>No results for {{ search_query|escape }}</h2>
于 2013-04-15T23:02:00.950 回答
0

我将@Blender的解决方案改编为瓶子,这里是:

from string import ascii_letters, digits
from random import choice
from bottle import Bottle, request, Jinja2Template, abort

app = Bottle()

@app.hook('before_request')
def csrf_protect():
    if request.method == 'POST':
        sess = request.environ['beaker.session']
        req_token = request.forms.get('csrf_token')

        # if no token is in session or it doesn't match the request one, abort
        if 'csrf_token' not in sess or sess['csrf_token'] != req_token:
            abort(403)

def str_random(length):
    '''Generate a random string using range [a-zA-Z0-9].'''
    chars = ascii_letters + digits
    return ''.join([choice(chars) for i in range(length)])

def gen_token():
    '''Put a generated token in session if none exist and return it.'''
    sess = request.environ['beaker.session']
    if 'csrf_token' not in sess:
        sess['csrf_token'] = str_random(32)
    return sess['csrf_token']

# allow access of the token generator using csrf_token
Jinja2Template.defaults['csrf_token'] = gen_token

Bottle 默认情况下不附带会话,因此我使用的是bottle-beaker

需要包含在每个表单中的输入:

<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> 
于 2016-08-16T10:40:03.683 回答