1

我正在使用 Flask kvsession 来避免重放攻击,因为 Flask-login 使用的基于 cookie 的客户端会话很容易出现这种情况。例如:如果在 /index 页面上,您的标头中的 cookie 设置为您的应用标头,例如 myapp_session : 'value1' 并且如果您导航到 /important 页面,您将获得一个新标头,例如 myapp_session : 'value2' 所以如果黑客得到 ' value1' 他可以执行重放攻击并滥用它,因为它永远不会失效。

为了解决这个问题,我使用了flask-kvsession,它将会话cookie标头值存储在缓存或某个后端中。所以基本上只有一个 myapp_session 在您注销时生成并失效。但问题是:-

__init__.py 

from simplekv.memory.redisstore import RedisStore
import redis

store = RedisStore(redis.StrictRedis())
#store = memcache.Client(['127.0.0.1:11211'], debug =0)
store.ttl_support = True
app = create_app(__name__)
current_kvsession = KVSessionExtension(store, app)

如果您查看 kv-session http://pythonhosted.org/Flask-KVSession/#flask_kvsession.KVSessionExtension.cleanup_sessions代码的 cleanup_session 部分

它只删除过期的会话。但是,如果我想在注销时为特定用户显式删除当前 myapp_session 的值,我该怎么做?

@app.before_request
def redirect_if_logout():
  if request.path == url_for('logout'):
      for key in app.kvsession_store.keys():
        logger.debug(key)
        m = current_kvsession.key_regex.match(key)
        logger.debug('found %s', m)
        app.kvsession_store.delete(key)

但这会删除所有键,因为我不知道当前会话的唯一键是什么。

Q2。另外,如何使用 memcache 而不是 redis,因为它没有 app.kvsession_store.keys() 函数并给出 i/o 错误。

4

1 回答 1

3

我想我刚刚想到了关于如何在注销时删除特定键的问题的第一部分。

如文档中所述:

在内部,Flask-KVSession 存储被序列化为 KEY_CREATED 的会话 id,其中 KEY 是一个随机数(会话“真实”id),并且 CREATED 是创建会话时的 UNIX 时间戳。

在客户端创建的示例 cookie 值(您可以使用该 cookie 管理器扩展检查 firefox):

c823af88aedaf496_571b3fd5.4kv9X8UvyQqtCtNV87jTxy3Zcqc

和会话 id 作为键存储在 redis 中:

c823af88aedaf496_571b3fd5

因此,在注销处理程序上,您只需要读取 cookie 值,将其拆分并使用字符串的第一部分:

对我有用的示例代码:

import redis
from flask import Flask
from flask_kvsession import KVSessionExtension
from simplekv.memory.redisstore import RedisStore

store = RedisStore(redis.StrictRedis())

app = Flask(__name__)
KVSessionExtension(store, app)

#Logout Handler
@app.route('/logout', methods=['GET'])
def logout():
    #here you are reading the cookie 
    cookie_val = request.cookies.get('session').split(".")[0]
    store.delete(cookie_val)

并且由于您添加了 ttl_support:

store.ttl_support = True

如果您在配置文件或 app.py 文件的开头设置了该值,它将与永久会话生命周期中的 TTL(秒)值匹配。

例如,在我的应用程序中,我在 app.py 文件的开头设置为:

session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=5)

现在,当我注销时,它会删除 redis 中的密钥,但它不会被删除,直到 TTL 从 300 变为 0(如 Permanent_session_lifetime value 中提到的 5 分钟)。

如果你想立即从 redis 中删除它,你可以手动将 app.permanent_session_lifetime 更改为 1 秒,这反过来会更改 redis 的 TTL。

import redis
import os
from flask import Flask
from flask_kvsession import KVSessionExtension
from simplekv.memory.redisstore import RedisStore

store = RedisStore(redis.StrictRedis())

app = Flask(__name__)
KVSessionExtension(store, app)

#Logout Handler
@app.route('/logout', methods=['GET'])
def logout():
    cookie_val = request.cookies.get('session').split(".")[0]
    app.permanent_session_lifetime = timedelta(seconds=1)
    store.delete(cookie_val)

使用上面的代码,我能够阻止会话重放攻击。

并解决您的第二个问题:

我可以看到的 3 个可能的错误是:

1:在您创建的代码的开头:

store = RedisStore(redis.StrictRedis())

但在循环中,您将其用作 kvsession_store 而不仅仅是存储:

app.kvsession_store.keys()
  1. 要在没有任何错误/异常的情况下使用它,您可以使用它来store.keys()代替 app.store.keys():

    from flask_kvsession import KVSessionExtension
    from simplekv.memory.redisstore import RedisStore
    store = RedisStore(redis.StrictRedis())
    
    for key in store.keys():
        print key
    
  2. store.delete(key)不是删除所有键,而是在循环中运行它,一个一个地删除所有键。

于 2016-04-23T11:26:49.287 回答