【问题标题】:Methods to protect a bottle.py webapplication against XSS and CSRF?保护bottle.py web应用程序免受XSS和CSRF的方法?
【发布时间】:2016-08-16 18:45:03
【问题描述】:

我正在使用bottle.pyBeaker 为会话和一个自定义 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 应用程序?

【问题讨论】:

    标签: python security wsgi bottle


    【解决方案1】:

    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}}" />
    

    【讨论】:

    • 很好,可以作为装饰者:)
    【解决方案2】:

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

    这里有一个Flask snippet,您可以根据自己的 Bottle 应用进行调整:

    对抗CSRF 攻击的常用技术是添加随机字符串 到会话,并检查该字符串与隐藏字段中的 发布。

    @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 有eescape 过滤器:

    <h2>No results for {{ search_query|escape }}</h2>
    

    【讨论】:

      【解决方案3】:

      我将 @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() }}"> 
      

      【讨论】:

        猜你喜欢
        • 2012-02-16
        • 2016-01-06
        • 2019-09-08
        • 1970-01-01
        • 2014-08-13
        • 1970-01-01
        • 2020-01-15
        • 2017-05-14
        • 1970-01-01
        相关资源
        最近更新 更多