通过 cookie 标头发送令牌身份验证信息是不是安全?

Posted

技术标签:

【中文标题】通过 cookie 标头发送令牌身份验证信息是不是安全?【英文标题】:Is sending token authentication information via cookie headers secure?通过 cookie 标头发送令牌身份验证信息是否安全? 【发布时间】:2020-04-25 10:15:51 【问题描述】:

0

我绝不是安全工程师,而且我才刚刚开始我作为 Web 开发人员的旅程。我为我的后端使用一个名为 django 的 python 包,为我的前端使用 react.js。最近我加入了 django-channels ,这是一个让我能够在我的项目中使用 websockets 的包。由于我已经解耦了我的前端和后端,我使用的身份验证的基础是通过令牌(将考虑使用 jwt)。

问题在于,使用 javascript 时,无法通过 websocket 连接发送身份验证标头(或者我告诉你),因此很多人使用 cookie 来发送此身份验证令牌。这是我如何从前端发送令牌的示例 sn-p:

const path = wsStart + 'localhost:8000'+ loc.pathname
document.cookie = 'authorization=' + token + ';' 
this.socketRef = new WebSocket(path)

这样做可以让我通过在后端使用定制的中间件提取令牌信息。

import re
from channels.db import database_sync_to_async
from django.db import close_old_connections

@database_sync_to_async
def get_user(token_key):
    try:
        return Token.objects.get(key=token_key).user
    except Token.DoesNotExist:
        return AnonymousUser()


class TokenAuthMiddleware:
    """
    Token authorization middleware for Django Channels 2
    see:
    https://channels.readthedocs.io/en/latest/topics/authentication.html#custom-authentication
    """

    def __init__(self, inner):
        self.inner = inner

    def __call__(self, scope):
        return TokenAuthMiddlewareInstance(scope, self)


class TokenAuthMiddlewareInstance:
    def __init__(self, scope, middleware):
        self.middleware = middleware
        self.scope = dict(scope)
        self.inner = self.middleware.inner

    async def __call__(self, receive, send):
        close_old_connections()
        headers = dict(self.scope["headers"])
        print(headers[b"cookie"])
        if b"authorization" in headers[b"cookie"]:
            print('still good here')
            cookies = headers[b"cookie"].decode()
            token_key = re.search("authorization=(.*)(; )?", cookies).group(1)
            if token_key:
                self.scope["user"] = await get_user(token_key)

        inner = self.inner(self.scope)
        return await inner(receive, send) 


TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))

然而,这已经引发了某种形式的安全危险信号(或者我告诉你)。

因此,我希望将这个问题扩展到安全资深人士:

    这种通过 cookie 标头发送令牌身份验证信息的方法安全吗? 我实施此方法是否安全? 有没有办法进一步确保这一点?

【问题讨论】:

【参考方案1】:
    如果您使用的是 HTTPS (WSS) websocket 连接,那么主要是。 是的,看起来不错 是的,有更好的方法。

如果您可以设置(正常)django 会话 cookie,则创建一个常规 HTTP 端点(在此域名上),这通常是您的 django 登录端点。这将设置一个 HTTPONLY cookie(也不能从 javascript 读取)。这很重要,因此您可能在页面上使用的任何其他 js 代码都无法读取该值并窃取它。

然后你可以使用https://channels.readthedocs.io/en/latest/topics/sessions.html。

请注意,在运行时(仅使用 HTTP),您也应该在 django 设置中设置 SESSION_COOKIE_SECURE=True

【讨论】:

非常感谢您的意见,我正在使用基于令牌的身份验证与 DRF,我的前端和后端完全分离,是否仍然可以按照您的建议进行操作? 如果您使用基于令牌的身份验证,那么您可以将其作为query param 添加到 url ?token=.... 中,并从您的消费范围中读取。或者,您可以发送一个帧action: "autheticate", token: "",当您收到此帧时,您检查令牌并验证消费(将标志从 false 更改为 true)。如果您在获得身份验证之前收到任何其他消息,则关闭连接。但是所有这些都将秘密暴露给 JS,所以并没有比添加标题好多少。 如果你使用标题,我只会添加一个常规的Authorization: Token ...,这应该更容易解析更正常。由于您使用基于 DRF 令牌的身份验证,因此我会尝试发送与您在那里相同的标头。 如果您已经在使用 DRF,我可以建议您使用 github.com/hishnash/djangochannelsrestframework 这个框架为您提供了一个类似于 DRF 的界面,用于编写消费者(它还提供了一些身份验证处理)请参阅此博客文章了解更多信息信息:lostmoa.com/blog/DjangoChannelsRestFramework

以上是关于通过 cookie 标头发送令牌身份验证信息是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ionic 4 中发送带有标头的身份验证令牌?

ORBEON:是不是可以添加自定义标头或向 API 授权方发送会话 cookie

如果用于身份验证的 JWT 令牌保存在 HTTP-Only cookie 中,您如何从 cookie 中读取它以便我可以将其包含在请求标头中?

当我在授权标头中发送有效的不记名令牌时,为啥我的 Spring-Cloud Gateway / OAuth2-Client 没有通过身份验证?

在 Chromecast Receiver 中利用基于 cookie 的身份验证

在基于令牌的身份验证中使用刷新令牌是不是安全?