设置 HttpOnly Cookie 存储 JWT示例

Flask 示例:设置 HttpOnly Cookie 存储 JWT

from flask import Flask, make_response, request, jsonify
import jwt
import datetime

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'

@app.route('/login', methods=['POST'])
def login():
    # 模拟登录成功后的用户信息
    user_id = 123
    token = jwt.encode(
        {'user_id': user_id, 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)},
        app.config['SECRET_KEY'],
        algorithm='HS256'
    )

    # 创建响应对象
    resp = make_response(jsonify({'message': '登录成功'}))

    # 设置 HttpOnly Cookie
    resp.set_cookie(
        'access_token',         # Cookie 名称
        token,                  # Cookie 值(JWT)
        httponly=True,          # 禁止 JS 访问,防 XSS
        secure=False,           # 生产环境应设为 True(仅 HTTPS)
        samesite='Lax',         # 防 CSRF,推荐 Lax 或 Strict
        max_age=3600            # 有效期 1 小时
    )

    return resp

@app.route('/protected')
def protected():
    token = request.cookies.get('access_token')
    if not token:
        return jsonify({'error': '未授权'}), 401

    try:
        payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
        return jsonify({'user_id': payload['user_id']})
    except jwt.ExpiredSignatureError:
        return jsonify({'error': 'Token 已过期'}), 401

解析亮点

  • set_cookie() 设置了 HttpOnly 属性,防止 JS 访问。

  • secure=False 仅用于开发环境,生产环境必须启用 HTTPS。

  • samesite='Lax' 防止跨站请求伪造(CSRF)。

  • request.cookies.get() 用于读取 Cookie 中的 Token。

Django 示例:设置 HttpOnly Cookie 存储 JWT

from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from django.utils import timezone
import jwt

class LoginView(APIView):
    def post(self, request):
        user_id = 123  # 模拟登录成功
        payload = {
            'user_id': user_id,
            'exp': timezone.now() + timezone.timedelta(hours=1)
        }
        token = jwt.encode(payload, settings.SECRET_KEY, algorithm='HS256')

        response = Response({'message': '登录成功'})

        # 设置 HttpOnly Cookie
        response.set_cookie(
            key='access_token',
            value=token,
            httponly=True,
            secure=not settings.DEBUG,
            samesite='Lax',
            max_age=3600
        )

        return response

class ProtectedView(APIView):
    def get(self, request):
        token = request.COOKIES.get('access_token')
        if not token:
            return Response({'error': '未授权'}, status=401)

        try:
            payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
            return Response({'user_id': payload['user_id']})
        except jwt.ExpiredSignatureError:
            return Response({'error': 'Token 已过期'}, status=401)

解析亮点

  • response.set_cookie() 设置 HttpOnly Cookie。

  • secure=not settings.DEBUG:开发环境允许 HTTP,生产强制 HTTPS。

  • request.COOKIES.get() 读取 Cookie 中的 Token。

  • 使用 jwt.decode() 验证 Token 合法性和过期时间。

安全建议(适用于 Flask 和 Django)

项目建议配置
httponly✅ 必须开启,防止 XSS
secure✅ 生产环境必须开启 HTTPS
samesite✅ 推荐 'Lax''Strict'
max_age根据业务设置有效期
Token刷新建议使用 Refresh Token + 自动刷新机制

SameSite 属性作用

它是浏览器用来防止 CSRF(跨站请求伪造)攻击 的机制之一。通过限制 Cookie 在跨站请求中的发送行为,提升安全性。

SameSite=Lax(宽松模式)

  • 允许跨站 GET 请求携带 Cookie

    • 比如:点击链接跳转、打开新窗口、GET 表单提交

  • 禁止跨站 POST、PUT、DELETE 等非安全方法携带 Cookie

    • 比如:AJAX 请求、表单自动提交等

适合场景

  • 普通网站登录状态维持

  • 用户从其他网站跳转访问你的网站时仍能保持登录

SameSite=Strict(严格模式)

  • 所有跨站请求都不携带 Cookie

    • 无论是 GET 还是 POST,只要是跨站就不带 Cookie

  • ✅ 只有在用户直接访问你的网站(同源)时才会带 Cookie

适合场景

  • 高安全性要求的系统(如银行后台、管理系统)

  • 不希望任何第三方页面能触发带 Cookie 的请求

举个例子

假设你已经登录了 example.com

场景LaxStrict
你点击一个链接跳转到 example.com✅ Cookie 会带上✅ Cookie 会带上
其他网站通过表单 POST 到 example.com❌ 不带 Cookie❌ 不带 Cookie
其他网站通过 AJAX 请求 example.com❌ 不带 Cookie❌ 不带 Cookie

总结建议

属性安全性用户体验推荐用途
Strict差(容易掉登录)内部系统、后台管理
Lax普通网站、博客、商城

如果你正在做一个后台管理系统,Strict 是更安全的选择;如果你希望用户从其他页面跳转后仍保持登录状态,Lax 更合适。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值